[automerger skipped] DO NOT MERGE ANYWHERE resolve merge conflicts of bcf5e2388e608e4ec4372d1eeb918bbe0e095b2e to oc-dr1-dev am: 2ad06909c9 -s ours am skip reason: subject contains skip directive
am: 1fb9beca3f -s ours
am skip reason: subject contains skip directive

Change-Id: Idf3e102c8176259eba32d253cd0d127f8d08d21b
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index b3cbdef..bb84a18 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -3,6 +3,10 @@
 cc_binary {
     name: "atrace",
     srcs: ["atrace.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     shared_libs: [
         "libbinder",
@@ -14,8 +18,6 @@
         "libcutils",
         "libz",
         "libbase",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 9cdc9e9..31e73fb 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -56,9 +56,9 @@
 using std::string;
 
 #define MAX_SYS_FILES 10
-#define MAX_PACKAGES 16
 
 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
+const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
 
 const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
 const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
@@ -94,6 +94,7 @@
 static const TracingCategory k_categories[] = {
     { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
         { OPT,      "events/mdss/enable" },
+        { OPT,      "events/sde/enable" },
     } },
     { "input",      "Input",            ATRACE_TAG_INPUT, { } },
     { "view",       "View System",      ATRACE_TAG_VIEW, { } },
@@ -105,7 +106,6 @@
     { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
     { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
     { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
-    { "app",        "Application",      ATRACE_TAG_APP, { } },
     { "res",        "Resource Loading", ATRACE_TAG_RESOURCES, { } },
     { "dalvik",     "Dalvik VM",        ATRACE_TAG_DALVIK, { } },
     { "rs",         "RenderScript",     ATRACE_TAG_RS, { } },
@@ -116,6 +116,8 @@
     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
     { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
     { "adb",        "ADB",              ATRACE_TAG_ADB, { } },
+    { "vibrator",   "Vibrator",         ATRACE_TAG_VIBRATOR, { } },
+    { "aidl",       "AIDL calls",       ATRACE_TAG_AIDL, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
@@ -124,12 +126,21 @@
         { OPT,      "events/sched/sched_waking/enable" },
         { OPT,      "events/sched/sched_blocked_reason/enable" },
         { OPT,      "events/sched/sched_cpu_hotplug/enable" },
+        { OPT,      "events/sched/sched_pi_setprio/enable" },
         { OPT,      "events/cgroup/enable" },
     } },
     { "irq",        "IRQ Events",   0, {
         { REQ,      "events/irq/enable" },
         { OPT,      "events/ipi/enable" },
     } },
+    { "irqoff",     "IRQ-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/irq_enable/enable" },
+        { REQ,      "events/preemptirq/irq_disable/enable" },
+    } },
+    { "preemptoff", "Preempt-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/preempt_enable/enable" },
+        { REQ,      "events/preemptirq/preempt_disable/enable" },
+    } },
     { "i2c",        "I2C Events",   0, {
         { REQ,      "events/i2c/enable" },
         { REQ,      "events/i2c/i2c_read/enable" },
@@ -144,6 +155,11 @@
     { "freq",       "CPU Frequency",    0, {
         { REQ,      "events/power/cpu_frequency/enable" },
         { OPT,      "events/power/clock_set_rate/enable" },
+        { OPT,      "events/power/clock_disable/enable" },
+        { OPT,      "events/power/clock_enable/enable" },
+        { OPT,      "events/clk/clk_set_rate/enable" },
+        { OPT,      "events/clk/clk_disable/enable" },
+        { OPT,      "events/clk/clk_enable/enable" },
         { OPT,      "events/power/cpu_frequency_limits/enable" },
     } },
     { "membus",     "Memory Bus Utilization", 0, {
@@ -171,7 +187,10 @@
         { REQ,      "events/cpufreq_interactive/enable" },
     } },
     { "sync",       "Synchronization",  0, {
-        { REQ,      "events/sync/enable" },
+        // before linux kernel 4.9
+        { OPT,      "events/sync/enable" },
+        // starting in linux kernel 4.9
+        { OPT,      "events/fence/enable" },
     } },
     { "workq",      "Kernel Workqueues", 0, {
         { REQ,      "events/workqueue/enable" },
@@ -181,7 +200,7 @@
         { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
         { REQ,      "events/vmscan/mm_vmscan_kswapd_wake/enable" },
         { REQ,      "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
-        { REQ,      "events/lowmemorykiller/enable" },
+        { OPT,      "events/lowmemorykiller/enable" },
     } },
     { "regulators",  "Voltage and Current Regulators", 0, {
         { REQ,      "events/regulator/enable" },
@@ -226,8 +245,11 @@
 static const char* k_traceBufferSizePath =
     "buffer_size_kb";
 
+#if 0
+// TODO: Re-enable after stabilization
 static const char* k_traceCmdlineSizePath =
     "saved_cmdlines_size";
+#endif
 
 static const char* k_tracingOverwriteEnablePath =
     "options/overwrite";
@@ -250,9 +272,6 @@
 static const char* k_funcgraphFlatPath =
     "options/funcgraph-flat";
 
-static const char* k_funcgraphDurationPath =
-    "options/funcgraph-duration";
-
 static const char* k_ftraceFilterPath =
     "set_ftrace_filter";
 
@@ -429,6 +448,16 @@
     return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
 }
 
+// Set the user initiated trace property
+static bool setUserInitiatedTraceProperty(bool enable)
+{
+    if (!android::base::SetProperty(k_userInitiatedTraceProperty, enable ? "1" : "")) {
+        fprintf(stderr, "error setting user initiated strace system property\n");
+        return false;
+    }
+    return true;
+}
+
 // Enable or disable kernel tracing.
 static bool setTracingEnabled(bool enable)
 {
@@ -445,7 +474,6 @@
 static bool setTraceBufferSizeKB(int size)
 {
     char str[32] = "1";
-    int len;
     if (size < 1) {
         size = 1;
     }
@@ -453,6 +481,8 @@
     return writeStr(k_traceBufferSizePath, str);
 }
 
+#if 0
+// TODO: Re-enable after stabilization
 // Set the default size of cmdline hashtable
 static bool setCmdlineSize()
 {
@@ -461,6 +491,7 @@
     }
     return true;
 }
+#endif
 
 // Set the clock to the best available option while tracing. Use 'boot' if it's
 // available; otherwise, use 'mono'. If neither are available use 'global'.
@@ -481,8 +512,8 @@
         newClock = "global";
     }
 
-    size_t begin = clockStr.find("[") + 1;
-    size_t end = clockStr.find("]");
+    size_t begin = clockStr.find('[') + 1;
+    size_t end = clockStr.find(']');
     if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
         return true;
     }
@@ -543,7 +574,7 @@
     auto listRet = sm->list([&](const auto &interfaces) {
         for (size_t i = 0; i < interfaces.size(); i++) {
             string fqInstanceName = interfaces[i];
-            string::size_type n = fqInstanceName.find("/");
+            string::size_type n = fqInstanceName.find('/');
             if (n == std::string::npos || interfaces[i].size() == n+1)
                 continue;
             hidl_string fqInterfaceName = fqInstanceName.substr(0, n);
@@ -586,12 +617,6 @@
 
 static void clearAppProperties()
 {
-    for (int i = 0; i < MAX_PACKAGES; i++) {
-        std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
-        if (!android::base::SetProperty(key, "")) {
-            fprintf(stderr, "failed to clear system property: %s\n", key.c_str());
-        }
-    }
     if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
         fprintf(stderr, "failed to clear system property: %s",
               k_traceAppsNumberProperty);
@@ -605,11 +630,6 @@
     int i = 0;
     char* start = cmdline;
     while (start != NULL) {
-        if (i == MAX_PACKAGES) {
-            fprintf(stderr, "error: only 16 packages could be traced at once\n");
-            clearAppProperties();
-            return false;
-        }
         char* end = strchr(start, ',');
         if (end != NULL) {
             *end = '\0';
@@ -769,22 +789,10 @@
     return ok;
 }
 
-// Set all the kernel tracing settings to the desired state for this trace
-// capture.
-static bool setUpTrace()
+static bool setUpUserspaceTracing()
 {
     bool ok = true;
 
-    // Set up the tracing options.
-    ok &= setCategoriesEnableFromFile(g_categoriesFile);
-    ok &= setTraceOverwriteEnable(g_traceOverwrite);
-    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
-    // TODO: Re-enable after stabilization
-    //ok &= setCmdlineSize();
-    ok &= setClock();
-    ok &= setPrintTgidEnableIfPresent(true);
-    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
-
     // Set up the tags property.
     uint64_t tags = 0;
     for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -822,6 +830,39 @@
         ok &= ServiceUtility::PokeServices();
     }
 
+    return ok;
+}
+
+static void cleanUpUserspaceTracing()
+{
+    setTagsProperty(0);
+    clearAppProperties();
+    pokeBinderServices();
+
+    if (g_tracePdx) {
+        ServiceUtility::PokeServices();
+    }
+}
+
+
+// Set all the kernel tracing settings to the desired state for this trace
+// capture.
+static bool setUpKernelTracing()
+{
+    bool ok = true;
+
+    ok &= setUserInitiatedTraceProperty(true);
+
+    // Set up the tracing options.
+    ok &= setCategoriesEnableFromFile(g_categoriesFile);
+    ok &= setTraceOverwriteEnable(g_traceOverwrite);
+    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
+    // TODO: Re-enable after stabilization
+    //ok &= setCmdlineSize();
+    ok &= setClock();
+    ok &= setPrintTgidEnableIfPresent(true);
+    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
+
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
     ok &= disableKernelTraceEvents();
@@ -849,28 +890,19 @@
 }
 
 // Reset all the kernel tracing settings to their default state.
-static void cleanUpTrace()
+static void cleanUpKernelTracing()
 {
     // Disable all tracing that we're able to.
     disableKernelTraceEvents();
 
-    // Reset the system properties.
-    setTagsProperty(0);
-    clearAppProperties();
-    pokeBinderServices();
-
-    if (g_tracePdx) {
-        ServiceUtility::PokeServices();
-    }
-
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
     setPrintTgidEnableIfPresent(false);
     setKernelTraceFuncs(NULL);
+    setUserInitiatedTraceProperty(false);
 }
 
-
 // Enable tracing in the kernel.
 static bool startTrace()
 {
@@ -1047,7 +1079,7 @@
     fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
     fprintf(stderr, "options include:\n"
                     "  -a appname      enable app-level tracing for a comma "
-                        "separated list of cmdlines\n"
+                        "separated list of cmdlines; * is a wildcard matching any process\n"
                     "  -b N            use a trace buffer size of N KB\n"
                     "  -c              trace into a circular buffer\n"
                     "  -f filename     use the categories written in a file as space-separated\n"
@@ -1102,6 +1134,7 @@
     bool traceStop = true;
     bool traceDump = true;
     bool traceStream = false;
+    bool onlyUserspace = false;
 
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
@@ -1117,12 +1150,13 @@
         int ret;
         int option_index = 0;
         static struct option long_options[] = {
-            {"async_start",     no_argument, 0,  0 },
-            {"async_stop",      no_argument, 0,  0 },
-            {"async_dump",      no_argument, 0,  0 },
-            {"list_categories", no_argument, 0,  0 },
-            {"stream",          no_argument, 0,  0 },
-            {           0,                0, 0,  0 }
+            {"async_start",       no_argument, 0,  0 },
+            {"async_stop",        no_argument, 0,  0 },
+            {"async_dump",        no_argument, 0,  0 },
+            {"only_userspace",    no_argument, 0,  0 },
+            {"list_categories",   no_argument, 0,  0 },
+            {"stream",            no_argument, 0,  0 },
+            {           0,                  0, 0,  0 }
         };
 
         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
@@ -1192,6 +1226,8 @@
                     async = true;
                     traceStart = false;
                     traceStop = false;
+                } else if (!strcmp(long_options[option_index].name, "only_userspace")) {
+                    onlyUserspace = true;
                 } else if (!strcmp(long_options[option_index].name, "stream")) {
                     traceStream = true;
                     traceDump = false;
@@ -1209,6 +1245,14 @@
         }
     }
 
+    if (onlyUserspace) {
+        if (!async || !(traceStart || traceStop)) {
+            fprintf(stderr, "--only_userspace can only be used with "
+                    "--async_start or --async_stop\n");
+            exit(1);
+        }
+    }
+
     registerSigHandler();
 
     if (g_initialSleepSecs > 0) {
@@ -1216,11 +1260,19 @@
     }
 
     bool ok = true;
-    ok &= setUpTrace();
-    ok &= startTrace();
+
+    if (traceStart) {
+        ok &= setUpUserspaceTracing();
+    }
+
+    if (ok && traceStart && !onlyUserspace) {
+        ok &= setUpKernelTracing();
+        ok &= startTrace();
+    }
 
     if (ok && traceStart) {
-        if (!traceStream) {
+
+        if (!traceStream && !onlyUserspace) {
             printf("capturing trace...");
             fflush(stdout);
         }
@@ -1230,9 +1282,12 @@
         // contain entries from only one CPU can cause "begin" entries without a
         // matching "end" entry to show up if a task gets migrated from one CPU to
         // another.
-        ok = clearTrace();
+        if (!onlyUserspace)
+            ok = clearTrace();
 
-        writeClockSyncMarker();
+        if (!onlyUserspace)
+            writeClockSyncMarker();
+
         if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
@@ -1251,10 +1306,10 @@
     }
 
     // Stop the trace and restore the default settings.
-    if (traceStop)
+    if (traceStop && !onlyUserspace)
         stopTrace();
 
-    if (ok && traceDump) {
+    if (ok && traceDump && !onlyUserspace) {
         if (!g_traceAborted) {
             printf(" done\n");
             fflush(stdout);
@@ -1281,8 +1336,11 @@
     }
 
     // Reset the trace buffer size to 1.
-    if (traceStop)
-        cleanUpTrace();
+    if (traceStop) {
+        cleanUpUserspaceTracing();
+        if (!onlyUserspace)
+            cleanUpKernelTracing();
+    }
 
     return g_traceAborted ? 1 : 0;
 }
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 3ea1d56..d3d0711 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -1,146 +1,129 @@
 ## Permissions to allow system-wide tracing to the kernel trace buffer.
 ##
-on post-fs
+on late-init
 
 # Allow writing to the kernel trace log.
     chmod 0222 /sys/kernel/debug/tracing/trace_marker
     chmod 0222 /sys/kernel/tracing/trace_marker
 
-# Allow the shell group to enable (some) kernel tracing.
-    chown root shell /sys/kernel/debug/tracing/trace_clock
-    chown root shell /sys/kernel/tracing/trace_clock
-    chown root shell /sys/kernel/debug/tracing/buffer_size_kb
-    chown root shell /sys/kernel/tracing/buffer_size_kb
-    chown root shell /sys/kernel/debug/tracing/options/overwrite
-    chown root shell /sys/kernel/tracing/options/overwrite
-    chown root shell /sys/kernel/debug/tracing/options/print-tgid
-    chown root shell /sys/kernel/tracing/options/print-tgid
-    chown root shell /sys/kernel/debug/tracing/saved_cmdlines_size
-    chown root shell /sys/kernel/tracing/saved_cmdlines_size
-    chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
-    chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
-    chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
-    chown root shell /sys/kernel/tracing/events/sched/sched_wakeup/enable
-    chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
-    chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
-    chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
-    chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
-    chown root shell /sys/kernel/debug/tracing/events/cgroup/enable
-    chown root shell /sys/kernel/tracing/events/cgroup/enable
-    chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
-    chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
-    chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
-    chown root shell /sys/kernel/tracing/events/power/cpu_idle/enable
-    chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
-    chown root shell /sys/kernel/tracing/events/power/clock_set_rate/enable
-    chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
-    chown root shell /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
-    chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
-    chown root shell /sys/kernel/tracing/events/cpufreq_interactive/enable
-    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
-    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
-    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
-    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
-    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
-    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
-    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
-    chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
-    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
-    chown root shell /sys/kernel/tracing/events/binder/binder_transaction/enable
-    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
-    chown root shell /sys/kernel/tracing/events/binder/binder_transaction_received/enable
-    chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
-    chown root shell /sys/kernel/tracing/events/binder/binder_lock/enable
-    chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
-    chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
-    chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
-    chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
-    chown root shell /sys/kernel/debug/tracing/events/lowmemorykiller/enable
-    chown root shell /sys/kernel/tracing/events/lowmemorykiller/enable
+# Scheduler tracepoints require schedstats=enable
+    write /proc/sys/kernel/sched_schedstats 1
 
-    chown root shell /sys/kernel/debug/tracing/tracing_on
-    chown root shell /sys/kernel/tracing/tracing_on
+# Grant unix world read/write permissions to kernel tracepoints.
+# Access control to these files is now entirely in selinux policy.
+    chmod 0666 /sys/kernel/debug/tracing/trace_clock
+    chmod 0666 /sys/kernel/tracing/trace_clock
+    chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
+    chmod 0666 /sys/kernel/tracing/buffer_size_kb
+    chmod 0666 /sys/kernel/debug/tracing/options/overwrite
+    chmod 0666 /sys/kernel/tracing/options/overwrite
+    chmod 0666 /sys/kernel/debug/tracing/options/print-tgid
+    chmod 0666 /sys/kernel/tracing/options/print-tgid
+    chmod 0666 /sys/kernel/debug/tracing/saved_cmdlines_size
+    chmod 0666 /sys/kernel/tracing/saved_cmdlines_size
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_switch/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_wakeup/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
+    chmod 0666 /sys/kernel/tracing/events/cgroup/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+    chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+    chmod 0666 /sys/kernel/tracing/events/power/cpu_idle/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+    chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+    chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chmod 0666 /sys/kernel/debug/tracing/tracing_on
+    chmod 0666 /sys/kernel/tracing/tracing_on
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_lock/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_locked/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/i2c_read/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/i2c_write/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/i2c_result/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/i2c_reply/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/smbus_read/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/smbus_write/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/smbus_result/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
+    chmod 0666 /sys/kernel/tracing/events/i2c/smbus_reply/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+    chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sync/enable
+    chmod 0666 /sys/kernel/tracing/events/sync/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
+    chmod 0666 /sys/kernel/tracing/events/fence/enable
 
-    chmod 0664 /sys/kernel/debug/tracing/trace_clock
-    chmod 0664 /sys/kernel/tracing/trace_clock
-    chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
-    chmod 0664 /sys/kernel/tracing/buffer_size_kb
-    chmod 0664 /sys/kernel/debug/tracing/options/overwrite
-    chmod 0664 /sys/kernel/tracing/options/overwrite
-    chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
-    chmod 0664 /sys/kernel/tracing/options/print-tgid
-    chmod 0664 /sys/kernel/debug/tracing/saved_cmdlines_size
-    chmod 0664 /sys/kernel/tracing/saved_cmdlines_size
-    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
-    chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
-    chmod 0664 /sys/kernel/tracing/events/sched/sched_wakeup/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
-    chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
-    chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/cgroup/enable
-    chmod 0664 /sys/kernel/tracing/events/cgroup/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
-    chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
-    chmod 0664 /sys/kernel/tracing/events/power/cpu_idle/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
-    chmod 0664 /sys/kernel/tracing/events/power/clock_set_rate/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
-    chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
-    chmod 0664 /sys/kernel/tracing/events/cpufreq_interactive/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
-    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
-    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
-    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
-    chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
-    chmod 0664 /sys/kernel/debug/tracing/tracing_on
-    chmod 0664 /sys/kernel/tracing/tracing_on
-    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
-    chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
-    chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
-    chmod 0664 /sys/kernel/tracing/events/binder/binder_lock/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
-    chmod 0664 /sys/kernel/tracing/events/binder/binder_locked/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
-    chmod 0664 /sys/kernel/tracing/events/binder/binder_unlock/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_read/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_write/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_result/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/i2c_reply/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_read/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_write/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
-    chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
-    chmod 0664 /sys/kernel/tracing/events/lowmemorykiller/enable
 
-    # Tracing disabled by default
+    # disk
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
+    chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+
+    # graphics
+    chmod 0666 /sys/kernel/tracing/events/sde/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sde/enable
+    chmod 0666 /sys/kernel/tracing/events/mdss/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/mdss/enable
+
+# Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
     write /sys/kernel/tracing/tracing_on 0
 
-# Allow only the shell group to read and truncate the kernel trace.
-    chown root shell /sys/kernel/debug/tracing/trace
-    chown root shell /sys/kernel/tracing/trace
-    chmod 0660 /sys/kernel/debug/tracing/trace
-    chmod 0660 /sys/kernel/tracing/trace
+# Read and truncate the kernel trace.
+    chmod 0666 /sys/kernel/debug/tracing/trace
+    chmod 0666 /sys/kernel/tracing/trace
 
 on property:persist.debug.atrace.boottrace=1
     start boottrace
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 5fd28e2..f4e5b98 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -1,47 +1,19 @@
 ## Permissions to allow additional system-wide tracing to the kernel trace buffer.
 ## The default list of permissions is set in frameworks/native/cmds/atrace/atrace.rc
 
-# Allow the shell group to enable kernel tracepoints:
+# Grant unix world read/write permissions to enable kernel tracepoints.
+# Access control to these files is now entirely in selinux policy.
 
 on post-fs
-    chown root shell /sys/kernel/debug/tracing/events/sync/enable
-    chown root shell /sys/kernel/debug/tracing/events/workqueue/enable
-    chown root shell /sys/kernel/debug/tracing/events/regulator/enable
-    chown root shell /sys/kernel/debug/tracing/events/pagecache/enable
+    chmod 0666 /sys/kernel/tracing/events/workqueue/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
+    chmod 0666 /sys/kernel/tracing/events/regulator/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/regulator/enable
+    chmod 0666 /sys/kernel/tracing/events/pagecache/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/pagecache/enable
 
     # irq
-    chown root shell /sys/kernel/debug/tracing/events/irq/enable
-    chown root shell /sys/kernel/debug/tracing/events/ipi/enable
-
-    # disk
-    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
-    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
-    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
-    chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
-    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
-    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
-    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
-    chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
-    chown root shell /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
-    chown root shell /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
-
-    chmod 0664 /sys/kernel/debug/tracing/events/sync/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/workqueue/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/regulator/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/pagecache/enable
-
-    # irq
-    chmod 0664 /sys/kernel/debug/tracing/events/irq/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/ipi/enable
-
-    # disk
-    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
-    chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 139e4b2..24044a6 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,6 +1,6 @@
 cc_binary {
     name: "bugreport",
     srcs: ["bugreport.cpp"],
-    cflags: ["-Wall"],
+    cflags: ["-Wall", "-Werror"],
     shared_libs: ["libcutils"],
 }
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
index d565e57..4868555 100644
--- a/cmds/cmd/Android.mk
+++ b/cmds/cmd/Android.mk
@@ -10,6 +10,8 @@
     libselinux \
 	libbinder
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE)
 
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 014c995..48d5d4a 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -61,7 +61,8 @@
 public:
     bool mActive = true;
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         String8 path8(path);
         char cwd[256];
         getcwd(cwd, 256);
@@ -71,23 +72,67 @@
             aerr << "Open attempt after active for: " << fullPath << endl;
             return -EPERM;
         }
-        int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+#if DEBUG
+        ALOGD("openFile: %s, full=%s", path8.string(), fullPath.string());
+#endif
+        int flags = 0;
+        bool checkRead = false;
+        bool checkWrite = false;
+        if (mode == String16("w")) {
+            flags = O_WRONLY|O_CREAT|O_TRUNC;
+            checkWrite = true;
+        } else if (mode == String16("w+")) {
+            flags = O_RDWR|O_CREAT|O_TRUNC;
+            checkRead = checkWrite = true;
+        } else if (mode == String16("r")) {
+            flags = O_RDONLY;
+            checkRead = true;
+        } else if (mode == String16("r+")) {
+            flags = O_RDWR;
+            checkRead = checkWrite = true;
+        } else {
+            aerr << "Invalid mode requested: " << mode.string() << endl;
+            return -EINVAL;
+        }
+        int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
+#if DEBUG
+        ALOGD("openFile: fd=%d", fd);
+#endif
         if (fd < 0) {
             return fd;
         }
         if (is_selinux_enabled() && seLinuxContext.size() > 0) {
             String8 seLinuxContext8(seLinuxContext);
             security_context_t tmp = NULL;
-            int ret = getfilecon(fullPath.string(), &tmp);
+            getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
-            int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                    "file", "write", NULL);
-            if (accessGranted != 0) {
-                close(fd);
-                aerr << "System server has no access to file context " << context.get()
-                        << " (from path " << fullPath.string() << ", context "
-                        << seLinuxContext8.string() << ")" << endl;
-                return -EPERM;
+            if (checkWrite) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "write", NULL);
+                if (accessGranted != 0) {
+#if DEBUG
+                    ALOGD("openFile: failed selinux write check!");
+#endif
+                    close(fd);
+                    aerr << "System server has no access to write file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
+            }
+            if (checkRead) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "read", NULL);
+                if (accessGranted != 0) {
+#if DEBUG
+                    ALOGD("openFile: failed selinux read check!");
+#endif
+                    close(fd);
+                    aerr << "System server has no access to read file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
             }
         }
         return fd;
@@ -131,6 +176,9 @@
     proc->setThreadPoolMaxThreadCount(0);
     proc->startThreadPool();
 
+#if DEBUG
+    ALOGD("cmd: starting");
+#endif
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
     if (sm == NULL) {
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index f908cbf..b04543b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -14,7 +14,7 @@
 // limitations under the License.
 
 cc_defaults {
-    name: "dumpstate_defaults",
+    name: "dumpstate_cflag_defaults",
     cflags: [
         "-Wall",
         "-Werror",
@@ -24,29 +24,13 @@
     ],
 }
 
-cc_library_headers {
-    name: "dumpstate_headers",
-    vendor_available: true,
-    export_include_dirs: ["."],
-    header_libs: [
-        "libbase_headers",
-        "libutils_headers",
-    ],
-    export_header_lib_headers: [
-        "libbase_headers",
-        "libutils_headers",
-    ],
-}
-
 cc_library_shared {
     name: "libdumpstateutil",
-    defaults: ["dumpstate_defaults"],
+    defaults: ["dumpstate_cflag_defaults"],
     vendor_available: true,
     vndk: {
         enabled: true,
     },
-    header_libs: ["dumpstate_headers"],
-    export_header_lib_headers: ["dumpstate_headers"],
     srcs: [
         "DumpstateInternal.cpp",
         "DumpstateUtil.cpp",
@@ -55,11 +39,15 @@
         "libbase",
         "liblog",
     ],
+    export_include_dirs: ["."],
+    export_shared_lib_headers: [
+        "libbase",
+    ],
 }
 
 cc_library_shared {
     name: "libdumpstateaidl",
-    defaults: ["dumpstate_defaults"],
+    defaults: ["dumpstate_cflag_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -75,10 +63,9 @@
     ],
 }
 
-cc_binary {
-    name: "dumpstate",
-    defaults: ["dumpstate_defaults"],
-    header_libs: ["dumpstate_headers"],
+cc_defaults {
+    name: "dumpstate_defaults",
+    defaults: ["dumpstate_cflag_defaults"],
     shared_libs: [
         "android.hardware.dumpstate@1.0",
         "libziparchive",
@@ -89,16 +76,29 @@
         "libdebuggerd_client",
         "libdumpstateaidl",
         "libdumpstateutil",
+        "libdumputils",
         "libhidlbase",
         "libhidltransport",
         "liblog",
         "libutils",
     ],
     srcs: [
-        "DumpstateInternal.cpp",
+        "DumpstateSectionReporter.cpp",
         "DumpstateService.cpp",
         "utils.cpp",
+    ],
+    static_libs: [
+        "libdumpsys",
+        "libserviceutils"
+    ],
+}
+
+cc_binary {
+    name: "dumpstate",
+    defaults: ["dumpstate_defaults"],
+    srcs: [
         "dumpstate.cpp",
+        "main.cpp",
     ],
     init_rc: ["dumpstate.rc"],
 }
@@ -106,25 +106,18 @@
 cc_test {
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
-    header_libs: ["dumpstate_headers"],
-    shared_libs: [
-        "libziparchive",
-        "libbase",
-        "libbinder",
-        "libcutils",
-        "libdebuggerd_client",
-        "libdumpstateaidl",
-        "libdumpstateutil",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-        "libutils",
-    ],
     srcs: [
-        "DumpstateInternal.cpp",
-        "DumpstateService.cpp",
-        "utils.cpp",
         "tests/dumpstate_test.cpp",
     ],
     static_libs: ["libgmock"],
 }
+
+cc_test {
+    name: "dumpstate_smoke_test",
+    defaults: ["dumpstate_defaults"],
+    srcs: [
+        "dumpstate.cpp",
+        "tests/dumpstate_smoke_test.cpp",
+    ],
+    static_libs: ["libgmock"],
+}
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index f0b6203..33e35f7 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -18,7 +18,9 @@
 
 #include "DumpstateInternal.h"
 
+#include <errno.h>
 #include <grp.h>
+#include <poll.h>
 #include <pwd.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -34,6 +36,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <log/log.h>
 
 uint64_t Nanotime() {
@@ -97,13 +100,25 @@
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     capheader.pid = 0;
 
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
+    if (capget(&capheader, &capdata[0]) != 0) {
+        MYLOGE("capget failed: %s\n", strerror(errno));
+        return false;
+    }
 
-    if (capset(&capheader, &capdata[0]) < 0) {
-        MYLOGE("capset failed: %s\n", strerror(errno));
+    const uint32_t cap_syslog_mask = CAP_TO_MASK(CAP_SYSLOG);
+    const uint32_t cap_syslog_index = CAP_TO_INDEX(CAP_SYSLOG);
+    bool has_cap_syslog = (capdata[cap_syslog_index].effective & cap_syslog_mask) != 0;
+
+    memset(&capdata, 0, sizeof(capdata));
+    if (has_cap_syslog) {
+        // Only attempt to keep CAP_SYSLOG if it was present to begin with.
+        capdata[cap_syslog_index].permitted |= cap_syslog_mask;
+        capdata[cap_syslog_index].effective |= cap_syslog_mask;
+    }
+
+    if (capset(&capheader, &capdata[0]) != 0) {
+        MYLOGE("capset({%#x, %#x}) failed: %s\n", capdata[0].effective,
+               capdata[1].effective, strerror(errno));
         return false;
     }
 
@@ -141,22 +156,16 @@
         return 0;
     }
     bool newline = false;
-    fd_set read_set;
-    timeval tm;
     while (true) {
-        FD_ZERO(&read_set);
-        FD_SET(fd, &read_set);
-        /* Timeout if no data is read for 30 seconds. */
-        tm.tv_sec = 30;
-        tm.tv_usec = 0;
-        uint64_t elapsed = Nanotime();
-        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, nullptr, nullptr, &tm));
+        uint64_t start_time = Nanotime();
+        pollfd fds[] = { { .fd = fd, .events = POLLIN } };
+        int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), 30 * 1000));
         if (ret == -1) {
-            dprintf(out_fd, "*** %s: select failed: %s\n", path, strerror(errno));
+            dprintf(out_fd, "*** %s: poll failed: %s\n", path, strerror(errno));
             newline = true;
             break;
         } else if (ret == 0) {
-            elapsed = Nanotime() - elapsed;
+            uint64_t elapsed = Nanotime() - start_time;
             dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
             newline = true;
             break;
@@ -175,7 +184,6 @@
             }
         }
     }
-    close(fd);
 
     if (!newline) dprintf(out_fd, "\n");
     if (!title.empty()) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp
new file mode 100644
index 0000000..f814bde
--- /dev/null
+++ b/cmds/dumpstate/DumpstateSectionReporter.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateSectionReporter.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title,
+                                                   sp<android::os::IDumpstateListener> listener,
+                                                   bool sendReport)
+    : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) {
+    started_ = std::chrono::steady_clock::now();
+}
+
+DumpstateSectionReporter::~DumpstateSectionReporter() {
+    if ((listener_ != nullptr) && (sendReport_)) {
+        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::steady_clock::now() - started_);
+        listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count());
+    }
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h
new file mode 100644
index 0000000..e971de8
--- /dev/null
+++ b/cmds/dumpstate/DumpstateSectionReporter.h
@@ -0,0 +1,65 @@
+/*
+ * 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 ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
+#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
+
+#include <android/os/IDumpstateListener.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+
+/*
+ * Helper class used to report per section details to a listener.
+ *
+ * Typical usage:
+ *
+ *    DumpstateSectionReporter sectionReporter(title, listener, sendReport);
+ *    sectionReporter.setSize(5000);
+ *
+ */
+class DumpstateSectionReporter {
+  public:
+    DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener,
+                             bool sendReport);
+
+    ~DumpstateSectionReporter();
+
+    void setStatus(status_t status) {
+        status_ = status;
+    }
+
+    void setSize(int size) {
+        size_ = size;
+    }
+
+  private:
+    std::string title_;
+    android::sp<android::os::IDumpstateListener> listener_;
+    bool sendReport_;
+    status_t status_;
+    int size_;
+    std::chrono::time_point<std::chrono::steady_clock> started_;
+};
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
+
+#endif  // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index efe0466..49a78e7 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -52,6 +52,7 @@
 
 binder::Status DumpstateService::setListener(const std::string& name,
                                              const sp<IDumpstateListener>& listener,
+                                             bool getSectionDetails,
                                              sp<IDumpstateToken>* returned_token) {
     *returned_token = nullptr;
     if (name.empty()) {
@@ -70,6 +71,7 @@
 
     ds_.listener_name_ = name;
     ds_.listener_ = listener;
+    ds_.report_section_ = getSectionDetails;
     *returned_token = new DumpstateToken();
 
     return binder::Status::ok();
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 4352d3d..7bca24a 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -38,6 +38,7 @@
 
     status_t dump(int fd, const Vector<String16>& args) override;
     binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
+                               bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
   private:
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index e866b8b..85eb464 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <log/log.h>
 
 #include "DumpstateInternal.h"
@@ -42,7 +43,7 @@
 
 static constexpr const char* kSuPath = "/system/xbin/su";
 
-static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
+static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
     sigset_t child_mask, old_mask;
     sigemptyset(&child_mask);
     sigaddset(&child_mask, SIGCHLD);
@@ -53,10 +54,11 @@
     }
 
     timespec ts;
-    ts.tv_sec = timeout_seconds;
-    ts.tv_nsec = 0;
+    ts.tv_sec = MSEC_TO_SEC(timeout_ms);
+    ts.tv_nsec = (timeout_ms % 1000) * 1000000;
     int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
     int saved_errno = errno;
+
     // Set the signals back the way they were.
     if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
         printf("*** sigprocmask failed: %s\n", strerror(errno));
@@ -90,7 +92,7 @@
 CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
 CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build();
 
-CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout) : values(timeout) {
+CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout_ms) : values(timeout_ms) {
 }
 
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Always() {
@@ -103,6 +105,12 @@
     return *this;
 }
 
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
+    if (!PropertiesHelper::IsUserBuild())
+        values.account_mode_ = SU_ROOT;
+    return *this;
+}
+
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() {
     values.account_mode_ = DROP_ROOT;
     return *this;
@@ -123,8 +131,8 @@
     return CommandOptions(values);
 }
 
-CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout)
-    : timeout_(timeout),
+CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout_ms)
+    : timeout_ms_(timeout_ms),
       always_(false),
       account_mode_(DONT_DROP_ROOT),
       output_mode_(NORMAL_OUTPUT),
@@ -135,7 +143,11 @@
 }
 
 int64_t CommandOptions::Timeout() const {
-    return values.timeout_;
+    return MSEC_TO_SEC(values.timeout_ms_);
+}
+
+int64_t CommandOptions::TimeoutInMs() const {
+    return values.timeout_ms_;
 }
 
 bool CommandOptions::Always() const {
@@ -154,8 +166,12 @@
     return values.logging_message_;
 }
 
-CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout) {
-    return CommandOptions::CommandOptionsBuilder(timeout);
+CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeout(int64_t timeout_sec) {
+    return CommandOptions::CommandOptionsBuilder(SEC_TO_MSEC(timeout_sec));
+}
+
+CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t timeout_ms) {
+    return CommandOptions::CommandOptionsBuilder(timeout_ms);
 }
 
 std::string PropertiesHelper::build_type_ = "";
@@ -176,8 +192,8 @@
 }
 
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
-    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+    if (fd.get() < 0) {
         int err = errno;
         if (title.empty()) {
             dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err));
@@ -188,7 +204,7 @@
         fsync(out_fd);
         return -1;
     }
-    return DumpFileFromFdToFd(title, path, fd, out_fd, PropertiesHelper::IsDryRun());
+    return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
 }
 
 int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
@@ -307,7 +323,7 @@
 
     /* handle parent case */
     int status;
-    bool ret = waitpid_with_timeout(pid, options.Timeout(), &status);
+    bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status);
     fsync(fd);
 
     uint64_t elapsed = Nanotime() - start;
@@ -326,9 +342,9 @@
                    static_cast<float>(elapsed) / NANOS_PER_SEC, pid);
         }
         kill(pid, SIGTERM);
-        if (!waitpid_with_timeout(pid, 5, nullptr)) {
+        if (!waitpid_with_timeout(pid, 5000, nullptr)) {
             kill(pid, SIGKILL);
-            if (!waitpid_with_timeout(pid, 5, nullptr)) {
+            if (!waitpid_with_timeout(pid, 5000, nullptr)) {
                 if (!silent)
                     dprintf(fd, "could not kill command '%s' (pid %d) even with SIGKILL.\n",
                             command, pid);
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 5a8ce5b..8342099 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -19,6 +19,16 @@
 #include <cstdint>
 #include <string>
 
+/*
+ * Converts seconds to milliseconds.
+ */
+#define SEC_TO_MSEC(second) (second * 1000)
+
+/*
+ * Converts milliseconds to seconds.
+ */
+#define MSEC_TO_SEC(millisecond) (millisecond / 1000)
+
 namespace android {
 namespace os {
 namespace dumpstate {
@@ -66,9 +76,9 @@
   private:
     class CommandOptionsValues {
       private:
-        CommandOptionsValues(int64_t timeout);
+        CommandOptionsValues(int64_t timeout_ms);
 
-        int64_t timeout_;
+        int64_t timeout_ms_;
         bool always_;
         PrivilegeMode account_mode_;
         OutputMode output_mode_;
@@ -89,6 +99,8 @@
         CommandOptionsBuilder& Always();
         /* Sets the command's PrivilegeMode as `SU_ROOT` */
         CommandOptionsBuilder& AsRoot();
+        /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+        CommandOptionsBuilder& AsRootIfAvailable();
         /* Sets the command's PrivilegeMode as `DROP_ROOT` */
         CommandOptionsBuilder& DropRoot();
         /* Sets the command's OutputMode as `REDIRECT_TO_STDERR` */
@@ -100,13 +112,15 @@
         CommandOptions Build();
 
       private:
-        CommandOptionsBuilder(int64_t timeout);
+        CommandOptionsBuilder(int64_t timeout_ms);
         CommandOptionsValues values;
         friend class CommandOptions;
     };
 
-    /** Gets the command timeout, in seconds. */
+    /** Gets the command timeout in seconds. */
     int64_t Timeout() const;
+    /** Gets the command timeout in milliseconds. */
+    int64_t TimeoutInMs() const;
     /* Checks whether the command should always be run, even on dry-run mode. */
     bool Always() const;
     /** Gets the PrivilegeMode of the command. */
@@ -116,8 +130,11 @@
     /** Gets the logging message header, it any. */
     std::string LoggingMessage() const;
 
-    /** Creates a builder with the requied timeout. */
-    static CommandOptionsBuilder WithTimeout(int64_t timeout);
+    /** Creates a builder with the requied timeout in seconds. */
+    static CommandOptionsBuilder WithTimeout(int64_t timeout_sec);
+
+    /** Creates a builder with the requied timeout in milliseconds. */
+    static CommandOptionsBuilder WithTimeoutInMs(int64_t timeout_ms);
 
     // Common options.
     static CommandOptions DEFAULT;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 4becccf..9b11b96 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -30,6 +30,9 @@
      *
      * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
      * set (the listener behaves like a Highlander: There Can be Only One).
+     * Set {@code getSectionDetails} to true in order to receive callbacks with per section
+     * progress details
      */
-    IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener);
+    IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
+                                boolean getSectionDetails);
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 32717f4..030d69d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -24,4 +24,16 @@
 interface IDumpstateListener {
     void onProgressUpdated(int progress);
     void onMaxProgressUpdated(int maxProgress);
+
+    /**
+    * Called after every section is complete.
+    * @param  name          section name
+    * @param  status        values from status_t
+    *                       {@code OK} section completed successfully
+    *                       {@code TIMEOUT} dump timed out
+    *                       {@code != OK} error
+    * @param  size          size in bytes, may be invalid if status != OK
+    * @param  durationMs    duration in ms
+    */
+    void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
 }
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index b995b80..39e70d1 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -56,8 +56,37 @@
 - `description.txt`: whose value is a multi-line, detailed description of the problem.
 
 ## Android O versions
-On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
-- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`).
+On _Android O (Oreo)_, the following changes were made:
+- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-split-anr`).
+
+## Version 2.0 (Android P)
+On _Android P_, the following changes were made:
+- Framework services are dumped by priority. Supported priorities can be specified
+  when registering the service. If a service does not specify its priority, its
+  assumed to be NORMAL.
+  Supported priorities:
+    - CRITICAL - services that must dump first, and fast (under 100ms). Ex: cpuinfo.
+    - HIGH - services that also must dump first, but can take longer (under 250ms)
+      to dump. Ex: meminfo.
+    - NORMAL - services that have no rush to dump and can take a long time (under 10s).
+
+  Format changes:
+    - Two additional dumpsys sections are generated. The two new sections can be
+      identified by their HEADER `DUMPSYS CRITICAL` and `DUMPSYS HIGH`.
+    - Services in the new sections will have a new header containing the
+      priority.
+      `DUMP OF SERVICE CRITICAL <servicename>` and
+      `DUMP OF SERVICE HIGH <servicename>`.
+    For example, cpuinfo will now move to `DUMPSYS CRITICAL` and will have a
+    header `DUMP OF SERVICE CRITICAL CPUINFO`.
+
+- Bug report will contain proto dumps from all supporting services. Support can be
+  specified when registering framework services.
+  Format changes:
+    - All protos will be generated into separate files per service, per priority. The files
+      will be stored in `proto/<servicename>(_CRITICAL|_HIGH|).proto`
+
+- ANR trace feature has been pushed to version `3.0-dev-split-anr`
 
 ## Intermediate versions
 During development, the versions will be suffixed with _-devX_ or
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 5f93e99..1d951be 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -25,41 +25,68 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/poll.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
+
+#include <chrono>
+#include <functional>
+#include <future>
 #include <memory>
 #include <regex>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
+#include <dumpsys.h>
+#include <hidl/ServiceManagement.h>
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
-
+#include <serviceutils/PriorityDumper.h>
+#include <utils/StrongPointer.h>
 #include "DumpstateInternal.h"
+#include "DumpstateSectionReporter.h"
 #include "DumpstateService.h"
 #include "dumpstate.h"
 
 using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::std::literals::chrono_literals::operator""ms;
+using ::std::literals::chrono_literals::operator""s;
 
 // TODO: remove once moved to namespace
+using android::defaultServiceManager;
+using android::Dumpsys;
+using android::INVALID_OPERATION;
+using android::IServiceManager;
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::String16;
+using android::String8;
+using android::TIMED_OUT;
+using android::UNKNOWN_ERROR;
+using android::Vector;
 using android::os::dumpstate::CommandOptions;
 using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::DumpstateSectionReporter;
 using android::os::dumpstate::GetPidByName;
+using android::os::dumpstate::PropertiesHelper;
 
 /* read before root is shed */
 static char cmdline_buf[16384] = "(unknown)";
@@ -77,10 +104,12 @@
 #define RAFT_DIR "/data/misc/raft"
 #define RECOVERY_DIR "/cache/recovery"
 #define RECOVERY_DATA_DIR "/data/misc/recovery"
+#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
 #define WLUTIL "/vendor/xbin/wlutil"
+#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
 
 // TODO(narayan): Since this information has to be kept in sync
 // with tombstoned, we should just put it in a common header.
@@ -91,19 +120,6 @@
 static const std::string ANR_DIR = "/data/anr/";
 static const std::string ANR_FILE_PREFIX = "anr_";
 
-struct DumpData {
-    std::string name;
-    int fd;
-    time_t mtime;
-};
-
-static bool operator<(const DumpData& d1, const DumpData& d2) {
-    return d1.mtime > d2.mtime;
-}
-
-static std::unique_ptr<std::vector<DumpData>> tombstone_data;
-static std::unique_ptr<std::vector<DumpData>> anr_data;
-
 // TODO: temporary variables and functions used during C++ refactoring
 static Dumpstate& ds = Dumpstate::GetInstance();
 static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
@@ -112,8 +128,8 @@
 }
 static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
                        const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
-                       long dumpsysTimeout = 0) {
-    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeout);
+                       long dumpsysTimeoutMs = 0) {
+    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
 }
 static int DumpFile(const std::string& title, const std::string& path) {
     return ds.DumpFile(title, path);
@@ -124,14 +140,14 @@
 
 // Must be hardcoded because dumpstate HAL implementation need SELinux access to it
 static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kProtoPath = "proto/";
+static const std::string kProtoExt = ".proto";
 static const std::string kDumpstateBoardFiles[] = {
     "dumpstate_board.txt",
     "dumpstate_board.bin"
 };
 static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
 
-static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
-
 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
 static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
@@ -146,15 +162,20 @@
  * is set, the vector only contains files that were written in the last 30 minutes.
  * If |limit_by_count| is set, the vector only contains the ten latest files.
  */
-static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
-                                         const std::string& file_prefix,
-                                         bool limit_by_mtime,
-                                         bool limit_by_count = true) {
+static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
+                                        const std::string& file_prefix,
+                                        bool limit_by_mtime,
+                                        bool limit_by_count = true) {
     const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
 
-    std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
     std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
 
+    if (dump_dir == nullptr) {
+        MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
+        return std::vector<DumpData>();
+    }
+
+    std::vector<DumpData> dump_data;
     struct dirent* entry = nullptr;
     while ((entry = readdir(dump_dir.get()))) {
         if (entry->d_type != DT_REG) {
@@ -170,33 +191,34 @@
         android::base::unique_fd fd(
             TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
         if (fd == -1) {
-            MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
             break;
         }
 
         struct stat st = {};
         if (fstat(fd, &st) == -1) {
-            MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
             continue;
         }
 
-        if (limit_by_mtime && st.st_mtime >= thirty_minutes_ago) {
+        if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
             MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
             continue;
         }
 
-        DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};
-
-        dump_data->push_back(data);
+        dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
     }
 
-    std::sort(dump_data->begin(), dump_data->end());
+    // Sort in descending modification time so that we only keep the newest
+    // reports if |limit_by_count| is true.
+    std::sort(dump_data.begin(), dump_data.end(),
+              [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
 
-    if (limit_by_count && dump_data->size() > 10) {
-        dump_data->erase(dump_data->begin() + 10, dump_data->end());
+    if (limit_by_count && dump_data.size() > 10) {
+        dump_data.erase(dump_data.begin() + 10, dump_data.end());
     }
 
-    return dump_data.release();
+    return dump_data;
 }
 
 static bool AddDumps(const std::vector<DumpData>::const_iterator start,
@@ -207,15 +229,25 @@
         const std::string& name = it->name;
         const int fd = it->fd;
         dumped = true;
+
+        // Seek to the beginning of the file before dumping any data. A given
+        // DumpData entry might be dumped multiple times in the report.
+        //
+        // For example, the most recent ANR entry is dumped to the body of the
+        // main entry and it also shows up as a separate entry in the bugreport
+        // ZIP file.
+        if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
+            MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
+                   strerror(errno));
+        }
+
         if (ds.IsZipping() && add_to_zip) {
-            if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
-                MYLOGE("Unable to add %s %s to zip file\n", name.c_str(), type_name);
+            if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
+                MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
             }
         } else {
             dump_file_from_fd(type_name, name.c_str(), fd);
         }
-
-        close(fd);
     }
 
     return dumped;
@@ -640,12 +672,18 @@
     return 0;
 }
 
-/* timeout in ms */
-static unsigned long logcat_timeout(const char *name) {
-    log_id_t id = android_name_to_log_id(name);
-    unsigned long property_size = __android_logger_get_buffer_size(id);
-    /* Engineering margin is ten-fold our guess */
-    return 10 * (property_size + worst_write_perf) / worst_write_perf;
+static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
+
+/* timeout in ms to read a list of buffers */
+static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
+    unsigned long timeout_ms = 0;
+    for (const auto& buffer : buffers) {
+        log_id_t id = android_name_to_log_id(buffer.c_str());
+        unsigned long property_size = __android_logger_get_buffer_size(id);
+        /* Engineering margin is ten-fold our guess */
+        timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
+    }
+    return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
 }
 
 void Dumpstate::PrintHeader() const {
@@ -674,6 +712,9 @@
     printf("Kernel: ");
     DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
     printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
+    printf("Uptime: ");
+    RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
+                   CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
     printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
            PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
@@ -688,16 +729,17 @@
       ".shb", ".sys", ".vb",  ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
 };
 
-bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
+status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
+                                      std::chrono::milliseconds timeout = 0ms) {
     if (!IsZipping()) {
         MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
                entry_name.c_str());
-        return false;
+        return INVALID_OPERATION;
     }
     std::string valid_name = entry_name;
 
     // Rename extension if necessary.
-    size_t idx = entry_name.rfind(".");
+    size_t idx = entry_name.rfind('.');
     if (idx != std::string::npos) {
         std::string extension = entry_name.substr(idx);
         std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
@@ -714,32 +756,55 @@
     if (err != 0) {
         MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
                ZipWriter::ErrorCodeString(err));
-        return false;
+        return UNKNOWN_ERROR;
     }
+    auto start = std::chrono::steady_clock::now();
+    auto end = start + timeout;
+    struct pollfd pfd = {fd, POLLIN};
 
     std::vector<uint8_t> buffer(65536);
     while (1) {
+        if (timeout.count() > 0) {
+            // lambda to recalculate the timeout.
+            auto time_left_ms = [end]() {
+                auto now = std::chrono::steady_clock::now();
+                auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+                return std::max(diff.count(), 0LL);
+            };
+
+            int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+            if (rc < 0) {
+                MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
+                       strerror(errno));
+                return -errno;
+            } else if (rc == 0) {
+                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+                       entry_name.c_str(), strerror(errno), timeout.count());
+                return TIMED_OUT;
+            }
+        }
+
         ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
         if (bytes_read == 0) {
             break;
         } else if (bytes_read == -1) {
             MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
-            return false;
+            return -errno;
         }
         err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
         if (err) {
             MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
-            return false;
+            return UNKNOWN_ERROR;
         }
     }
 
     err = zip_writer_->FinishEntry();
     if (err != 0) {
         MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
-        return false;
+        return UNKNOWN_ERROR;
     }
 
-    return true;
+    return OK;
 }
 
 bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
@@ -750,12 +815,12 @@
         return false;
     }
 
-    return AddZipEntryFromFd(entry_name, fd.get());
+    return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
 }
 
 /* adds a file to the existing zipped bugreport */
 static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
-    return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
+    return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
 }
 
 void Dumpstate::AddDir(const std::string& dir, bool recursive) {
@@ -811,41 +876,43 @@
     }
 }
 
+static void DoKernelLogcat() {
+    unsigned long timeout_ms = logcat_timeout({"kernel"});
+    RunCommand(
+        "KERNEL LOG",
+        {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+        CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+}
+
 static void DoLogcat() {
-    unsigned long timeout;
+    unsigned long timeout_ms;
     // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
     // calculate timeout
-    timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
-    if (timeout < 20000) {
-        timeout = 20000;
-    }
+    timeout_ms = logcat_timeout({"main", "system", "crash"});
     RunCommand("SYSTEM LOG",
-               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid",
-                        "-d", "*:v"},
-               CommandOptions::WithTimeout(timeout / 1000).Build());
-    timeout = logcat_timeout("events");
-    if (timeout < 20000) {
-        timeout = 20000;
-    }
-    RunCommand("EVENT LOG",
-               {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
-                        "-d", "*:v"},
-               CommandOptions::WithTimeout(timeout / 1000).Build());
-    timeout = logcat_timeout("radio");
-    if (timeout < 20000) {
-        timeout = 20000;
-    }
-    RunCommand("RADIO LOG",
-               {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
-                        "-d", "*:v"},
-               CommandOptions::WithTimeout(timeout / 1000).Build());
+               {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+               CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+    timeout_ms = logcat_timeout({"events"});
+    RunCommand(
+        "EVENT LOG",
+        {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+        CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+    timeout_ms = logcat_timeout({"stats"});
+    RunCommand(
+        "STATS LOG",
+        {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+        CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+    timeout_ms = logcat_timeout({"radio"});
+    RunCommand(
+        "RADIO LOG",
+        {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+        CommandOptions::WithTimeoutInMs(timeout_ms).Build());
 
     RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
 
     /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
-    RunCommand("LAST LOGCAT",
-                {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
-                        "-d", "*:v"});
+    RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
+                               "-v", "uid", "-d", "*:v"});
 }
 
 static void DumpIpTablesAsRoot() {
@@ -887,9 +954,9 @@
     MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
            dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
 
-    int fd = TEMP_FAILURE_RETRY(
-        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+    if (fd.get() < 0) {
         printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
     } else {
         if (add_to_zip) {
@@ -901,7 +968,7 @@
         } else {
             MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
                    anr_traces_file.c_str());
-            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd);
+            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
         }
     }
 }
@@ -930,16 +997,16 @@
     }
 
     // Add a specific message for the first ANR Dump.
-    if (anr_data->size() > 0) {
-        AddDumps(anr_data->begin(), anr_data->begin() + 1,
+    if (ds.anr_data_.size() > 0) {
+        AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
                  "VM TRACES AT LAST ANR", add_to_zip);
 
-        if (anr_data->size() > 1) {
-            // NOTE: Historical ANRs are always added as separate entries in the
-            // bugreport zip file.
-            AddDumps(anr_data->begin() + 1, anr_data->end(),
-                     "HISTORICAL ANR", true /* add_to_zip */);
-        }
+        // The "last" ANR will always be included as separate entry in the zip file. In addition,
+        // it will be present in the body of the main entry if |add_to_zip| == false.
+        //
+        // Historical ANRs are always included as separate entries in the bugreport zip file.
+        AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
+                 "HISTORICAL ANR", true /* add_to_zip */);
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
     }
@@ -1038,6 +1105,187 @@
     RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
 }
 
+static void RunDumpsysTextByPriority(const std::string& title, int priority,
+                                     std::chrono::milliseconds timeout,
+                                     std::chrono::milliseconds service_timeout) {
+    auto start = std::chrono::steady_clock::now();
+    sp<android::IServiceManager> sm = defaultServiceManager();
+    Dumpsys dumpsys(sm.get());
+    Vector<String16> args;
+    Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
+    Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
+    for (const String16& service : services) {
+        std::string path(title);
+        path.append(" - ").append(String8(service).c_str());
+        DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
+        size_t bytes_written = 0;
+        status_t status = dumpsys.startDumpThread(service, args);
+        if (status == OK) {
+            dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+            std::chrono::duration<double> elapsed_seconds;
+            status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+                                       /* as_proto = */ false, elapsed_seconds, bytes_written);
+            section_reporter.setSize(bytes_written);
+            dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
+            bool dump_complete = (status == OK);
+            dumpsys.stopDumpThread(dump_complete);
+        }
+        section_reporter.setStatus(status);
+
+        auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::steady_clock::now() - start);
+        if (elapsed_duration > timeout) {
+            MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
+                   elapsed_duration.count());
+            break;
+        }
+    }
+}
+
+static void RunDumpsysText(const std::string& title, int priority,
+                           std::chrono::milliseconds timeout,
+                           std::chrono::milliseconds service_timeout) {
+    DurationReporter duration_reporter(title);
+    dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
+    fsync(STDOUT_FILENO);
+    RunDumpsysTextByPriority(title, priority, timeout, service_timeout);
+}
+
+/* Dump all services registered with Normal or Default priority. */
+static void RunDumpsysTextNormalPriority(const std::string& title,
+                                         std::chrono::milliseconds timeout,
+                                         std::chrono::milliseconds service_timeout) {
+    DurationReporter duration_reporter(title);
+    dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
+    fsync(STDOUT_FILENO);
+    RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
+                             service_timeout);
+    RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
+                             service_timeout);
+}
+
+static void RunDumpsysProto(const std::string& title, int priority,
+                            std::chrono::milliseconds timeout,
+                            std::chrono::milliseconds service_timeout) {
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
+        return;
+    }
+    sp<android::IServiceManager> sm = defaultServiceManager();
+    Dumpsys dumpsys(sm.get());
+    Vector<String16> args;
+    Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
+    DurationReporter duration_reporter(title);
+
+    auto start = std::chrono::steady_clock::now();
+    Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
+    for (const String16& service : services) {
+        std::string path(kProtoPath);
+        path.append(String8(service).c_str());
+        if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
+            path.append("_CRITICAL");
+        } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
+            path.append("_HIGH");
+        }
+        path.append(kProtoExt);
+        DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
+        status_t status = dumpsys.startDumpThread(service, args);
+        if (status == OK) {
+            status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
+            bool dumpTerminated = (status == OK);
+            dumpsys.stopDumpThread(dumpTerminated);
+        }
+        ZipWriter::FileEntry file_entry;
+        ds.zip_writer_->GetLastEntry(&file_entry);
+        section_reporter.setSize(file_entry.compressed_size);
+        section_reporter.setStatus(status);
+
+        auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::steady_clock::now() - start);
+        if (elapsed_duration > timeout) {
+            MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
+                   elapsed_duration.count());
+            break;
+        }
+    }
+}
+
+// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
+static void RunDumpsysCritical() {
+    RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
+                   /* timeout= */ 5s, /* service_timeout= */ 500ms);
+    RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
+                    /* timeout= */ 5s, /* service_timeout= */ 500ms);
+}
+
+// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
+static void RunDumpsysHigh() {
+    // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
+    // high priority. Reduce timeout once they are able to dump in a shorter time or
+    // moved to a parallel task.
+    RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
+                   /* timeout= */ 90s, /* service_timeout= */ 30s);
+    RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
+                    /* timeout= */ 5s, /* service_timeout= */ 1s);
+}
+
+// Runs dumpsys on services that must dump but can take up to 10s to dump.
+static void RunDumpsysNormal() {
+    RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
+    RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
+                    /* timeout= */ 90s, /* service_timeout= */ 10s);
+}
+
+static void DumpHals() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::hardware::defaultServiceManager;
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+        MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
+        return;
+    }
+
+    auto ret = sm->list([&](const auto& interfaces) {
+        for (const std::string& interface : interfaces) {
+            std::string cleanName = interface;
+            std::replace_if(cleanName.begin(),
+                            cleanName.end(),
+                            [](char c) {
+                                return !isalnum(c) &&
+                                    std::string("@-_:.").find(c) == std::string::npos;
+                            }, '_');
+            const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName;
+
+            {
+                auto fd = android::base::unique_fd(
+                    TEMP_FAILURE_RETRY(open(path.c_str(),
+                    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+                if (fd < 0) {
+                    MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
+                    continue;
+                }
+                RunCommandToFd(fd,
+                        "",
+                        {"lshal", "debug", "-E", interface},
+                        CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+
+                bool empty = 0 == lseek(fd, 0, SEEK_END);
+                if (!empty) {
+                    ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
+                }
+            }
+
+            unlink(path.c_str());
+        }
+    });
+
+    if (!ret.isOk()) {
+        MYLOGE("Could not list hals from hwservicemanager.\n");
+    }
+}
+
 static void dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
@@ -1062,21 +1310,14 @@
     DumpFile("KERNEL SYNC", "/d/sync");
 
     RunCommand("PROCESSES AND THREADS",
-               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
+               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
     RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
 
     if (ds.IsZipping()) {
-        RunCommand(
-                "HARDWARE HALS",
-                {"lshal", std::string("--debug=") + kLsHalDebugPath},
-                CommandOptions::AS_ROOT);
-
-        ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
-
-        unlink(kLsHalDebugPath.c_str());
+        RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+        DumpHals();
     } else {
-        RunCommand(
-                "HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::AS_ROOT);
+        RunCommand("HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
     }
 
     RunCommand("PRINTENV", {"printenv"});
@@ -1088,7 +1329,12 @@
         RunCommand("LSMOD", {"lsmod"});
     }
 
-    do_dmesg();
+    if (__android_logger_property_get_bool(
+            "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
+        DoKernelLogcat();
+    } else {
+        do_dmesg();
+    }
 
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
     for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
@@ -1109,7 +1355,7 @@
 
     // NOTE: tombstones are always added as separate entries in the zip archive
     // and are not interspersed with the main report.
-    const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
+    const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
                                             "TOMBSTONE", true /* add_to_zip */);
     if (!tombstones_dumped) {
         printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
@@ -1127,33 +1373,16 @@
     RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
     RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
 
-    RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
-               CommandOptions::WithTimeout(10).Build());
+    RunDumpsysHigh();
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
-    RunCommand("VOLD DUMP", {"vdc", "dump"});
-    RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
-
-    RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build());
+    RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
 
     RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
 
     RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
 
-    printf("------ BACKLIGHTS ------\n");
-    printf("LCD brightness=");
-    DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
-    printf("Button brightness=");
-    DumpFile("", "/sys/class/leds/button-backlight/brightness");
-    printf("Keyboard brightness=");
-    DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
-    printf("ALS mode=");
-    DumpFile("", "/sys/class/leds/lcd-backlight/als");
-    printf("LCD driver registers:\n");
-    DumpFile("", "/sys/class/leds/lcd-backlight/registers");
-    printf("\n");
-
     /* Binder state is expensive to look at as it uses a lot of memory. */
     DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
     DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
@@ -1161,6 +1390,11 @@
     DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
     DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
 
+    /* Add window and surface trace files. */
+    if (!PropertiesHelper::IsUserBuild()) {
+        ds.AddDir(WMTRACE_DATA_DIR, false);
+    }
+
     ds.DumpstateBoard();
 
     /* Migrate the ril_dumpstate to a device specific dumpstate? */
@@ -1181,8 +1415,7 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
-               10);
+    RunDumpsysNormal();
 
     printf("========================================================\n");
     printf("== Checkins\n");
@@ -1199,19 +1432,40 @@
     printf("== Running Application Activities\n");
     printf("========================================================\n");
 
-    RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"});
+    // The following dumpsys internally collects output from running apps, so it can take a long
+    // time. So let's extend the timeout.
+
+    const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
+
+    RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
 
     printf("========================================================\n");
-    printf("== Running Application Services\n");
+    printf("== Running Application Services (platform)\n");
     printf("========================================================\n");
 
-    RunDumpsys("APP SERVICES", {"activity", "service", "all"});
+    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS);
 
     printf("========================================================\n");
-    printf("== Running Application Providers\n");
+    printf("== Running Application Services (non-platform)\n");
     printf("========================================================\n");
 
-    RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
+    RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS);
+
+    printf("========================================================\n");
+    printf("== Running Application Providers (platform)\n");
+    printf("========================================================\n");
+
+    RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS);
+
+    printf("========================================================\n");
+    printf("== Running Application Providers (non-platform)\n");
+    printf("========================================================\n");
+
+    RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS);
 
     printf("========================================================\n");
     printf("== Dropbox crashes\n");
@@ -1228,10 +1482,8 @@
     printf("========================================================\n");
 }
 
-// This method collects dumpsys for telephony debugging only
-static void DumpstateTelephonyOnly() {
-    DurationReporter duration_reporter("DUMPSTATE");
-
+// This method collects common dumpsys for telephony and wifi
+static void DumpstateRadioCommon() {
     DumpIpTablesAsRoot();
 
     if (!DropRootUser()) {
@@ -1247,6 +1499,14 @@
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
+}
+
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+    DurationReporter duration_reporter("DUMPSTATE");
+    const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
+
+    DumpstateRadioCommon();
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
@@ -1254,8 +1514,14 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
-    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
 
     printf("========================================================\n");
     printf("== Running Application Services\n");
@@ -1264,6 +1530,39 @@
     RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
 
     printf("========================================================\n");
+    printf("== Running Application Services (non-platform)\n");
+    printf("========================================================\n");
+
+    RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS);
+
+    printf("========================================================\n");
+    printf("== Checkins\n");
+    printf("========================================================\n");
+
+    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+
+    printf("========================================================\n");
+    printf("== dumpstate: done (id %d)\n", ds.id_);
+    printf("========================================================\n");
+}
+
+// This method collects dumpsys for wifi debugging only
+static void DumpstateWifiOnly() {
+    DurationReporter duration_reporter("DUMPSTATE");
+
+    DumpstateRadioCommon();
+
+    printf("========================================================\n");
+    printf("== Android Framework Services\n");
+    printf("========================================================\n");
+
+    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+
+    printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
 }
@@ -1274,77 +1573,112 @@
     printf("== Board\n");
     printf("========================================================\n");
 
-    ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
-    if (dumpstate_device == nullptr) {
-        MYLOGE("No IDumpstateDevice implementation\n");
-        return;
-    }
-
     if (!IsZipping()) {
         MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
         return;
     }
 
-    std::string path[NUM_OF_DUMPS];
-    android::base::unique_fd fd[NUM_OF_DUMPS];
-    int numFds = 0;
-
+    std::vector<std::string> paths;
+    std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
-        path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
-        MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
-
-        fd[i] = android::base::unique_fd(
-            TEMP_FAILURE_RETRY(open(path[i].c_str(),
-            O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
-        if (fd[i] < 0) {
-            MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
-            return;
-        } else {
-            numFds++;
-        }
+        paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
+        remover.emplace_back(android::base::make_scope_guard(std::bind(
+            [](std::string path) {
+                if (remove(path.c_str()) != 0 && errno != ENOENT) {
+                    MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+                }
+            },
+            paths[i])));
     }
 
-    native_handle_t *handle = native_handle_create(numFds, 0);
+    sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
+    if (dumpstate_device == nullptr) {
+        MYLOGE("No IDumpstateDevice implementation\n");
+        return;
+    }
+
+    using ScopedNativeHandle =
+            std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+    ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
+                              [](native_handle_t* handle) {
+                                  native_handle_close(handle);
+                                  native_handle_delete(handle);
+                              });
     if (handle == nullptr) {
         MYLOGE("Could not create native_handle\n");
         return;
     }
 
-    for (int i = 0; i < numFds; i++) {
-        handle->data[i] = fd[i].release();
-    }
+    for (size_t i = 0; i < paths.size(); i++) {
+        MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
 
-    // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
-    android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
-    if (!status.isOk()) {
-        MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
-        native_handle_close(handle);
-        native_handle_delete(handle);
-        return;
-    }
-
-    for (int i = 0; i < numFds; i++) {
-        struct stat s;
-        if (fstat(handle->data[i], &s) == -1) {
-            MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
-        } else if (s.st_size > 0) {
-            AddZipEntry(kDumpstateBoardFiles[i], path[i]);
-        } else {
-            MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+            open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+        if (fd < 0) {
+            MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
+            return;
         }
+        handle.get()->data[i] = fd.release();
+    }
+
+    // Given that bugreport is required to diagnose failures, it's better to
+    // set an arbitrary amount of timeout for IDumpstateDevice than to block the
+    // rest of bugreport. In the timeout case, we will kill dumpstate board HAL
+    // and grab whatever dumped
+    std::packaged_task<bool()>
+            dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
+            android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
+            if (!status.isOk()) {
+                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+                return false;
+            }
+            return true;
+        });
+
+    auto result = dumpstate_task.get_future();
+    std::thread(std::move(dumpstate_task)).detach();
+
+    constexpr size_t timeout_sec = 30;
+    if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+        MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
+        if (!android::base::SetProperty("ctl.interface_restart",
+                                        android::base::StringPrintf("%s/default",
+                                                                    IDumpstateDevice::descriptor))) {
+            MYLOGE("Couldn't restart dumpstate HAL\n");
+        }
+    }
+    // Wait some time for init to kill dumpstate vendor HAL
+    constexpr size_t killing_timeout_sec = 10;
+    if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+        MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
+               "there might be racing in content\n", killing_timeout_sec);
+    }
+
+    auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
+    for (size_t i = 0; i < paths.size(); i++) {
+        struct stat s;
+        if (fstat(handle.get()->data[i], &s) == -1) {
+            MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
+                   strerror(errno));
+            file_sizes[i] = -1;
+            continue;
+        }
+        file_sizes[i] = s.st_size;
+    }
+
+    for (size_t i = 0; i < paths.size(); i++) {
+        if (file_sizes[i] == -1) {
+            continue;
+        }
+        if (file_sizes[i] == 0) {
+            MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+            continue;
+        }
+        AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
     }
 
     printf("*** See dumpstate-board.txt entry ***\n");
-
-    native_handle_close(handle);
-    native_handle_delete(handle);
-
-    for (int i = 0; i < numFds; i++) {
-        if (remove(path[i].c_str()) != 0) {
-            MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
-        }
-    }
 }
 
 static void ShowUsageAndExit(int exitCode = 1) {
@@ -1359,7 +1693,7 @@
             "  -p: capture screenshot to filename.png (requires -o)\n"
             "  -z: generate zipped file (requires -o)\n"
             "  -s: write output to control socket (for init)\n"
-            "  -S: write file location to control socket (for init; requires -o and -z)"
+            "  -S: write file location to control socket (for init; requires -o and -z)\n"
             "  -q: disable vibrate\n"
             "  -B: send broadcast when finished (requires -o)\n"
             "  -P: send broadcast when started and update system properties on "
@@ -1375,20 +1709,8 @@
     ShowUsageAndExit();
 }
 
-static void sig_handler(int) {
-    _exit(EXIT_FAILURE);
-}
-
 static void register_sig_handler() {
-    struct sigaction sa;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    sa.sa_handler = sig_handler;
-    sigaction(SIGPIPE, &sa, NULL); // broken pipe
-    sigaction(SIGSEGV, &sa, NULL); // segment fault
-    sigaction(SIGINT, &sa, NULL); // ctrl-c
-    sigaction(SIGTERM, &sa, NULL); // killed
-    sigaction(SIGQUIT, &sa, NULL); // quit
+    signal(SIGPIPE, SIG_IGN);
 }
 
 bool Dumpstate::FinishZipFile() {
@@ -1438,7 +1760,7 @@
     return true;
 }
 
-static std::string SHA256_file_hash(std::string filepath) {
+static std::string SHA256_file_hash(const std::string& filepath) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
             | O_CLOEXEC | O_NOFOLLOW)));
     if (fd == -1) {
@@ -1500,7 +1822,8 @@
     // clang-format on
 }
 
-int main(int argc, char *argv[]) {
+/** Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
     int do_add_date = 0;
     int do_zip_file = 0;
     int do_vibrate = 1;
@@ -1513,6 +1836,9 @@
     bool show_header_only = false;
     bool do_start_service = false;
     bool telephony_only = false;
+    bool wifi_only = false;
+    int dup_stdout_fd;
+    int dup_stderr_fd;
 
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
@@ -1579,9 +1905,14 @@
             is_remote_mode = 1;
             do_fb = 0;
         } else if (ds.extra_options_ == "bugreportwear") {
+            do_start_service = true;
             ds.update_progress_ = true;
+            do_zip_file = 1;
         } else if (ds.extra_options_ == "bugreporttelephony") {
             telephony_only = true;
+        } else if (ds.extra_options_ == "bugreportwifi") {
+            wifi_only = true;
+            do_zip_file = 1;
         } else {
             MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
         }
@@ -1700,6 +2031,8 @@
 
         if (telephony_only) {
             ds.base_name_ += "-telephony";
+        } else if (wifi_only) {
+            ds.base_name_ += "-wifi";
         }
 
         if (do_fb) {
@@ -1781,11 +2114,13 @@
     }
 
     if (is_redirecting) {
+        TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
         redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
         if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
                    ds.log_path_.c_str(), strerror(errno));
         }
+        TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
         /* TODO: rather than generating a text file now and zipping it later,
            it would be more efficient to redirect stdout to the zip entry
            directly, but the libziparchive doesn't support that option yet. */
@@ -1807,6 +2142,8 @@
     if (telephony_only) {
         DumpstateTelephonyOnly();
         ds.DumpstateBoard();
+    } else if (wifi_only) {
+        DumpstateWifiOnly();
     } else {
         // Dumps systrace right away, otherwise it will be filled with unnecessary events.
         // First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1817,10 +2154,7 @@
 
         // Invoking the following dumpsys calls before dump_traces() to try and
         // keep the system stats as close to its initial state as possible.
-        RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
-                   CommandOptions::WithTimeout(90).DropRoot().Build());
-        RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
-                   CommandOptions::WithTimeout(10).DropRoot().Build());
+        RunDumpsysCritical();
 
         // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
         dump_raft();
@@ -1829,11 +2163,12 @@
         dump_traces_path = dump_traces();
 
         /* Run some operations that require root. */
-        tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
-        anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));
+        ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+        ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
 
         ds.AddDir(RECOVERY_DIR, true);
         ds.AddDir(RECOVERY_DATA_DIR, true);
+        ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
         ds.AddDir(LOGPERSIST_DATA_DIR, false);
         if (!PropertiesHelper::IsUserBuild()) {
             ds.AddDir(PROFILE_DATA_DIR_CUR, true);
@@ -1850,6 +2185,9 @@
         RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
                    CommandOptions::WithTimeout(10).Build());
 
+        // Run iotop as root to show top 100 IO threads
+        RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
+
         if (!DropRootUser()) {
             return -1;
         }
@@ -1859,7 +2197,7 @@
 
     /* close output if needed */
     if (is_redirecting) {
-        fclose(stdout);
+        TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
     }
 
     /* rename or zip the (now complete) .tmp file to its final location */
@@ -1935,9 +2273,11 @@
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
-    for (int i = 0; i < 3; i++) {
-        Vibrate(75);
-        usleep((75 + 50) * 1000);
+    if (do_vibrate) {
+        for (int i = 0; i < 3; i++) {
+            Vibrate(75);
+            usleep((75 + 50) * 1000);
+        }
     }
 
     /* tell activity manager we're done */
@@ -1990,7 +2330,7 @@
     MYLOGI("done (id %d)\n", ds.id_);
 
     if (is_redirecting) {
-        fclose(stderr);
+        TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
     }
 
     if (use_control_socket && ds.control_socket_fd_ != -1) {
@@ -1998,5 +2338,8 @@
         close(ds.control_socket_fd_);
     }
 
+    ds.tombstone_data_.clear();
+    ds.anr_data_.clear();
+
     return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7757c1e..b220013 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <android-base/macros.h>
+#include <android-base/unique_fd.h>
 #include <android/os/IDumpstateListener.h>
 #include <utils/StrongPointer.h>
 #include <ziparchive/zip_writer.h>
@@ -145,13 +146,13 @@
  *
  * See bugreport-format.md for more info.
  */
-static std::string VERSION_CURRENT = "1.0";
+static std::string VERSION_CURRENT = "2.0";
 
 /*
  * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
- * will be bumped to 2.0-dev-1.
+ * will be bumped to 3.0.
  */
-static std::string VERSION_SPLIT_ANR = "2.0-dev-1";
+static std::string VERSION_SPLIT_ANR = "3.0-dev-split-anr";
 
 /*
  * "Alias" for the current version.
@@ -159,6 +160,20 @@
 static std::string VERSION_DEFAULT = "default";
 
 /*
+ * Structure that contains the information of an open dump file.
+ */
+struct DumpData {
+    // Path of the file.
+    std::string name;
+
+    // Open file descriptor for the file.
+    android::base::unique_fd fd;
+
+    // Modification time of the file.
+    time_t mtime;
+};
+
+/*
  * Main class driving a bugreport generation.
  *
  * Currently, it only contains variables that are accessed externally, but gradually the functions
@@ -190,19 +205,19 @@
 
     /*
      * Runs `dumpsys` with the given arguments, automatically setting its timeout
-     * (`-t` argument)
+     * (`-T` argument)
      * according to the command options.
      *
      * |title| description of the command printed on `stdout` (or empty to skip
      * description).
      * |dumpsys_args| `dumpsys` arguments (except `-t`).
      * |options| optional argument defining the command's behavior.
-     * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -t` (otherwise it uses the
+     * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the
      * timeout from `options`)
      */
     void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
                     const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS,
-                    long dumpsys_timeout = 0);
+                    long dumpsys_timeout_ms = 0);
 
     /*
      * Prints the contents of a file.
@@ -220,8 +235,14 @@
 
     /*
      * Adds a new entry to the existing zip file.
+     *
+     * |entry_name| destination path of the new entry.
+     * |fd| file descriptor to read from.
+     * |timeout| timeout to terminate the read if not completed. Set
+     * value of 0s (default) to disable timeout.
      */
-    bool AddZipEntryFromFd(const std::string& entry_name, int fd);
+    android::status_t AddZipEntryFromFd(const std::string& entry_name, int fd,
+                                        std::chrono::milliseconds timeout);
 
     /*
      * Adds a text entry entry to the existing zip file.
@@ -266,6 +287,9 @@
     /* Gets the path of a bugreport file with the given suffix. */
     std::string GetPath(const std::string& suffix) const;
 
+    /* Returns true if the current version supports priority dump feature. */
+    bool CurrentVersionSupportsPriorityDumps() const;
+
     // TODO: initialize fields on constructor
 
     // dumpstate id - unique after each device reboot.
@@ -332,14 +356,21 @@
     // Pointer to the zip structure.
     std::unique_ptr<ZipWriter> zip_writer_;
 
-    // Binder object listing to progress.
+    // Binder object listening to progress.
     android::sp<android::os::IDumpstateListener> listener_;
     std::string listener_name_;
+    bool report_section_;
 
     // Notification title and description
     std::string notification_title;
     std::string notification_description;
 
+    // List of open tombstone dump files.
+    std::vector<DumpData> tombstone_data_;
+
+    // List of open ANR dump files.
+    std::vector<DumpData> anr_data_;
+
   private:
     // Used by GetInstance() only.
     Dumpstate(const std::string& version = VERSION_CURRENT);
@@ -424,6 +455,9 @@
 /** Gets command-line arguments. */
 void format_args(int argc, const char *argv[], std::string *args);
 
+/** Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/cmds/dumpstate/main.cpp
similarity index 71%
rename from vulkan/libvulkan/vulkan_loader_data.cpp
rename to cmds/dumpstate/main.cpp
index 0eda0af..78aad11 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/cmds/dumpstate/main.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "dumpstate.h"
 
-using namespace vulkan;
-
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
+int main(int argc, char* argv[]) {
+    return run_main(argc, argv);
 }
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
new file mode 100644
index 0000000..61a5ef5
--- /dev/null
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <android-base/file.h>
+#include <cutils/properties.h>
+#include <ziparchive/zip_archive.h>
+
+#include "dumpstate.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+using ::testing::Test;
+using ::std::literals::chrono_literals::operator""s;
+
+struct SectionInfo {
+    std::string name;
+    status_t status;
+    int32_t size_bytes;
+    int32_t duration_ms;
+};
+
+/**
+ * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
+ * section details generated by dumpstate are added to a vector to be used by Tests later.
+ */
+class DumpstateListener : public IDumpstateListener {
+  public:
+    int outFd_, max_progress_;
+    std::shared_ptr<std::vector<SectionInfo>> sections_;
+    DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
+        : outFd_(fd), max_progress_(5000), sections_(sections) {
+    }
+    binder::Status onProgressUpdated(int32_t progress) override {
+        dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+        return binder::Status::ok();
+    }
+    binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+        max_progress_ = max_progress;
+        return binder::Status::ok();
+    }
+    binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
+                                     int32_t duration_ms) override {
+        sections_->push_back({name, status, size_bytes, duration_ms});
+        return binder::Status::ok();
+    }
+    IBinder* onAsBinder() override {
+        return nullptr;
+    }
+};
+
+/**
+ * Generates bug report and provide access to the bug report file and other info for other tests.
+ * Since bug report generation is slow, the bugreport is only generated once.
+ */
+class ZippedBugreportGenerationTest : public Test {
+  public:
+    static std::shared_ptr<std::vector<SectionInfo>> sections;
+    static Dumpstate& ds;
+    static std::chrono::milliseconds duration;
+    static void SetUpTestCase() {
+        property_set("dumpstate.options", "bugreportplus");
+        // clang-format off
+        char* argv[] = {
+            (char*)"dumpstate",
+            (char*)"-d",
+            (char*)"-z",
+            (char*)"-B",
+            (char*)"-o",
+            (char*)dirname(android::base::GetExecutablePath().c_str())
+        };
+        // clang-format on
+        sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
+        ds.listener_ = listener;
+        ds.listener_name_ = "Smokey";
+        ds.report_section_ = true;
+        auto start = std::chrono::steady_clock::now();
+        run_main(ARRAY_SIZE(argv), argv);
+        auto end = std::chrono::steady_clock::now();
+        duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+    }
+
+    static const char* getZipFilePath() {
+        return ds.GetPath(".zip").c_str();
+    }
+};
+std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
+    std::make_shared<std::vector<SectionInfo>>();
+Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance();
+std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
+
+TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+    EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
+}
+
+TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+    struct stat st;
+    EXPECT_EQ(stat(getZipFilePath(), &st), 0);
+    EXPECT_GE(st.st_size, 3000000 /* 3MB */);
+    EXPECT_LE(st.st_size, 30000000 /* 30MB */);
+}
+
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+    EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
+                             << duration.count() << " s.";
+    EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+                              << duration.count() << " s.";
+}
+
+/**
+ * Run tests on contents of zipped bug report.
+ */
+class ZippedBugReportContentsTest : public Test {
+  public:
+    ZipArchiveHandle handle;
+    void SetUp() {
+        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
+    }
+    void TearDown() {
+        CloseArchive(handle);
+    }
+
+    void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+        ZipEntry entry;
+        EXPECT_EQ(FindEntry(handle, ZipString(filename), &entry), 0);
+        EXPECT_GT(entry.uncompressed_length, minsize);
+        EXPECT_LT(entry.uncompressed_length, maxsize);
+    }
+};
+
+TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
+    ZipEntry mainEntryLoc;
+    // contains main entry name file
+    EXPECT_EQ(FindEntry(handle, ZipString("main_entry.txt"), &mainEntryLoc), 0);
+
+    char* buf = new char[mainEntryLoc.uncompressed_length];
+    ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length);
+    delete[] buf;
+
+    // contains main entry file
+    FileExists(buf, 1000000U, 50000000U);
+}
+
+TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
+    ZipEntry entry;
+    // contains main entry name file
+    EXPECT_EQ(FindEntry(handle, ZipString("version.txt"), &entry), 0);
+
+    char* buf = new char[entry.uncompressed_length + 1];
+    ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
+    buf[entry.uncompressed_length] = 0;
+    EXPECT_STREQ(buf, ZippedBugreportGenerationTest::ds.version_.c_str());
+    delete[] buf;
+}
+
+TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
+    FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+    FileExists("dumpstate_board.txt", 100000U, 1000000U);
+}
+
+// Spot check on some files pulled from the file system
+TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
+    // FS/proc/*/mountinfo size > 0
+    FileExists("FS/proc/1/mountinfo", 0U, 100000U);
+
+    // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
+    FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
+}
+
+/**
+ * Runs tests on section data generated by dumpstate and captured by DumpstateListener.
+ */
+class BugreportSectionTest : public Test {
+  public:
+    int numMatches(const std::string& substring) {
+        int matches = 0;
+        for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+            if (section.name.find(substring) != std::string::npos) {
+                matches++;
+            }
+        }
+        return matches;
+    }
+    void SectionExists(const std::string& sectionName, int minsize) {
+        for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+            if (sectionName == section.name) {
+                EXPECT_GE(section.size_bytes, minsize);
+                return;
+            }
+        }
+        FAIL() << sectionName << " not found.";
+    }
+};
+
+// Test all sections are generated without timeouts or errors
+TEST_F(BugreportSectionTest, GeneratedWithoutErrors) {
+    for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+        EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status;
+    }
+}
+
+TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
+    int numSections = numMatches("DUMPSYS CRITICAL");
+    EXPECT_GE(numSections, 3);
+}
+
+TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
+    int numSections = numMatches("DUMPSYS HIGH");
+    EXPECT_GE(numSections, 2);
+}
+
+TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
+    int allSections = numMatches("DUMPSYS");
+    int criticalSections = numMatches("DUMPSYS CRITICAL");
+    int highSections = numMatches("DUMPSYS HIGH");
+    int normalSections = allSections - criticalSections - highSections;
+
+    EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
+                                  << "High:" << highSections << "Normal:" << normalSections << ")";
+}
+
+TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) {
+    int numSections = numMatches("proto/");
+    EXPECT_GE(numSections, 1);
+}
+
+// Test if some critical sections are being generated.
+TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
+    SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000);
+}
+
+TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
+    SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000);
+    SectionExists("DUMPSYS - activity", /* bytes= */ 10000);
+}
+
+TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
+    SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000);
+}
+
+TEST_F(BugreportSectionTest, WindowSectionGenerated) {
+    SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000);
+}
+
+TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
+    SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000);
+    SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000);
+}
+
+TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
+    SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000);
+}
+
+TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
+    SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000);
+}
+
+TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+    SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index a94cf99..838b385 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -58,6 +58,8 @@
   public:
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
     MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
+    MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
+                                                   int32_t size, int32_t durationMs));
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
@@ -477,6 +479,48 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+        return;
+    }
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
     EXPECT_THAT(out,
@@ -559,27 +603,43 @@
 TEST_F(DumpstateServiceTest, SetListenerNoName) {
     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
     sp<IDumpstateToken> token;
-    EXPECT_TRUE(dss.setListener("", listener, &token).isOk());
+    EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
     ASSERT_THAT(token, IsNull());
 }
 
 TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
     sp<IDumpstateToken> token;
-    EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk());
+    EXPECT_TRUE(
+        dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
     ASSERT_THAT(token, IsNull());
 }
 
 TEST_F(DumpstateServiceTest, SetListenerTwice) {
     sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
     sp<IDumpstateToken> token;
-    EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk());
+    EXPECT_TRUE(
+        dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk());
     ASSERT_THAT(token, NotNull());
     EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+    EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
 
     token.clear();
-    EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk());
+    EXPECT_TRUE(
+        dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk());
     ASSERT_THAT(token, IsNull());
     EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+    EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
+}
+
+TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) {
+    sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+    sp<IDumpstateToken> token;
+    Dumpstate::GetInstance().listener_ = nullptr;
+    EXPECT_TRUE(
+        dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk());
+    ASSERT_THAT(token, NotNull());
+    EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+    EXPECT_TRUE(Dumpstate::GetInstance().report_section_);
 }
 
 class ProgressTest : public DumpstateBaseTest {
@@ -959,7 +1019,7 @@
         err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
 }
 
-TEST_F(DumpstateUtilTest, RunCommandTimesout) {
+TEST_F(DumpstateUtilTest, RunCommandTimesoutWithSec) {
     CreateFd("RunCommandTimesout.txt");
     EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
                              CommandOptions::WithTimeout(1).Build()));
@@ -969,6 +1029,17 @@
                                 " --sleep 2' timed out after 1"));
 }
 
+TEST_F(DumpstateUtilTest, RunCommandTimesoutWithMsec) {
+    CreateFd("RunCommandTimesout.txt");
+    EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
+                             CommandOptions::WithTimeoutInMs(1000).Build()));
+    EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+    EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
+                                " --sleep 2' timed out after 1"));
+}
+
+
 TEST_F(DumpstateUtilTest, RunCommandIsKilled) {
     CreateFd("RunCommandIsKilled.txt");
     CaptureStderr();
@@ -1053,6 +1124,51 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnUserBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootIfAvailableOnUserBuild.txt");
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootIfAvailableOnDebugBuild.txt");
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
     if (!IsStandalone()) {
         // TODO: temporarily disabled because it might cause other tests to fail after dropping
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 93f4c22..022f4fc 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -48,10 +48,10 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <debuggerd/client.h>
+#include <dumputils/dump_utils.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -76,34 +76,6 @@
     return ds.RunCommand(title, full_command, options);
 }
 
-/* list of native processes to include in the native dumps */
-// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
-static const char* native_processes_to_dump[] = {
-        "/system/bin/audioserver",
-        "/system/bin/cameraserver",
-        "/system/bin/drmserver",
-        "/system/bin/mediadrmserver",
-        "/system/bin/mediaextractor", // media.extractor
-        "/system/bin/mediaserver",
-        "/system/bin/sdcard",
-        "/system/bin/surfaceflinger",
-        "/system/bin/vehicle_network_service",
-        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
-        NULL,
-};
-
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
-        "android.hardware.bluetooth@1.0::IBluetoothHci",
-        "android.hardware.camera.provider@2.4::ICameraProvider",
-        "android.hardware.graphics.composer@2.1::IComposer",
-        "android.hardware.media.omx@1.0::IOmx",
-        "android.hardware.sensors@1.0::ISensors",
-        "android.hardware.vr@1.0::IVr",
-        NULL,
-};
-
 // Reasonable value for max stats.
 static const int STATS_MAX_N_RUNS = 1000;
 static const long STATS_MAX_AVERAGE = 100000;
@@ -215,10 +187,10 @@
     return progress_;
 }
 
-bool Progress::Inc(int32_t delta) {
+bool Progress::Inc(int32_t delta_sec) {
     bool changed = false;
-    if (delta >= 0) {
-        progress_ += delta;
+    if (delta_sec >= 0) {
+        progress_ += delta_sec;
         if (progress_ > max_) {
             int32_t old_max = max_;
             max_ = floor((float)progress_ * growth_factor_);
@@ -628,7 +600,7 @@
     struct dirent *d;
     char *newpath = NULL;
     const char *slash = "/";
-    int fd, retval = 0;
+    int retval = 0;
 
     if (!title.empty()) {
         printf("------ %s (%s) ------\n", title.c_str(), dir);
@@ -670,13 +642,13 @@
             }
             continue;
         }
-        fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-        if (fd < 0) {
-            retval = fd;
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+        if (fd.get() < 0) {
+            retval = -1;
             printf("*** %s: %s\n", newpath, strerror(errno));
             continue;
         }
-        (*dump_from_fd)(NULL, newpath, fd);
+        (*dump_from_fd)(NULL, newpath, fd.get());
     }
     closedir(dirp);
     if (!title.empty()) {
@@ -695,11 +667,9 @@
     int flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
         printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
-        close(fd);
         return -1;
     } else if (!(flags & O_NONBLOCK)) {
         printf("*** %s: fd must have O_NONBLOCK set.\n", path);
-        close(fd);
         return -1;
     }
     return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
@@ -721,9 +691,9 @@
 }
 
 void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
-                           const CommandOptions& options, long dumpsysTimeout) {
-    long timeout = dumpsysTimeout > 0 ? dumpsysTimeout : options.Timeout();
-    std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-t", std::to_string(timeout)};
+                           const CommandOptions& options, long dumpsysTimeoutMs) {
+    long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
+    std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
     dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
     RunCommand(title, dumpsys, options);
 }
@@ -809,53 +779,6 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
-static bool should_dump_hal_interface(const char* interface) {
-    for (const char** i = hal_interfaces_to_dump; *i; i++) {
-        if (!strcmp(*i, interface)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool should_dump_native_traces(const char* path) {
-    for (const char** p = native_processes_to_dump; *p; p++) {
-        if (!strcmp(*p, path)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-std::set<int> get_interesting_hal_pids() {
-    using android::hidl::manager::V1_0::IServiceManager;
-    using android::sp;
-    using android::hardware::Return;
-
-    sp<IServiceManager> manager = IServiceManager::getService();
-    std::set<int> pids;
-
-    Return<void> ret = manager->debugDump([&](auto& hals) {
-        for (const auto &info : hals) {
-            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
-                continue;
-            }
-
-            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
-                continue;
-            }
-
-            pids.insert(info.pid);
-        }
-    });
-
-    if (!ret.isOk()) {
-        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
-    }
-
-    return pids; // whether it was okay or not
-}
-
 const char* DumpTraces(const std::string& traces_path);
 const char* DumpTracesTombstoned(const std::string& traces_dir);
 
@@ -876,18 +799,6 @@
     return nullptr;
 }
 
-static bool IsZygote(int pid) {
-    static const std::string kZygotePrefix = "zygote";
-
-    std::string cmdline;
-    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
-                                         &cmdline)) {
-        return true;
-    }
-
-    return (cmdline.find(kZygotePrefix) == 0);
-}
-
 const char* DumpTracesTombstoned(const std::string& traces_dir) {
     const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
 
@@ -1163,14 +1074,14 @@
 }
 
 // TODO: make this function thread safe if sections are generated in parallel.
-void Dumpstate::UpdateProgress(int32_t delta) {
+void Dumpstate::UpdateProgress(int32_t delta_sec) {
     if (progress_ == nullptr) {
         MYLOGE("UpdateProgress: progress_ not set\n");
         return;
     }
 
     // Always update progess so stats can be tuned...
-    bool max_changed = progress_->Inc(delta);
+    bool max_changed = progress_->Inc(delta_sec);
 
     // ...but only notifiy listeners when necessary.
     if (!update_progress_) return;
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 3476964..f68b862 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -17,6 +17,10 @@
         "libbinder",
     ],
 
+    static_libs: [
+        "libserviceutils",
+    ],
+
     clang: true,
 }
 
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index fa6f6df..5412d4d 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/TextOutput.h>
+#include <serviceutils/PriorityDumper.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
 
@@ -42,9 +43,11 @@
 #include "dumpsys.h"
 
 using namespace android;
-using android::base::StringPrintf;
-using android::base::unique_fd;
-using android::base::WriteFully;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::unique_fd;
+using ::android::base::WriteFully;
+using ::android::base::WriteStringToFd;
 
 static int sort_func(const String16* lhs, const String16* rhs)
 {
@@ -53,13 +56,19 @@
 
 static void usage() {
     fprintf(stderr,
-        "usage: dumpsys\n"
+            "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
+            "SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
-            "         -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
+            "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
+            "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
+            "         --proto: filter services that support dumping data in proto format. Dumps"
+            "               will be in proto format.\n"
+            "         --priority LEVEL: filter services based on specified priority\n"
+            "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
             "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
             "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
@@ -73,18 +82,51 @@
     return false;
 }
 
+static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) {
+    if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL;
+        return true;
+    }
+    if (type == PriorityDumper::PRIORITY_ARG_HIGH) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH;
+        return true;
+    }
+    if (type == PriorityDumper::PRIORITY_ARG_NORMAL) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL;
+        return true;
+    }
+    return false;
+}
+
+String16 ConvertBitmaskToPriorityType(int bitmask) {
+    if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
+        return String16(PriorityDumper::PRIORITY_ARG_CRITICAL);
+    }
+    if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
+        return String16(PriorityDumper::PRIORITY_ARG_HIGH);
+    }
+    if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
+        return String16(PriorityDumper::PRIORITY_ARG_NORMAL);
+    }
+    return String16("");
+}
+
 int Dumpsys::main(int argc, char* const argv[]) {
     Vector<String16> services;
     Vector<String16> args;
+    String16 priorityType;
     Vector<String16> skippedServices;
+    Vector<String16> protoServices;
     bool showListOnly = false;
     bool skipServices = false;
-    int timeoutArg = 10;
-    static struct option longOptions[] = {
-        {"skip", no_argument, 0,  0 },
-        {"help", no_argument, 0,  0 },
-        {     0,           0, 0,  0 }
-    };
+    bool asProto = false;
+    int timeoutArgMs = 10000;
+    int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
+    static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+                                          {"proto", no_argument, 0, 0},
+                                          {"skip", no_argument, 0, 0},
+                                          {"help", no_argument, 0, 0},
+                                          {0, 0, 0, 0}};
 
     // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
     // happens on test cases).
@@ -93,7 +135,7 @@
         int c;
         int optionIndex = 0;
 
-        c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
+        c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);
 
         if (c == -1) {
             break;
@@ -103,18 +145,39 @@
         case 0:
             if (!strcmp(longOptions[optionIndex].name, "skip")) {
                 skipServices = true;
+            } else if (!strcmp(longOptions[optionIndex].name, "proto")) {
+                asProto = true;
             } else if (!strcmp(longOptions[optionIndex].name, "help")) {
                 usage();
                 return 0;
+            } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
+                priorityType = String16(String8(optarg));
+                if (!ConvertPriorityTypeToBitmask(priorityType, priorityFlags)) {
+                    fprintf(stderr, "\n");
+                    usage();
+                    return -1;
+                }
             }
             break;
 
         case 't':
             {
-                char *endptr;
-                timeoutArg = strtol(optarg, &endptr, 10);
-                if (*endptr != '\0' || timeoutArg <= 0) {
-                    fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
+                char* endptr;
+                timeoutArgMs = strtol(optarg, &endptr, 10);
+                timeoutArgMs = timeoutArgMs * 1000;
+                if (*endptr != '\0' || timeoutArgMs <= 0) {
+                    fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg);
+                    return -1;
+                }
+            }
+            break;
+
+        case 'T':
+            {
+                char* endptr;
+                timeoutArgMs = strtol(optarg, &endptr, 10);
+                if (*endptr != '\0' || timeoutArgMs <= 0) {
+                    fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg);
                     return -1;
                 }
             }
@@ -150,14 +213,11 @@
     }
 
     if (services.empty() || showListOnly) {
-        // gets all services
-        services = sm_->listServices();
-        services.sort(sort_func);
-        args.add(String16("-a"));
+        services = listServices(priorityFlags, asProto);
+        setServiceArgs(args, asProto, priorityFlags);
     }
 
     const size_t N = services.size();
-
     if (N > 1) {
         // first print a list of the current services
         aout << "Currently running services:" << endl;
@@ -177,125 +237,214 @@
     }
 
     for (size_t i = 0; i < N; i++) {
-        String16 service_name = std::move(services[i]);
-        if (IsSkipped(skippedServices, service_name)) continue;
+        const String16& serviceName = services[i];
+        if (IsSkipped(skippedServices, serviceName)) continue;
 
-        sp<IBinder> service = sm_->checkService(service_name);
-        if (service != nullptr) {
-            int sfd[2];
-
-            if (pipe(sfd) != 0) {
-                aerr << "Failed to create pipe to dump service info for " << service_name
-                     << ": " << strerror(errno) << endl;
-                continue;
+        if (startDumpThread(serviceName, args) == OK) {
+            bool addSeparator = (N > 1);
+            if (addSeparator) {
+                writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
             }
+            std::chrono::duration<double> elapsedDuration;
+            size_t bytesWritten = 0;
+            status_t status =
+                writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
+                          asProto, elapsedDuration, bytesWritten);
 
-            unique_fd local_end(sfd[0]);
-            unique_fd remote_end(sfd[1]);
-            sfd[0] = sfd[1] = -1;
-
-            if (N > 1) {
-                aout << "------------------------------------------------------------"
-                        "-------------------" << endl;
-                aout << "DUMP OF SERVICE " << service_name << ":" << endl;
-            }
-
-            // dump blocks until completion, so spawn a thread..
-            std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
-                int err = service->dump(remote_end.get(), args);
-
-                // It'd be nice to be able to close the remote end of the socketpair before the dump
-                // call returns, to terminate our reads if the other end closes their copy of the
-                // file descriptor, but then hangs for some reason. There doesn't seem to be a good
-                // way to do this, though.
-                remote_end.reset();
-
-                if (err != 0) {
-                    aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
-                         << endl;
-                }
-            });
-
-            auto timeout = std::chrono::seconds(timeoutArg);
-            auto start = std::chrono::steady_clock::now();
-            auto end = start + timeout;
-
-            struct pollfd pfd = {
-                .fd = local_end.get(),
-                .events = POLLIN
-            };
-
-            bool timed_out = false;
-            bool error = false;
-            while (true) {
-                // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
-                auto time_left_ms = [end]() {
-                    auto now = std::chrono::steady_clock::now();
-                    auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
-                    return std::max(diff.count(), 0ll);
-                };
-
-                int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
-                if (rc < 0) {
-                    aerr << "Error in poll while dumping service " << service_name << " : "
-                         << strerror(errno) << endl;
-                    error = true;
-                    break;
-                } else if (rc == 0) {
-                    timed_out = true;
-                    break;
-                }
-
-                char buf[4096];
-                rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
-                if (rc < 0) {
-                    aerr << "Failed to read while dumping service " << service_name << ": "
-                         << strerror(errno) << endl;
-                    error = true;
-                    break;
-                } else if (rc == 0) {
-                    // EOF.
-                    break;
-                }
-
-                if (!WriteFully(STDOUT_FILENO, buf, rc)) {
-                    aerr << "Failed to write while dumping service " << service_name << ": "
-                         << strerror(errno) << endl;
-                    error = true;
-                    break;
-                }
-            }
-
-            if (timed_out) {
+            if (status == TIMED_OUT) {
                 aout << endl
-                     << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
-                     << "s) EXPIRED ***" << endl
+                     << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
+                     << "ms) EXPIRED ***" << endl
                      << endl;
             }
 
-            if (timed_out || error) {
-                dump_thread.detach();
-            } else {
-                dump_thread.join();
+            if (addSeparator) {
+                writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration);
             }
-
-            if (N > 1) {
-              std::chrono::duration<double> elapsed_seconds =
-                  std::chrono::steady_clock::now() - start;
-              aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
-                   << "was the duration of dumpsys " << service_name;
-
-              using std::chrono::system_clock;
-              const auto finish = system_clock::to_time_t(system_clock::now());
-              std::tm finish_tm;
-              localtime_r(&finish, &finish_tm);
-              aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
-                   << endl;
-            }
-        } else {
-            aerr << "Can't find service: " << service_name << endl;
+            bool dumpComplete = (status == OK);
+            stopDumpThread(dumpComplete);
         }
     }
 
     return 0;
 }
+
+Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
+    Vector<String16> services = sm_->listServices(priorityFilterFlags);
+    services.sort(sort_func);
+    if (filterByProto) {
+        Vector<String16> protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
+        protoServices.sort(sort_func);
+        Vector<String16> intersection;
+        std::set_intersection(services.begin(), services.end(), protoServices.begin(),
+                              protoServices.end(), std::back_inserter(intersection));
+        services = std::move(intersection);
+    }
+    return services;
+}
+
+void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) {
+    // Add proto flag if dumping service as proto.
+    if (asProto) {
+        args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
+    }
+
+    // Add -a (dump all) flag if dumping all services, dumping normal services or
+    // services not explicitly registered to a priority bucket (default services).
+    if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) ||
+        (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) ||
+        (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT)) {
+        args.insertAt(String16("-a"), 0);
+    }
+
+    // Add priority flags when dumping services registered to a specific priority bucket.
+    if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) ||
+        (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) ||
+        (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL)) {
+        String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
+        args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
+        args.insertAt(priorityType, 1);
+    }
+}
+
+status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args) {
+    sp<IBinder> service = sm_->checkService(serviceName);
+    if (service == nullptr) {
+        aerr << "Can't find service: " << serviceName << endl;
+        return NAME_NOT_FOUND;
+    }
+
+    int sfd[2];
+    if (pipe(sfd) != 0) {
+        aerr << "Failed to create pipe to dump service info for " << serviceName << ": "
+             << strerror(errno) << endl;
+        return -errno;
+    }
+
+    redirectFd_ = unique_fd(sfd[0]);
+    unique_fd remote_end(sfd[1]);
+    sfd[0] = sfd[1] = -1;
+
+    // dump blocks until completion, so spawn a thread..
+    activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
+        int err = service->dump(remote_end.get(), args);
+
+        // It'd be nice to be able to close the remote end of the socketpair before the dump
+        // call returns, to terminate our reads if the other end closes their copy of the
+        // file descriptor, but then hangs for some reason. There doesn't seem to be a good
+        // way to do this, though.
+        remote_end.reset();
+
+        if (err != 0) {
+            aerr << "Error dumping service info: (" << strerror(err) << ") "
+                 << serviceName << endl;
+        }
+    });
+    return OK;
+}
+
+void Dumpsys::stopDumpThread(bool dumpComplete) {
+    if (dumpComplete) {
+        activeThread_.join();
+    } else {
+        activeThread_.detach();
+    }
+    /* close read end of the dump output redirection pipe */
+    redirectFd_.reset();
+}
+
+void Dumpsys::writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const {
+    std::string msg(
+        "----------------------------------------"
+        "---------------------------------------\n");
+    if (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL ||
+        priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL ||
+        priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
+        StringAppendF(&msg, "DUMP OF SERVICE %s:\n", String8(serviceName).c_str());
+    } else {
+        String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
+        StringAppendF(&msg, "DUMP OF SERVICE %s %s:\n", String8(priorityType).c_str(),
+                      String8(serviceName).c_str());
+    }
+    WriteStringToFd(msg, fd);
+}
+
+status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
+                            bool asProto, std::chrono::duration<double>& elapsedDuration,
+                            size_t& bytesWritten) const {
+    status_t status = OK;
+    size_t totalBytes = 0;
+    auto start = std::chrono::steady_clock::now();
+    auto end = start + timeout;
+
+    int serviceDumpFd = redirectFd_.get();
+    if (serviceDumpFd == -1) {
+        return INVALID_OPERATION;
+    }
+
+    struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN};
+
+    while (true) {
+        // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
+        auto time_left_ms = [end]() {
+            auto now = std::chrono::steady_clock::now();
+            auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+            return std::max(diff.count(), 0ll);
+        };
+
+        int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+        if (rc < 0) {
+            aerr << "Error in poll while dumping service " << serviceName << " : "
+                 << strerror(errno) << endl;
+            status = -errno;
+            break;
+        } else if (rc == 0) {
+            status = TIMED_OUT;
+            break;
+        }
+
+        char buf[4096];
+        rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));
+        if (rc < 0) {
+            aerr << "Failed to read while dumping service " << serviceName << ": "
+                 << strerror(errno) << endl;
+            status = -errno;
+            break;
+        } else if (rc == 0) {
+            // EOF.
+            break;
+        }
+
+        if (!WriteFully(fd, buf, rc)) {
+            aerr << "Failed to write while dumping service " << serviceName << ": "
+                 << strerror(errno) << endl;
+            status = -errno;
+            break;
+        }
+        totalBytes += rc;
+    }
+
+    if ((status == TIMED_OUT) && (!asProto)) {
+        std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n",
+                                       String8(serviceName).string(), timeout.count());
+        WriteStringToFd(msg, fd);
+    }
+
+    elapsedDuration = std::chrono::steady_clock::now() - start;
+    bytesWritten = totalBytes;
+    return status;
+}
+
+void Dumpsys::writeDumpFooter(int fd, const String16& serviceName,
+                              const std::chrono::duration<double>& elapsedDuration) const {
+    using std::chrono::system_clock;
+    const auto finish = system_clock::to_time_t(system_clock::now());
+    std::tm finish_tm;
+    localtime_r(&finish, &finish_tm);
+    std::stringstream oss;
+    oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S");
+    std::string msg =
+        StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n",
+                     elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str());
+    WriteStringToFd(msg, fd);
+}
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 2534dde..84f3b02 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -17,6 +17,9 @@
 #ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
 #define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
 
+#include <thread>
+
+#include <android-base/unique_fd.h>
 #include <binder/IServiceManager.h>
 
 namespace android {
@@ -25,10 +28,97 @@
   public:
     Dumpsys(android::IServiceManager* sm) : sm_(sm) {
     }
+    /**
+     * Main entry point into dumpsys.
+     */
     int main(int argc, char* const argv[]);
 
+    /**
+     * Returns a list of services.
+     * @param priorityFlags filter services by specified priorities
+     * @param supportsProto filter services that support proto dumps
+     * @return list of services
+     */
+    Vector<String16> listServices(int priorityFlags, bool supportsProto) const;
+
+    /**
+     * Modifies @{code args} to add additional arguments  to indicate if the service
+     * must dump as proto or dump to a certian priority bucket.
+     * @param args initial list of arguments to pass to service dump method.
+     * @param asProto dump service as proto by passing an additional --proto arg
+     * @param priorityFlags indicates priority of dump by passing additional priority args
+     * to the service
+     */
+    static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
+
+    /**
+     * Starts a thread to connect to a service and get its dump output. The thread redirects
+     * the output to a pipe. Thread must be stopped by a subsequent callto {@code
+     * stopDumpThread}.
+     * @param serviceName
+     * @param args list of arguments to pass to service dump method.
+     * @return {@code OK} thread is started successfully.
+     *         {@code NAME_NOT_FOUND} service could not be found.
+     *         {@code != OK} error
+     */
+    status_t startDumpThread(const String16& serviceName, const Vector<String16>& args);
+
+    /**
+     * Writes a section header to a file descriptor.
+     * @param fd file descriptor to write data
+     * @param serviceName
+     * @param priorityFlags dump priority specified
+     */
+    void writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const;
+
+    /**
+     * Redirects service dump to a file descriptor. This requires
+     * {@code startDumpThread} to be called successfully otherwise the function will
+     * return {@code INVALID_OPERATION}.
+     * @param fd file descriptor to write data
+     * @param serviceName
+     * @param timeout timeout to terminate the dump if not completed
+     * @param asProto used to supresses additional output to the fd such as timeout
+     * error messages
+     * @param elapsedDuration returns elapsed time in seconds
+     * @param bytesWritten returns number of bytes written
+     * @return {@code OK} if successful
+     *         {@code TIMED_OUT} dump timed out
+     *         {@code INVALID_OPERATION} invalid state
+     *         {@code != OK} error
+     */
+    status_t writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
+                       bool asProto, std::chrono::duration<double>& elapsedDuration,
+                       size_t& bytesWritten) const;
+
+    /**
+     * Writes a section footer to a file descriptor with duration info.
+     * @param fd file descriptor to write data
+     * @param serviceName
+     * @param elapsedDuration duration of dump
+     */
+    void writeDumpFooter(int fd, const String16& serviceName,
+                         const std::chrono::duration<double>& elapsedDuration) const;
+
+    /**
+     * Terminates dump thread.
+     * @param dumpComplete If {@code true}, indicates the dump was successfully completed and
+     * tries to join the thread. Otherwise thread is detached.
+     */
+    void stopDumpThread(bool dumpComplete);
+
+    /**
+     * Returns file descriptor of the pipe used to dump service data. This assumes
+     * {@code startDumpThread} was called successfully.
+     */
+    int getDumpFd() const {
+        return redirectFd_.get();
+    }
+
   private:
     android::IServiceManager* sm_;
+    std::thread activeThread_;
+    mutable android::base::unique_fd redirectFd_;
 };
 }
 
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 127e0f3..e182b9d 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -4,6 +4,7 @@
     test_suites: ["device-tests"],
 
     srcs: ["dumpsys_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
 
     shared_libs: [
         "libbase",
@@ -14,6 +15,7 @@
     static_libs: [
         "libdumpsys",
         "libgmock",
+        "libserviceutils",
     ],
 
     clang: true,
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index cfd53e5..5029352 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 
 #include <android-base/file.h>
+#include <serviceutils/PriorityDumper.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -50,8 +51,8 @@
   public:
     MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
     MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
-    MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
-    MOCK_METHOD0(listServices, Vector<String16>());
+    MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
+    MOCK_METHOD1(listServices, Vector<String16>(int));
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
@@ -96,7 +97,7 @@
     }
     int i = 0;
     std::ostringstream actual_stream, expected_stream;
-    for (String16 actual : arg) {
+    for (const String16& actual : arg) {
         std::string actual_str = String8(actual).c_str();
         std::string expected_str = expected[i];
         actual_stream << "'" << actual_str << "' ";
@@ -131,7 +132,16 @@
         for (auto& service : services) {
             services16.add(String16(service.c_str()));
         }
-        EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+        EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL))
+            .WillRepeatedly(Return(services16));
+    }
+
+    void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpFlags) {
+        Vector<String16> services16;
+        for (auto& service : services) {
+            services16.add(String16(service.c_str()));
+        }
+        EXPECT_CALL(sm_, listServices(dumpFlags)).WillRepeatedly(Return(services16));
     }
 
     sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
@@ -178,8 +188,27 @@
         EXPECT_THAT(status, Eq(0));
     }
 
+    void CallSingleService(const String16& serviceName, Vector<String16>& args, int priorityFlags,
+                           bool supportsProto, std::chrono::duration<double>& elapsedDuration,
+                           size_t& bytesWritten) {
+        CaptureStdout();
+        CaptureStderr();
+        dump_.setServiceArgs(args, supportsProto, priorityFlags);
+        status_t status = dump_.startDumpThread(serviceName, args);
+        EXPECT_THAT(status, Eq(0));
+        status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
+                                 elapsedDuration, bytesWritten);
+        EXPECT_THAT(status, Eq(0));
+        dump_.stopDumpThread(/* dumpCompleted = */ true);
+        stdout_ = GetCapturedStdout();
+        stderr_ = GetCapturedStderr();
+    }
+
     void AssertRunningServices(const std::vector<std::string>& services) {
-        std::string expected("Currently running services:\n");
+        std::string expected;
+        if (services.size() > 1) {
+            expected.append("Currently running services:\n");
+        }
         for (const std::string& service : services) {
             expected.append("  ").append(service).append("\n");
         }
@@ -196,6 +225,15 @@
 
     void AssertDumped(const std::string& service, const std::string& dump) {
         EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
+        EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
+    }
+
+    void AssertDumpedWithPriority(const std::string& service, const std::string& dump,
+                                  const char16_t* priorityType) {
+        std::string priority = String8(priorityType).c_str();
+        EXPECT_THAT(stdout_,
+                    HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump));
+        EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
     }
 
     void AssertNotDumped(const std::string& dump) {
@@ -236,6 +274,39 @@
     AssertNotDumped({"Valet"});
 }
 
+// Tests 'dumpsys -l --priority HIGH'
+TEST_F(DumpsysTest, ListAllServicesWithPriority) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l --priority HIGH' with and empty list
+TEST_F(DumpsysTest, ListEmptyServicesWithPriority) {
+    ExpectListServicesWithPriority({}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({});
+}
+
+// Tests 'dumpsys -l --proto'
+TEST_F(DumpsysTest, ListAllServicesWithProto) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet", "Car"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+    ExpectListServicesWithPriority({"Valet", "Car"}, IServiceManager::DUMP_FLAG_PROTO);
+    ExpectCheckService("Car");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l", "--proto"});
+
+    AssertRunningServices({"Car", "Valet"});
+}
+
 // Tests 'dumpsys service_name' on a service is running
 TEST_F(DumpsysTest, DumpRunningService) {
     ExpectDump("Valet", "Here's your car");
@@ -246,12 +317,25 @@
 }
 
 // Tests 'dumpsys -t 1 service_name' on a service that times out after 2s
-TEST_F(DumpsysTest, DumpRunningServiceTimeout) {
+TEST_F(DumpsysTest, DumpRunningServiceTimeoutInSec) {
     sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car");
 
     CallMain({"-t", "1", "Valet"});
 
-    AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED");
+    AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1000ms) EXPIRED");
+    AssertNotDumped("Here's your car");
+
+    // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp
+    Mock::AllowLeak(binder_mock.get());
+}
+
+// Tests 'dumpsys -T 500 service_name' on a service that times out after 2s
+TEST_F(DumpsysTest, DumpRunningServiceTimeoutInMs) {
+    sp<BinderMock> binder_mock = ExpectDumpAndHang("Valet", 2, "Here's your car");
+
+    CallMain({"-T", "500", "Valet"});
+
+    AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (500ms) EXPIRED");
     AssertNotDumped("Here's your car");
 
     // TODO(b/65056227): BinderMock is not destructed because thread is detached on dumpsys.cpp
@@ -267,6 +351,65 @@
     AssertOutput("I DO!");
 }
 
+// Tests dumpsys passes the -a flag when called on all services
+TEST_F(DumpsysTest, PassAllFlagsToServices) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+    ExpectDumpWithArgs("Locksmith", {"-a"}, "dumped1");
+    ExpectDumpWithArgs("Valet", {"-a"}, "dumped2");
+
+    CallMain({"-T", "500"});
+
+    AssertDumped("Locksmith", "dumped1");
+    AssertDumped("Valet", "dumped2");
+}
+
+// Tests dumpsys passes the -a flag when called on NORMAL priority services
+TEST_F(DumpsysTest, PassAllFlagsToNormalServices) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+    ExpectDumpWithArgs("Locksmith", {"-a", "--dump-priority", "NORMAL"}, "dump1");
+    ExpectDumpWithArgs("Valet", {"-a", "--dump-priority", "NORMAL"}, "dump2");
+
+    CallMain({"--priority", "NORMAL"});
+
+    AssertDumped("Locksmith", "dump1");
+    AssertDumped("Valet", "dump2");
+}
+
+// Tests dumpsys passes only priority flags when called on CRITICAL priority services
+TEST_F(DumpsysTest, PassPriorityFlagsToCriticalServices) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+    ExpectDumpWithArgs("Locksmith", {"--dump-priority", "CRITICAL"}, "dump1");
+    ExpectDumpWithArgs("Valet", {"--dump-priority", "CRITICAL"}, "dump2");
+
+    CallMain({"--priority", "CRITICAL"});
+
+    AssertDumpedWithPriority("Locksmith", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertDumpedWithPriority("Valet", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL);
+}
+
+// Tests dumpsys passes only priority flags when called on HIGH priority services
+TEST_F(DumpsysTest, PassPriorityFlagsToHighServices) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+    ExpectDumpWithArgs("Locksmith", {"--dump-priority", "HIGH"}, "dump1");
+    ExpectDumpWithArgs("Valet", {"--dump-priority", "HIGH"}, "dump2");
+
+    CallMain({"--priority", "HIGH"});
+
+    AssertDumpedWithPriority("Locksmith", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+    AssertDumpedWithPriority("Valet", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
+}
+
 // Tests 'dumpsys' with no arguments
 TEST_F(DumpsysTest, DumpMultipleServices) {
     ExpectListServices({"running1", "stopped2", "running3"});
@@ -300,3 +443,124 @@
     AssertNotDumped("dump3");
     AssertNotDumped("dump5");
 }
+
+// Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services
+TEST_F(DumpsysTest, DumpWithSkipAndPriority) {
+    ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+    ExpectDump("running1", "dump1");
+    ExpectCheckService("stopped2", false);
+    ExpectDump("skipped3", "dump3");
+    ExpectDump("running4", "dump4");
+    ExpectDump("skipped5", "dump5");
+
+    CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"});
+
+    AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+    AssertDumpedWithPriority("running1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertDumpedWithPriority("running4", "dump4", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertStopped("stopped2");
+    AssertNotDumped("dump3");
+    AssertNotDumped("dump5");
+}
+
+// Tests 'dumpsys --priority CRITICAL'
+TEST_F(DumpsysTest, DumpWithPriorityCritical) {
+    ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+    ExpectDump("runningcritical1", "dump1");
+    ExpectDump("runningcritical2", "dump2");
+
+    CallMain({"--priority", "CRITICAL"});
+
+    AssertRunningServices({"runningcritical1", "runningcritical2"});
+    AssertDumpedWithPriority("runningcritical1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertDumpedWithPriority("runningcritical2", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL);
+}
+
+// Tests 'dumpsys --priority HIGH'
+TEST_F(DumpsysTest, DumpWithPriorityHigh) {
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+    ExpectDump("runninghigh1", "dump1");
+    ExpectDump("runninghigh2", "dump2");
+
+    CallMain({"--priority", "HIGH"});
+
+    AssertRunningServices({"runninghigh1", "runninghigh2"});
+    AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+    AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
+}
+
+// Tests 'dumpsys --priority NORMAL'
+TEST_F(DumpsysTest, DumpWithPriorityNormal) {
+    ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+    ExpectDump("runningnormal1", "dump1");
+    ExpectDump("runningnormal2", "dump2");
+
+    CallMain({"--priority", "NORMAL"});
+
+    AssertRunningServices({"runningnormal1", "runningnormal2"});
+    AssertDumped("runningnormal1", "dump1");
+    AssertDumped("runningnormal2", "dump2");
+}
+
+// Tests 'dumpsys --proto'
+TEST_F(DumpsysTest, DumpWithProto) {
+    ExpectListServicesWithPriority({"run8", "run1", "run2", "run5"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+    ExpectListServicesWithPriority({"run3", "run2", "run4", "run8"},
+                                   IServiceManager::DUMP_FLAG_PROTO);
+    ExpectDump("run2", "dump1");
+    ExpectDump("run8", "dump2");
+
+    CallMain({"--proto"});
+
+    AssertRunningServices({"run2", "run8"});
+    AssertDumped("run2", "dump1");
+    AssertDumped("run8", "dump2");
+}
+
+// Tests 'dumpsys --priority HIGH --proto'
+TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) {
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2", "runninghigh3"},
+                                   IServiceManager::DUMP_FLAG_PROTO);
+
+    ExpectDump("runninghigh1", "dump1");
+    ExpectDump("runninghigh2", "dump2");
+
+    CallMain({"--priority", "HIGH", "--proto"});
+
+    AssertRunningServices({"runninghigh1", "runninghigh2"});
+    AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+    AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
+}
+
+TEST_F(DumpsysTest, GetBytesWritten) {
+    const char* serviceName = "service2";
+    const char* dumpContents = "dump1";
+    ExpectDump(serviceName, dumpContents);
+
+    String16 service(serviceName);
+    Vector<String16> args;
+    std::chrono::duration<double> elapsedDuration;
+    size_t bytesWritten;
+
+    CallSingleService(service, args, IServiceManager::DUMP_FLAG_PRIORITY_ALL,
+                      /* as_proto = */ false, elapsedDuration, bytesWritten);
+
+    AssertOutput(dumpContents);
+    EXPECT_THAT(bytesWritten, Eq(strlen(dumpContents)));
+}
+
+TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) {
+    std::chrono::duration<double> elapsedDuration;
+    size_t bytesWritten;
+    status_t status =
+        dump_.writeDump(STDOUT_FILENO, String16("service"), std::chrono::milliseconds(500),
+                        /* as_proto = */ false, elapsedDuration, bytesWritten);
+    EXPECT_THAT(status, Eq(INVALID_OPERATION));
+}
\ No newline at end of file
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index c295167..7aa111c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -8,6 +8,8 @@
     Renderers.cpp   \
     Main.cpp        \
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MODULE:= flatland
 
 LOCAL_MODULE_TAGS := tests
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index dfc3e58..d5b3372 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -269,24 +269,10 @@
         return false;
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    err = sc->setLayer(0x7FFFFFFF);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
-        return false;
-    }
-    err = sc->setMatrix(scale, 0.0f, 0.0f, scale);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err);
-        return false;
-    }
-
-    err = sc->show();
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
-        return false;
-    }
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
+            .setMatrix(sc, scale, 0.0f, 0.0f, scale)
+            .show(sc)
+            .apply();
 
     sp<ANativeWindow> anw = sc->getSurface();
     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index ec1e543..3d7cac0 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -284,7 +284,6 @@
 public:
 
     Layer() :
-        mFirstFrame(true),
         mGLHelper(NULL),
         mSurface(EGL_NO_SURFACE) {
     }
@@ -358,8 +357,6 @@
     }
 
 private:
-    bool mFirstFrame;
-
     LayerDesc mDesc;
 
     GLHelper* mGLHelper;
@@ -389,7 +386,6 @@
         ATRACE_CALL();
 
         bool result;
-        EGLint resulte;
 
         float scaleFactor = float(mDesc.runHeights[mInstance]) /
             float(mDesc.height);
@@ -465,7 +461,6 @@
         ATRACE_CALL();
 
         bool result;
-        status_t err;
 
         resetColorGenerator();
 
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 33db6db..94c3102 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -4,6 +4,11 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wextra",
+
+        "-Wunreachable-code",
+        "-Wunreachable-code-break",
+        "-Wunreachable-code-return",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -12,11 +17,15 @@
         "dexopt.cpp",
         "globals.cpp",
         "utils.cpp",
-        "binder/android/os/IInstalld.aidl",
+        ":installd_aidl",
+    ],
+    header_libs: [
+        "dex2oat_headers",
     ],
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "liblog",
         "liblogwrap",
@@ -25,6 +34,17 @@
     ],
 
     clang: true,
+
+    tidy: true,
+    tidy_checks: [
+        "-*",
+        "clang-analyzer-security*",
+        "cert-*",
+        "-cert-err58-cpp",
+    ],
+    tidy_flags: [
+        "-warnings-as-errors=clang-analyzer-security*,cert-*"
+    ],
 }
 
 //
@@ -72,4 +92,35 @@
     ],
 }
 
+filegroup {
+    name: "installd_aidl",
+    srcs: [
+        "binder/android/os/IInstalld.aidl",
+    ],
+}
+
+//
+// Static library for otapreopt used in testing
+//
+cc_library_static {
+    name: "libotapreoptparameters",
+    cflags: [
+        "-Wall",
+        "-Werror"
+    ],
+    clang: true,
+
+    srcs: [
+        "otapreopt_parameters.cpp"],
+
+    export_include_dirs: ["."],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 1d21b3c..a4f95da 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -23,10 +23,11 @@
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
 
-LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
+LOCAL_SRC_FILES := otapreopt.cpp otapreopt_parameters.cpp globals.cpp utils.cpp dexopt.cpp
 LOCAL_HEADER_LIBRARIES := dex2oat_headers
 LOCAL_SHARED_LIBRARIES := \
     libbase \
+    libcrypto \
     libcutils \
     liblog \
     liblogwrap \
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index 3eb39b9..ea0cd9e 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -60,7 +60,7 @@
 
     ATRACE_BEGIN("loadStats tree");
     cacheUsed = 0;
-    for (auto path : mDataPaths) {
+    for (const auto& path : mDataPaths) {
         auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
         auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
         calculate_tree_size(cachePath, &cacheUsed);
@@ -170,7 +170,7 @@
     items.clear();
 
     ATRACE_BEGIN("loadItems");
-    for (auto path : mDataPaths) {
+    for (const auto& path : mDataPaths) {
         loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
         loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
     }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 8a79ee1..860a68b 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,17 +18,21 @@
 
 #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
 
+#include <algorithm>
 #include <errno.h>
-#include <inttypes.h>
 #include <fstream>
 #include <fts.h>
+#include <functional>
+#include <inttypes.h>
 #include <regex>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
 #include <sys/file.h>
-#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/quota.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/types.h>
@@ -37,9 +41,11 @@
 #include <unistd.h>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <cutils/ashmem.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
@@ -71,6 +77,7 @@
 
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
+static constexpr const char* kPropHasReserved = "vold.has_reserved";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -82,6 +89,12 @@
 static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
 static constexpr const char* IDMAP_SUFFIX = "@idmap";
 
+// fsverity assumes the page size is always 4096. If not, the feature can not be
+// enabled.
+static constexpr int kVerityPageSize = 4096;
+static constexpr size_t kSha256Size = 32;
+static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
+
 // NOTE: keep in sync with Installer
 static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
 static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
@@ -100,6 +113,7 @@
 }
 
 static binder::Status exception(uint32_t code, const std::string& msg) {
+    LOG(ERROR) << msg << " (" << code << ")";
     return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
 }
 
@@ -158,6 +172,35 @@
     }
 }
 
+binder::Status checkArgumentPath(const std::string& path) {
+    if (path.empty()) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path");
+    }
+    if (path[0] != '/') {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("Path %s is relative", path.c_str()));
+    }
+    if ((path + '/').find("/../") != std::string::npos) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("Path %s is shady", path.c_str()));
+    }
+    for (const char& c : path) {
+        if (c == '\0' || c == '\n') {
+            return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                    StringPrintf("Path %s is malformed", path.c_str()));
+        }
+    }
+    return ok();
+}
+
+binder::Status checkArgumentPath(const std::unique_ptr<std::string>& path) {
+    if (path) {
+        return checkArgumentPath(*path);
+    } else {
+        return ok();
+    }
+}
+
 #define ENFORCE_UID(uid) {                                  \
     binder::Status status = checkUid((uid));                \
     if (!status.isOk()) {                                   \
@@ -180,6 +223,19 @@
     }                                                       \
 }
 
+#define CHECK_ARGUMENT_PATH(path) {                         \
+    binder::Status status = checkArgumentPath((path));      \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}
+
+#define ASSERT_PAGE_SIZE_4K() {                             \
+    if (getpagesize() != kVerityPageSize) {                 \
+        return error("FSVerity only supports 4K pages");     \
+    }                                                       \
+}
+
 }  // namespace
 
 status_t InstalldNativeService::start() {
@@ -300,8 +356,11 @@
  * Ensure that we have a hard-limit quota to protect against abusive apps;
  * they should never use more than 90% of blocks or 50% of inodes.
  */
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
-        uid_t uid) {
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
+        const std::string& device, uid_t uid) {
+    // Skip when reserved blocks are protecting us against abusive apps
+    if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
+    // Skip when device no quotas present
     if (device.empty()) return 0;
 
     struct dqblk dq;
@@ -342,6 +401,49 @@
 #endif
 }
 
+static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
+    if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
+        return true;
+    }
+
+    int32_t uid = multiuser_get_uid(userId, appId);
+    int shared_app_gid = multiuser_get_shared_gid(userId, appId);
+    if (shared_app_gid == -1) {
+        // TODO(calin): this should no longer be possible but do not continue if we don't get
+        // a valid shared gid.
+        PLOG(WARNING) << "Invalid shared_app_gid for " << packageName;
+        return true;
+    }
+
+    const std::string profile_dir =
+            create_primary_current_profile_package_dir_path(userId, packageName);
+    // read-write-execute only for the app user.
+    if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << profile_dir;
+        return false;
+    }
+
+    const std::string ref_profile_path =
+            create_primary_reference_profile_package_dir_path(packageName);
+
+    // Prepare the reference profile directory. Note that we use the non strict version of
+    // fs_prepare_dir. This will fix the permission and the ownership to the correct values.
+    // This is particularly important given that in O there were some fixes for how the
+    // shared_app_gid is computed.
+    //
+    // Note that by the time we get here we know that we are using a correct uid (otherwise
+    // prepare_app_dir and the above fs_prepare_file_strict which check the uid). So we
+    // are sure that the gid being used belongs to the owning app and not someone else.
+    //
+    // dex2oat/profman runs under the shared app gid and it needs to read/write reference profiles.
+    if (fs_prepare_dir(ref_profile_path.c_str(), 0770, AID_SYSTEM, shared_app_gid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
+        return false;
+    }
+
+    return true;
+}
+
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -417,28 +519,8 @@
             return error("Failed to set hard quota " + path);
         }
 
-        if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
-            const std::string profile_dir =
-                    create_primary_current_profile_package_dir_path(userId, pkgname);
-            // read-write-execute only for the app user.
-            if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
-                return error("Failed to prepare " + profile_dir);
-            }
-            const std::string profile_file = create_current_profile_path(userId, pkgname,
-                    /*is_secondary_dex*/false);
-            // read-write only for the app user.
-            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
-                return error("Failed to prepare " + profile_file);
-            }
-            const std::string ref_profile_path =
-                    create_primary_reference_profile_package_dir_path(pkgname);
-            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
-            // profiles.
-            int shared_app_gid = multiuser_get_shared_gid(0, appId);
-            if ((shared_app_gid != -1) && fs_prepare_dir_strict(
-                    ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
-                return error("Failed to prepare " + ref_profile_path);
-            }
+        if (!prepare_app_profile_dir(packageName, appId, userId)) {
+            return error("Failed to prepare profiles for " + packageName);
         }
     }
     return ok();
@@ -489,16 +571,17 @@
 }
 
 
-binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
+binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName,
+        const std::string& profileName) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     binder::Status res = ok();
-    if (!clear_primary_reference_profile(packageName)) {
+    if (!clear_primary_reference_profile(packageName, profileName)) {
         res = error("Failed to clear reference profile for " + packageName);
     }
-    if (!clear_primary_current_profiles(packageName)) {
+    if (!clear_primary_current_profiles(packageName, profileName)) {
         res = error("Failed to clear current profiles for " + packageName);
     }
     return res;
@@ -525,6 +608,9 @@
         if (access(path.c_str(), F_OK) == 0) {
             if (delete_dir_contents(path) != 0) {
                 res = error("Failed to delete contents of " + path);
+            } else if ((flags & (FLAG_CLEAR_CACHE_ONLY | FLAG_CLEAR_CODE_CACHE_ONLY)) == 0) {
+                remove_path_xattr(path, kXattrInodeCache);
+                remove_path_xattr(path, kXattrInodeCodeCache);
             }
         }
     }
@@ -545,11 +631,6 @@
                 res = error("Failed to delete contents of " + path);
             }
         }
-        if (!only_cache) {
-            if (!clear_primary_current_profile(packageName, userId)) {
-                res = error("Failed to clear current profile for " + packageName);
-            }
-        }
     }
     return res;
 }
@@ -711,6 +792,9 @@
                     // Ignore all other GID transitions, since they're kinda shady
                     LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
                             << " instead of " << expected;
+                    if (!(flags & FLAG_FORCE)) {
+                        fts_set(fts, p, FTS_SKIP);
+                    }
                 }
             }
         }
@@ -1093,6 +1177,7 @@
 binder::Status InstalldNativeService::rmdex(const std::string& codePath,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(codePath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     char dex_path[PKG_PATH_MAX];
@@ -1349,9 +1434,12 @@
         const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
-    for (auto packageName : packageNames) {
+    for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
+    for (const auto& codePath : codePaths) {
+        CHECK_ARGUMENT_PATH(codePath);
+    }
     // NOTE: Locking is relaxed on this method, since it's limited to
     // read-only measurements without mutation.
 
@@ -1388,7 +1476,7 @@
     }
 
     ATRACE_BEGIN("obb");
-    for (auto packageName : packageNames) {
+    for (const auto& packageName : packageNames) {
         auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
@@ -1396,7 +1484,7 @@
 
     if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
         ATRACE_BEGIN("code");
-        for (auto codePath : codePaths) {
+        for (const auto& codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize, -1,
                     multiuser_get_shared_gid(0, appId));
         }
@@ -1407,7 +1495,7 @@
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
-        for (auto codePath : codePaths) {
+        for (const auto& codePath : codePaths) {
             calculate_tree_size(codePath, &stats.codeSize);
         }
         ATRACE_END();
@@ -1794,64 +1882,101 @@
 // Dumps the contents of a profile file, using pkgname's dex files for pretty
 // printing the result.
 binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
-        const std::string& codePaths, bool* _aidl_return) {
+        const std::string& profileName, const std::string& codePath, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_PATH(codePath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    const char* pkgname = packageName.c_str();
-    const char* code_paths = codePaths.c_str();
-
-    *_aidl_return = dump_profiles(uid, pkgname, code_paths);
+    *_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
     return ok();
 }
 
 // Copy the contents of a system profile over the data profile.
 binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile,
-        int32_t packageUid, const std::string& packageName, bool* _aidl_return) {
+        int32_t packageUid, const std::string& packageName, const std::string& profileName,
+        bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
-    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName);
+    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName, profileName);
     return ok();
 }
 
 // TODO: Consider returning error codes.
 binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
-        bool* _aidl_return) {
+        const std::string& profileName, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    *_aidl_return = analyze_primary_profiles(uid, packageName);
+    *_aidl_return = analyze_primary_profiles(uid, packageName, profileName);
     return ok();
 }
 
+binder::Status InstalldNativeService::createProfileSnapshot(int32_t appId,
+        const std::string& packageName, const std::string& profileName,
+        const std::string& classpath, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    *_aidl_return = create_profile_snapshot(appId, packageName, profileName, classpath);
+    return ok();
+}
+
+binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& packageName,
+        const std::string& profileName) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    std::string snapshot = create_snapshot_profile_path(packageName, profileName);
+    if ((unlink(snapshot.c_str()) != 0) && (errno != ENOENT)) {
+        return error("Failed to destroy profile snapshot for " + packageName + ":" + profileName);
+    }
+    return ok();
+}
+
+static const char* getCStr(const std::unique_ptr<std::string>& data,
+        const char* default_value = nullptr) {
+    return data == nullptr ? default_value : data->c_str();
+}
 binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
         const std::unique_ptr<std::string>& classLoaderContext,
-        const std::unique_ptr<std::string>& seInfo, bool downgrade) {
+        const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
+        const std::unique_ptr<std::string>& profileName,
+        const std::unique_ptr<std::string>& dexMetadataPath,
+        const std::unique_ptr<std::string>& compilationReason) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    CHECK_ARGUMENT_PATH(apkPath);
     if (packageName && *packageName != "*") {
         CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
     }
+    CHECK_ARGUMENT_PATH(outputPath);
+    CHECK_ARGUMENT_PATH(dexMetadataPath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
-    const char* pkgname = packageName ? packageName->c_str() : "*";
+    const char* pkgname = getCStr(packageName, "*");
     const char* instruction_set = instructionSet.c_str();
-    const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+    const char* oat_dir = getCStr(outputPath);
     const char* compiler_filter = compilerFilter.c_str();
-    const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
-    const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr;
-    const char* se_info = seInfo ? seInfo->c_str() : nullptr;
+    const char* volume_uuid = getCStr(uuid);
+    const char* class_loader_context = getCStr(classLoaderContext);
+    const char* se_info = getCStr(seInfo);
+    const char* profile_name = getCStr(profileName);
+    const char* dm_path = getCStr(dexMetadataPath);
+    const char* compilation_reason = getCStr(compilationReason);
+    std::string error_msg;
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade);
-    return res ? error(res, "Failed to dexopt") : ok();
+            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+    return res ? error(res, error_msg) : ok();
 }
 
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
@@ -1863,7 +1988,7 @@
     char boot_marker_path[PKG_PATH_MAX];
     sprintf(boot_marker_path,
           "%s/%s/%s/.booting",
-          android_data_dir.path,
+          android_data_dir.c_str(),
           DALVIK_CACHE,
           instruction_set);
 
@@ -1874,33 +1999,13 @@
     return ok();
 }
 
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
-        struct stat* statbuf)
-{
-    while (path[basepos] != 0) {
-        if (path[basepos] == '/') {
-            path[basepos] = 0;
-            if (lstat(path, statbuf) < 0) {
-                ALOGV("Making directory: %s\n", path);
-                if (mkdir(path, mode) == 0) {
-                    chown(path, uid, gid);
-                } else {
-                    ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
-                }
-            }
-            path[basepos] = '/';
-            basepos++;
-        }
-        basepos++;
-    }
-}
-
 binder::Status InstalldNativeService::linkNativeLibraryDirectory(
         const std::unique_ptr<std::string>& uuid, const std::string& packageName,
         const std::string& nativeLibPath32, int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_PATH(nativeLibPath32);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
@@ -2068,6 +2173,8 @@
 binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
         const std::string& overlayApkPath, int32_t uid) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(targetApkPath);
+    CHECK_ARGUMENT_PATH(overlayApkPath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* target_apk = targetApkPath.c_str();
@@ -2153,6 +2260,10 @@
 }
 
 binder::Status InstalldNativeService::removeIdmap(const std::string& overlayApkPath) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(overlayApkPath);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
     const char* overlay_apk = overlayApkPath.c_str();
     char idmap_path[PATH_MAX];
 
@@ -2203,6 +2314,7 @@
 binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
         const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(oatDir);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* oat_dir = oatDir.c_str();
@@ -2227,6 +2339,7 @@
 
 binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(packageDir);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     if (validate_apk_path(packageDir.c_str())) {
@@ -2241,6 +2354,8 @@
 binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
         const std::string& fromBase, const std::string& toBase) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(fromBase);
+    CHECK_ARGUMENT_PATH(toBase);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* relative_path = relativePath.c_str();
@@ -2269,6 +2384,8 @@
 binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
         const std::string& instructionSet, const std::string& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(apkPath);
+    CHECK_ARGUMENT_PATH(outputPath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
@@ -2282,6 +2399,8 @@
 binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
         const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(apkPath);
+    CHECK_ARGUMENT_PATH(outputPath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* apk_path = apkPath.c_str();
@@ -2292,6 +2411,142 @@
     return res ? ok() : error();
 }
 
+// This kernel feature is experimental.
+// TODO: remove local definition once upstreamed
+#ifndef FS_IOC_ENABLE_VERITY
+
+#define FS_IOC_ENABLE_VERITY           _IO('f', 133)
+#define FS_IOC_SET_VERITY_MEASUREMENT  _IOW('f', 134, struct fsverity_measurement)
+
+#define FS_VERITY_ALG_SHA256           1
+
+struct fsverity_measurement {
+    __u16 digest_algorithm;
+    __u16 digest_size;
+    __u32 reserved1;
+    __u64 reserved2[3];
+    __u8 digest[];
+};
+
+#endif
+
+binder::Status InstalldNativeService::installApkVerity(const std::string& filePath,
+        const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(filePath);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
+        return ok();
+    }
+#ifndef NDEBUG
+    ASSERT_PAGE_SIZE_4K();
+#endif
+    // TODO: also check fsverity support in the current file system if compiled with DEBUG.
+    // TODO: change ashmem to some temporary file to support huge apk.
+    if (!ashmem_valid(verityInputAshmem.get())) {
+        return error("FD is not an ashmem");
+    }
+
+    // 1. Seek to the next page boundary beyond the end of the file.
+    ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY));
+    if (wfd.get() < 0) {
+        return error("Failed to open " + filePath);
+    }
+    struct stat st;
+    if (fstat(wfd.get(), &st) < 0) {
+        return error("Failed to stat " + filePath);
+    }
+    // fsverity starts from the block boundary.
+    off_t padding = kVerityPageSize - st.st_size % kVerityPageSize;
+    if (padding == kVerityPageSize) {
+        padding = 0;
+    }
+    if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) {
+        return error("Failed to lseek " + filePath);
+    }
+
+    // 2. Write everything in the ashmem to the file.  Note that allocated
+    //    ashmem size is multiple of page size, which is different from the
+    //    actual content size.
+    int shmSize = ashmem_get_size_region(verityInputAshmem.get());
+    if (shmSize < 0) {
+        return error("Failed to get ashmem size: " + std::to_string(shmSize));
+    }
+    if (contentSize < 0) {
+        return error("Invalid content size: " + std::to_string(contentSize));
+    }
+    if (contentSize > shmSize) {
+        return error("Content size overflow: " + std::to_string(contentSize) + " > " +
+                     std::to_string(shmSize));
+    }
+    auto data = std::unique_ptr<void, std::function<void (void *)>>(
+        mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+        [contentSize] (void* ptr) {
+          if (ptr != MAP_FAILED) {
+            munmap(ptr, contentSize);
+          }
+        });
+
+    if (data.get() == MAP_FAILED) {
+        return error("Failed to mmap the ashmem");
+    }
+    char* cursor = reinterpret_cast<char*>(data.get());
+    int remaining = contentSize;
+    while (remaining > 0) {
+        int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining));
+        if (ret < 0) {
+            return error("Failed to write to " + filePath + " (" + std::to_string(remaining) +
+                         + "/" + std::to_string(contentSize) + ")");
+        }
+        cursor += ret;
+        remaining -= ret;
+    }
+    wfd.reset();
+
+    // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable.
+    ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY));
+    if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
+        return error("Failed to enable fsverity on " + filePath);
+    }
+    return ok();
+}
+
+binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::string& filePath,
+        const std::vector<uint8_t>& expectedHash) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PATH(filePath);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
+        return ok();
+    }
+    // TODO: also check fsverity support in the current file system if compiled with DEBUG.
+    if (expectedHash.size() != kSha256Size) {
+        return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " +
+                     std::to_string(expectedHash.size()));
+    }
+
+    ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
+    if (fd.get() < 0) {
+        return error("Failed to open " + filePath + ": " + strerror(errno));
+    }
+
+    unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size;
+    std::vector<char> buffer(buffer_size, 0);
+
+    fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data());
+    config->digest_algorithm = FS_VERITY_ALG_SHA256;
+    config->digest_size = kSha256Size;
+    memcpy(config->digest, expectedHash.data(), kSha256Size);
+    if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) {
+        // This includes an expected failure case with no FSVerity setup. It normally happens when
+        // the apk does not contains the Merkle tree root hash.
+        return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
+    }
+    return ok();  // hashes match
+}
+
 binder::Status InstalldNativeService::reconcileSecondaryDexFile(
         const std::string& dexPath, const std::string& packageName, int32_t uid,
         const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
@@ -2299,13 +2554,31 @@
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
-
+    CHECK_ARGUMENT_PATH(dexPath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
+
     bool result = android::installd::reconcile_secondary_dex_file(
             dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return);
     return result ? ok() : error();
 }
 
+binder::Status InstalldNativeService::hashSecondaryDexFile(
+        const std::string& dexPath, const std::string& packageName, int32_t uid,
+        const std::unique_ptr<std::string>& volumeUuid, int32_t storageFlag,
+        std::vector<uint8_t>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_PATH(dexPath);
+
+    // mLock is not taken here since we will never modify the file system.
+    // If a file is modified just as we are reading it this may result in an
+    // anomalous hash, but that's ok.
+    bool result = android::installd::hash_secondary_dex_file(
+        dexPath, packageName, uid, volumeUuid, storageFlag, _aidl_return);
+    return result ? ok() : error();
+}
+
 binder::Status InstalldNativeService::invalidateMounts() {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -2342,14 +2615,18 @@
                 mQuotaReverseMounts[target] = source;
 
                 // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
-                // need to kick it again to enable DQUOT_LIMITS_ENABLED.
-                if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
-                        && errno != EBUSY) {
-                    PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
-                }
-                if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
-                        && errno != EBUSY) {
-                    PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+                // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
+                // only need hard limits enabled when we're not being protected
+                // by reserved blocks.
+                if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
+                    if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
+                            nullptr) != 0 && errno != EBUSY) {
+                        PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+                    }
+                    if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
+                            nullptr) != 0 && errno != EBUSY) {
+                        PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+                    }
                 }
             }
         }
@@ -2384,5 +2661,18 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::prepareAppProfile(const std::string& packageName,
+        int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
+        const std::unique_ptr<std::string>& dexMetadata, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    CHECK_ARGUMENT_PATH(codePath);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    *_aidl_return = prepare_app_profile(packageName, userId, appId, profileName, codePath,
+        dexMetadata);
+    return ok();
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index c8db3df..cebd3f9 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -84,18 +84,28 @@
             int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
             const std::unique_ptr<std::string>& classLoaderContext,
-            const std::unique_ptr<std::string>& seInfo, bool downgrade);
+            const std::unique_ptr<std::string>& seInfo, bool downgrade,
+            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName,
+            const std::unique_ptr<std::string>& dexMetadataPath,
+            const std::unique_ptr<std::string>& compilationReason);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
-    binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
+    binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
+            const std::string& profileName, bool* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
-            const std::string& codePaths, bool* _aidl_return);
+            const std::string& profileName, const std::string& codePath, bool* _aidl_return);
     binder::Status copySystemProfile(const std::string& systemProfile,
-            int32_t uid, const std::string& packageName, bool* _aidl_return);
-    binder::Status clearAppProfiles(const std::string& packageName);
+            int32_t uid, const std::string& packageName, const std::string& profileName,
+            bool* _aidl_return);
+    binder::Status clearAppProfiles(const std::string& packageName, const std::string& profileName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
+    binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
+            const std::string& profileName, const std::string& classpath, bool* _aidl_return);
+    binder::Status destroyProfileSnapshot(const std::string& packageName,
+            const std::string& profileName);
+
     binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
             int32_t uid);
     binder::Status removeIdmap(const std::string& overlayApkPath);
@@ -112,14 +122,26 @@
             const std::string& outputPath);
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
             const std::unique_ptr<std::string>& outputPath);
+    binder::Status installApkVerity(const std::string& filePath,
+            const ::android::base::unique_fd& verityInput, int32_t contentSize);
+    binder::Status assertFsverityRootHashMatches(const std::string& filePath,
+            const std::vector<uint8_t>& expectedHash);
     binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
         const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
         const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
+    binder::Status hashSecondaryDexFile(const std::string& dexPath,
+        const std::string& packageName, int32_t uid, const std::unique_ptr<std::string>& volumeUuid,
+        int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
 
     binder::Status invalidateMounts();
     binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
             bool* _aidl_return);
 
+    binder::Status prepareAppProfile(const std::string& packageName,
+            int32_t userId, int32_t appId, const std::string& profileName,
+            const std::string& codePath, const std::unique_ptr<std::string>& dexMetadata,
+            bool* _aidl_return);
+
 private:
     std::recursive_mutex mLock;
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 452a2b1..91e20b7 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,17 +51,25 @@
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
-            @nullable @utf8InCpp String seInfo, boolean downgrade);
+            @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion,
+            @nullable @utf8InCpp String profileName,
+            @nullable @utf8InCpp String dexMetadataPath,
+            @nullable @utf8InCpp String compilationReason);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
-    boolean mergeProfiles(int uid, @utf8InCpp String packageName);
-    boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+    boolean mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
+    boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String  profileName,
+            @utf8InCpp String codePath);
     boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
-            @utf8InCpp String packageName);
-    void clearAppProfiles(@utf8InCpp String packageName);
+            @utf8InCpp String packageName, @utf8InCpp String profileName);
+    void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
+    boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
+            @utf8InCpp String profileName, @utf8InCpp String classpath);
+    void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName);
+
     void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
     void removeIdmap(@utf8InCpp String overlayApkPath);
     void rmPackageDir(@utf8InCpp String packageDir);
@@ -77,11 +85,21 @@
             @utf8InCpp String outputPath);
     void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @nullable @utf8InCpp String outputPath);
+    void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput,
+            int contentSize);
+    void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash);
 
     boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
         int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
         int storage_flag);
 
+    byte[] hashSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
+        int uid, @nullable @utf8InCpp String volumeUuid, int storageFlag);
+
     void invalidateMounts();
     boolean isQuotaSupported(@nullable @utf8InCpp String uuid);
+
+    boolean prepareAppProfile(@utf8InCpp String packageName,
+        int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
+        @nullable @utf8InCpp String dexMetadata);
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f29da17..9615a75 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -15,6 +15,7 @@
  */
 #define LOG_TAG "installed"
 
+#include <array>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
@@ -27,30 +28,51 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <iomanip>
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
+#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
+#include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "dexopt_return_codes.h"
+#include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
 #include "utils.h"
 
-using android::base::StringPrintf;
 using android::base::EndsWith;
+using android::base::ReadFully;
+using android::base::StringPrintf;
+using android::base::WriteFully;
 using android::base::unique_fd;
 
 namespace android {
 namespace installd {
 
+// Should minidebug info be included in compiled artifacts? Even if this value is
+// "true," usage might still be conditional to other constraints, e.g., system
+// property overrides.
+static constexpr bool kEnableMinidebugInfo = true;
+
+static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
+static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
+static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
+static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
+
+
 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
 struct FreeDelete {
   // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
@@ -67,6 +89,14 @@
     return unique_fd(-1);
 }
 
+static bool is_debug_runtime() {
+    return android::base::GetProperty("persist.sys.dalvik.vm.lib.2", "") == "libartd.so";
+}
+
+static bool is_debuggable_build() {
+    return android::base::GetBoolProperty("ro.debuggable", false);
+}
+
 static bool clear_profile(const std::string& profile) {
     unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
     if (ufd.get() < 0) {
@@ -112,37 +142,43 @@
 }
 
 // Clear the reference profile for the given location.
-// The location is the package name for primary apks or the dex path for secondary dex files.
-static bool clear_reference_profile(const std::string& location, bool is_secondary_dex) {
-    return clear_profile(create_reference_profile_path(location, is_secondary_dex));
+// The location is the profile name for primary apks or the dex path for secondary dex files.
+static bool clear_reference_profile(const std::string& package_name, const std::string& location,
+        bool is_secondary_dex) {
+    return clear_profile(create_reference_profile_path(package_name, location, is_secondary_dex));
 }
 
 // Clear the reference profile for the given location.
-// The location is the package name for primary apks or the dex path for secondary dex files.
-static bool clear_current_profile(const std::string& pkgname, userid_t user,
-        bool is_secondary_dex) {
-    return clear_profile(create_current_profile_path(user, pkgname, is_secondary_dex));
+// The location is the profile name for primary apks or the dex path for secondary dex files.
+static bool clear_current_profile(const std::string& package_name, const std::string& location,
+        userid_t user, bool is_secondary_dex) {
+    return clear_profile(create_current_profile_path(user, package_name, location,
+            is_secondary_dex));
 }
 
 // Clear the reference profile for the primary apk of the given package.
-bool clear_primary_reference_profile(const std::string& pkgname) {
-    return clear_reference_profile(pkgname, /*is_secondary_dex*/false);
+// The location is the profile name for primary apks or the dex path for secondary dex files.
+bool clear_primary_reference_profile(const std::string& package_name,
+        const std::string& location) {
+    return clear_reference_profile(package_name, location, /*is_secondary_dex*/false);
 }
 
 // Clear all current profile for the primary apk of the given package.
-bool clear_primary_current_profiles(const std::string& pkgname) {
+// The location is the profile name for primary apks or the dex path for secondary dex files.
+bool clear_primary_current_profiles(const std::string& package_name, const std::string& location) {
     bool success = true;
     // For secondary dex files, we don't really need the user but we use it for sanity checks.
     std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
     for (auto user : users) {
-        success &= clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+        success &= clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
     }
     return success;
 }
 
 // Clear the current profile for the primary apk of the given package and user.
-bool clear_primary_current_profile(const std::string& pkgname, userid_t user) {
-    return clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+bool clear_primary_current_profile(const std::string& package_name, const std::string& location,
+        userid_t user) {
+    return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
 }
 
 static int split_count(const char *str)
@@ -151,7 +187,7 @@
   int count = 0;
   char buf[kPropertyValueMax];
 
-  strncpy(buf, str, sizeof(buf));
+  strlcpy(buf, str, sizeof(buf));
   char *pBuf = buf;
 
   while(strtok_r(pBuf, " ", &ctx) != NULL) {
@@ -188,16 +224,19 @@
     }
 }
 
+[[ noreturn ]]
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, int profile_fd, const char* class_loader_context) {
+        bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
+        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
+        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
+        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
+                   << MAX_INSTRUCTION_SET_LEN;
+        exit(DexoptReturnCodes::kInstructionSetLength);
     }
 
     // Get the relative path to the input file.
@@ -267,7 +306,20 @@
                 dex2oat_large_app_threshold);
     }
 
-    static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
+    // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+    const char* dex2oat_bin = "/system/bin/dex2oat";
+    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+    // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+    bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+    if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
+        if (access(kDex2oatDebugPath, X_OK) == 0) {
+            dex2oat_bin = kDex2oatDebugPath;
+        }
+    }
+
+    bool generate_minidebug_info = kEnableMinidebugInfo &&
+            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
+                                           kMinidebugInfoSystemPropertyDefault);
 
     static const char* RUNTIME_ARG = "--runtime-arg";
 
@@ -292,6 +344,7 @@
     bool have_dex2oat_image_fd = false;
     char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
     size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
+    char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
     char class_loader_context_arg[class_loader_context_size];
     if (class_loader_context != nullptr) {
         snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
@@ -322,12 +375,14 @@
     if (have_dex2oat_Xmx_flag) {
         sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
     }
+    sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
 
     // Compute compiler filter.
 
     bool have_dex2oat_compiler_filter_flag = false;
     if (skip_compilation) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
+                sizeof(dex2oat_compiler_filter_arg));
         have_dex2oat_compiler_filter_flag = true;
         have_dex2oat_relocation_skip_flag = true;
     } else if (compiler_filter != nullptr) {
@@ -375,8 +430,17 @@
         sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
     }
 
+    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
 
-    ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);
+    std::string compilation_reason_arg = compilation_reason == nullptr
+            ? ""
+            : std::string("--compilation-reason=") + compilation_reason;
+
+    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+    // Disable cdex if update input vdex is true since this combination of options is not
+    // supported.
+    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
 
     const char* argv[9  // program name, mandatory arguments and the final NULL
                      + (have_dex2oat_isa_variant ? 1 : 0)
@@ -395,9 +459,15 @@
                      + (profile_fd == -1 ? 0 : 1)
                      + (class_loader_context != nullptr ? 1 : 0)
                      + (has_base_dir ? 1 : 0)
-                     + (have_dex2oat_large_app_threshold ? 1 : 0)];
+                     + (have_dex2oat_large_app_threshold ? 1 : 0)
+                     + (disable_cdex ? 1 : 0)
+                     + (generate_minidebug_info ? 1 : 0)
+                     + (target_sdk_version != 0 ? 2 : 0)
+                     + (enable_hidden_api_checks ? 2 : 0)
+                     + (dex_metadata_fd > -1 ? 1 : 0)
+                     + (compilation_reason != nullptr ? 1 : 0)];
     int i = 0;
-    argv[i++] = DEX2OAT_BIN;
+    argv[i++] = dex2oat_bin;
     argv[i++] = zip_fd_arg;
     argv[i++] = zip_location_arg;
     argv[i++] = input_vdex_fd_arg;
@@ -459,12 +529,34 @@
     if (class_loader_context != nullptr) {
         argv[i++] = class_loader_context_arg;
     }
+    if (generate_minidebug_info) {
+        argv[i++] = kMinidebugDex2oatFlag;
+    }
+    if (disable_cdex) {
+        argv[i++] = kDisableCompactDexFlag;
+    }
+    if (target_sdk_version != 0) {
+        argv[i++] = RUNTIME_ARG;
+        argv[i++] = target_sdk_version_arg;
+    }
+    if (enable_hidden_api_checks) {
+        argv[i++] = RUNTIME_ARG;
+        argv[i++] = "-Xhidden-api-checks";
+    }
 
+    if (dex_metadata_fd > -1) {
+        argv[i++] = dex_metadata_fd_arg.c_str();
+    }
+
+    if(compilation_reason != nullptr) {
+        argv[i++] = compilation_reason_arg.c_str();
+    }
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
-    execv(DEX2OAT_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
+    execv(dex2oat_bin, (char * const *)argv);
+    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+    exit(DexoptReturnCodes::kDex2oatExec);
 }
 
 /*
@@ -516,24 +608,22 @@
 static void SetDex2OatScheduling(bool set_to_bg) {
     if (set_to_bg) {
         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
+            PLOG(ERROR) << "set_sched_policy failed";
+            exit(DexoptReturnCodes::kSetSchedPolicy);
         }
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
+            PLOG(ERROR) << "setpriority failed";
+            exit(DexoptReturnCodes::kSetPriority);
         }
     }
 }
 
-static bool create_profile(int uid, const std::string& profile) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
     if (fd.get() < 0) {
-        if (errno == EEXIST) {
-            return true;
-        } else {
+        if (errno != EEXIST) {
             PLOG(ERROR) << "Failed to create profile " << profile;
-            return false;
+            return invalid_unique_fd();
         }
     }
     // Profiles should belong to the app; make sure of that by giving ownership to
@@ -541,27 +631,26 @@
     // since dex2oat/profman will fail with SElinux denials.
     if (fchown(fd.get(), uid, uid) < 0) {
         PLOG(ERROR) << "Could not chwon profile " << profile;
-        return false;
+        return invalid_unique_fd();
     }
-    return true;
+    return fd;
 }
 
-static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
-    // Check if we need to open the profile for a read-write operation. If so, we
-    // might need to create the profile since the file might not be there. Reference
-    // profiles are created on the fly so they might not exist beforehand.
-    if (read_write) {
-        if (!create_profile(uid, profile)) {
-            return invalid_unique_fd();
-        }
-    }
-    int flags = read_write ? O_RDWR : O_RDONLY;
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
     // Do not follow symlinks when opening a profile:
     //   - primary profiles should not contain symlinks in their paths
     //   - secondary dex paths should have been already resolved and validated
     flags |= O_NOFOLLOW;
 
-    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+    // Check if we need to create the profile
+    // Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
+    unique_fd fd;
+    if ((flags & O_CREAT) != 0) {
+        fd = create_profile(uid, profile, flags);
+    } else {
+        fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+    }
+
     if (fd.get() < 0) {
         if (errno != ENOENT) {
             // Profiles might be missing for various reasons. For example, in a
@@ -578,23 +667,31 @@
     return fd;
 }
 
-static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
-        bool is_secondary_dex) {
-    std::string profile = create_current_profile_path(user, location, is_secondary_dex);
-    return open_profile(uid, profile, /*read_write*/false);
+static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& package_name,
+        const std::string& location, bool is_secondary_dex) {
+    std::string profile = create_current_profile_path(user, package_name, location,
+            is_secondary_dex);
+    return open_profile(uid, profile, O_RDONLY);
 }
 
-static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
-        bool is_secondary_dex) {
-    std::string profile = create_reference_profile_path(location, is_secondary_dex);
-    return open_profile(uid, profile, read_write);
+static unique_fd open_reference_profile(uid_t uid, const std::string& package_name,
+        const std::string& location, bool read_write, bool is_secondary_dex) {
+    std::string profile = create_reference_profile_path(package_name, location, is_secondary_dex);
+    return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
 }
 
-static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
+static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
+        const std::string& location) {
+    std::string profile = create_snapshot_profile_path(package_name, location);
+    return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
+}
+
+static void open_profile_files(uid_t uid, const std::string& package_name,
+            const std::string& location, bool is_secondary_dex,
             /*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* reference_profile_fd) {
     // Open the reference profile in read-write mode as profman might need to save the merge.
-    *reference_profile_fd = open_reference_profile(uid, location, /*read_write*/ true,
-            is_secondary_dex);
+    *reference_profile_fd = open_reference_profile(uid, package_name, location,
+            /*read_write*/ true, is_secondary_dex);
 
     // For secondary dex files, we don't really need the user but we use it for sanity checks.
     // Note: the user owning the dex file should be the current user.
@@ -605,7 +702,8 @@
         users = get_known_users(/*volume_uuid*/ nullptr);
     }
     for (auto user : users) {
-        unique_fd profile_fd = open_current_profile(uid, user, location, is_secondary_dex);
+        unique_fd profile_fd = open_current_profile(uid, user, package_name, location,
+                is_secondary_dex);
         // Add to the lists only if both fds are valid.
         if (profile_fd.get() >= 0) {
             profiles_fd->push_back(std::move(profile_fd));
@@ -615,12 +713,12 @@
 
 static void drop_capabilities(uid_t uid) {
     if (setgid(uid) != 0) {
-        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
-        exit(64);
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
     }
     if (setuid(uid) != 0) {
-        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
-        exit(65);
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
     }
     // drop capabilities
     struct __user_cap_header_struct capheader;
@@ -629,8 +727,8 @@
     memset(&capdata, 0, sizeof(capdata));
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     if (capset(&capheader, &capdata[0]) < 0) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(66);
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
     }
 }
 
@@ -640,34 +738,89 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
-        const unique_fd& reference_profile_fd) {
-    static const size_t MAX_INT_LEN = 32;
-    static const char* PROFMAN_BIN = "/system/bin/profman";
+[[ noreturn ]]
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+                        const unique_fd& reference_profile_fd,
+                        const std::vector<unique_fd>* apk_fds,
+                        const std::vector<std::string>* dex_locations,
+                        bool copy_and_update) {
+    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
 
-    std::vector<std::string> profile_args(profiles_fd.size());
-    char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
-    for (size_t k = 0; k < profiles_fd.size(); k++) {
-        sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k].get());
-        profile_args[k].assign(profile_buf);
+    if (copy_and_update) {
+        CHECK_EQ(1u, profile_fds.size());
+        CHECK(apk_fds != nullptr);
+        CHECK_EQ(1u, apk_fds->size());
     }
-    char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
-    sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd.get());
+    std::vector<std::string> profile_args(profile_fds.size());
+    for (size_t k = 0; k < profile_fds.size(); k++) {
+        profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
+    }
+    std::string reference_profile_arg = "--reference-profile-file-fd="
+            + std::to_string(reference_profile_fd.get());
+
+    std::vector<std::string> apk_args;
+    if (apk_fds != nullptr) {
+        for (size_t k = 0; k < apk_fds->size(); k++) {
+            apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+        }
+    }
+
+    std::vector<std::string> dex_location_args;
+    if (dex_locations != nullptr) {
+        for (size_t k = 0; k < dex_locations->size(); k++) {
+            dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+        }
+    }
 
     // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profiles_fd.size()];
+    const char* argv[3 + profile_args.size() + apk_args.size() + (copy_and_update ? 1 : 0)];
     int i = 0;
-    argv[i++] = PROFMAN_BIN;
-    argv[i++] = reference_profile_arg;
+    argv[i++] = profman_bin;
+    argv[i++] = reference_profile_arg.c_str();
     for (size_t k = 0; k < profile_args.size(); k++) {
         argv[i++] = profile_args[k].c_str();
     }
+    for (size_t k = 0; k < apk_args.size(); k++) {
+        argv[i++] = apk_args[k].c_str();
+    }
+    for (size_t k = 0; k < dex_location_args.size(); k++) {
+        argv[i++] = dex_location_args[k].c_str();
+    }
+    if (copy_and_update) {
+        argv[i++] = "--copy-and-update-profile-key";
+    }
+
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
 
-    execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    execv(profman_bin, (char * const *)argv);
+    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
+}
+
+[[ noreturn ]]
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+                              const unique_fd& reference_profile_fd,
+                              const std::vector<unique_fd>* apk_fds = nullptr,
+                              const std::vector<std::string>* dex_locations = nullptr) {
+    run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+            /*copy_and_update*/false);
+}
+
+[[ noreturn ]]
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+                                        unique_fd&& reference_profile_fd,
+                                        unique_fd&& apk_fd,
+                                        const std::string& dex_location) {
+    std::vector<unique_fd> profiles_fd;
+    profiles_fd.push_back(std::move(profile_fd));
+    std::vector<unique_fd> apk_fds;
+    apk_fds.push_back(std::move(apk_fd));
+    std::vector<std::string> dex_locations;
+    dex_locations.push_back(dex_location);
+
+    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
+            /*copy_and_update*/true);
 }
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
@@ -676,10 +829,12 @@
 // worth to recompile the given location.
 // If the return value is true all the current profiles would have been merged into
 // the reference profiles accessible with open_reference_profile().
-static bool analyze_profiles(uid_t uid, const std::string& location, bool is_secondary_dex) {
+static bool analyze_profiles(uid_t uid, const std::string& package_name,
+        const std::string& location, bool is_secondary_dex) {
     std::vector<unique_fd> profiles_fd;
     unique_fd reference_profile_fd;
-    open_profile_files(uid, location, is_secondary_dex, &profiles_fd, &reference_profile_fd);
+    open_profile_files(uid, package_name, location, is_secondary_dex,
+        &profiles_fd, &reference_profile_fd);
     if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
         // Skip profile guided compilation because no profiles were found.
         // Or if the reference profile info couldn't be opened.
@@ -691,7 +846,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
         run_profman_merge(profiles_fd, reference_profile_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -741,13 +895,14 @@
     if (should_clear_current_profiles) {
         if (is_secondary_dex) {
             // For secondary dex files, the owning user is the current user.
-            clear_current_profile(location, multiuser_get_user_id(uid), is_secondary_dex);
+            clear_current_profile(package_name, location, multiuser_get_user_id(uid),
+                    is_secondary_dex);
         } else  {
-            clear_primary_current_profiles(location);
+            clear_primary_current_profiles(package_name, location);
         }
     }
     if (should_clear_reference_profile) {
-        clear_reference_profile(location, is_secondary_dex);
+        clear_reference_profile(package_name, location, is_secondary_dex);
     }
     return need_to_compile;
 }
@@ -758,10 +913,12 @@
 // worth to recompile the package.
 // If the return value is true all the current profiles would have been merged into
 // the reference profiles accessible with open_reference_profile().
-bool analyze_primary_profiles(uid_t uid, const std::string& pkgname) {
-    return analyze_profiles(uid, pkgname, /*is_secondary_dex*/false);
+bool analyze_primary_profiles(uid_t uid, const std::string& package_name,
+        const std::string& profile_name) {
+    return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
+[[ noreturn ]]
 static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
                              const unique_fd& reference_profile_fd,
                              const std::vector<std::string>& dex_locations,
@@ -793,16 +950,18 @@
     argv[i] = NULL;
 
     execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
-bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
+bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
+        const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
     unique_fd reference_profile_fd;
-    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
+    std::string out_file_name = StringPrintf("/data/misc/profman/%s-%s.txt",
+        pkgname.c_str(), profile_name.c_str());
 
-    open_profile_files(uid, pkgname, /*is_secondary_dex*/false,
+    open_profile_files(uid, pkgname, profile_name, /*is_secondary_dex*/false,
             &profile_fds, &reference_profile_fd);
 
     const bool has_reference_profile = (reference_profile_fd.get() != -1);
@@ -816,22 +975,20 @@
     unique_fd output_fd(open(out_file_name.c_str(),
             O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
     if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
-        ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
+        LOG(ERROR) << "installd cannot chmod file for dump_profile" << out_file_name;
         return false;
     }
-    std::vector<std::string> code_full_paths = base::Split(code_paths, ";");
+
     std::vector<std::string> dex_locations;
     std::vector<unique_fd> apk_fds;
-    for (const std::string& code_full_path : code_full_paths) {
-        const char* full_path = code_full_path.c_str();
-        unique_fd apk_fd(open(full_path, O_RDONLY | O_NOFOLLOW));
-        if (apk_fd == -1) {
-            ALOGE("installd cannot open '%s'\n", full_path);
-            return false;
-        }
-        dex_locations.push_back(get_location_from_path(full_path));
-        apk_fds.push_back(std::move(apk_fd));
+    unique_fd apk_fd(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW));
+    if (apk_fd == -1) {
+        PLOG(ERROR) << "installd cannot open " << code_path.c_str();
+        return false;
     }
+    dex_locations.push_back(get_location_from_path(code_path.c_str()));
+    apk_fds.push_back(std::move(apk_fd));
+
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -839,7 +996,6 @@
         drop_capabilities(uid);
         run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
                          apk_fds, output_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -852,10 +1008,11 @@
 }
 
 bool copy_system_profile(const std::string& system_profile,
-        uid_t packageUid, const std::string& data_profile_location) {
+        uid_t packageUid, const std::string& package_name, const std::string& profile_name) {
     unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
     unique_fd out_fd(open_reference_profile(packageUid,
-                     data_profile_location,
+                     package_name,
+                     profile_name,
                      /*read_write*/ true,
                      /*secondary*/ false));
     if (in_fd.get() < 0) {
@@ -863,7 +1020,7 @@
         return false;
     }
     if (out_fd.get() < 0) {
-        PLOG(WARNING) << "Could not open profile " << data_profile_location;
+        PLOG(WARNING) << "Could not open profile " << package_name;
         return false;
     }
 
@@ -876,7 +1033,7 @@
 
         if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             if (errno != EWOULDBLOCK) {
-                PLOG(WARNING) << "Error locking profile " << data_profile_location;
+                PLOG(WARNING) << "Error locking profile " << package_name;
             }
             // This implies that the app owning this profile is running
             // (and has acquired the lock).
@@ -884,13 +1041,13 @@
             // The app never acquires the lock for the reference profiles of primary apks.
             // Only dex2oat from installd will do that. Since installd is single threaded
             // we should not see this case. Nevertheless be prepared for it.
-            PLOG(WARNING) << "Failed to flock " << data_profile_location;
+            PLOG(WARNING) << "Failed to flock " << package_name;
             return false;
         }
 
         bool truncated = ftruncate(out_fd.get(), 0) == 0;
         if (!truncated) {
-            PLOG(WARNING) << "Could not truncate " << data_profile_location;
+            PLOG(WARNING) << "Could not truncate " << package_name;
         }
 
         // Copy over data.
@@ -904,7 +1061,7 @@
             write(out_fd.get(), buffer, bytes);
         }
         if (flock(out_fd.get(), LOCK_UN) != 0) {
-            PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
+            PLOG(WARNING) << "Error unlocking profile " << package_name;
         }
         // Use _exit since we don't want to run the global destructors in the child.
         // b/62597429
@@ -920,7 +1077,7 @@
   if (EndsWith(oat_path, ".dex")) {
     std::string new_path = oat_path;
     new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
-    CHECK(EndsWith(new_path, new_ext.c_str()));
+    CHECK(EndsWith(new_path, new_ext));
     return new_path;
   }
 
@@ -949,14 +1106,6 @@
     return replace_file_extension(oat_path, ".vdex");
 }
 
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
-    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
-        return false;
-    }
-    strcat(file_name, extension);
-    return true;
-}
-
 static int open_output_file(const char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
@@ -1135,8 +1284,8 @@
 };
 
 // (re)Creates the app image if needed.
-Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
-        bool is_public, int uid, bool is_secondary_dex) {
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path,
+        bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) {
 
     // We don't create an image for secondary dex files.
     if (is_secondary_dex) {
@@ -1149,11 +1298,11 @@
         return Dex2oatFileWrapper();
     }
 
-    // Use app images only if it is enabled (by a set image format) and we are compiling
-    // profile-guided (so the app image doesn't conservatively contain all classes).
-    if (!profile_guided) {
-        // In case there is a stale image, remove it now. Ignore any error.
-        unlink(image_path.c_str());
+    // In case there is a stale image, remove it now. Ignore any error.
+    unlink(image_path.c_str());
+
+    // Not enabled, exit.
+    if (!generate_app_image) {
         return Dex2oatFileWrapper();
     }
     char app_image_format[kPropertyValueMax];
@@ -1192,21 +1341,16 @@
     if (!ShouldUseSwapFileForDexopt()) {
         return invalid_unique_fd();
     }
-    // Make sure there really is enough space.
-    char swap_file_name[PKG_PATH_MAX];
-    strcpy(swap_file_name, out_oat_path);
-    if (!add_extension_to_file_name(swap_file_name, ".swap")) {
-        return invalid_unique_fd();
-    }
+    auto swap_file_name = std::string(out_oat_path) + ".swap";
     unique_fd swap_fd(open_output_file(
-            swap_file_name, /*recreate*/true, /*permissions*/0600));
+            swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
     if (swap_fd.get() < 0) {
         // Could not create swap file. Optimistically go on and hope that we can compile
         // without it.
-        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name.c_str());
     } else {
         // Immediately unlink. We don't really want to hit flash.
-        if (unlink(swap_file_name) < 0) {
+        if (unlink(swap_file_name.c_str()) < 0) {
             PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
         }
     }
@@ -1216,26 +1360,49 @@
 // Opens the reference profiles if needed.
 // Note that the reference profile might not exist so it's OK if the fd will be -1.
 Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
-        const std::string& dex_path, bool profile_guided, bool is_public, int uid,
-        bool is_secondary_dex) {
-    // Public apps should not be compiled with profile information ever. Same goes for the special
-    // package '*' used for the system server.
-    if (!profile_guided || is_public || (pkgname[0] == '*')) {
+        const std::string& dex_path, const char* profile_name, bool profile_guided,
+        bool is_public, int uid, bool is_secondary_dex) {
+    // If we are not profile guided compilation, or we are compiling system server
+    // do not bother to open the profiles; we won't be using them.
+    if (!profile_guided || (pkgname[0] == '*')) {
+        return Dex2oatFileWrapper();
+    }
+
+    // If this is a secondary dex path which is public do not open the profile.
+    // We cannot compile public secondary dex paths with profiles. That's because
+    // it will expose how the dex files are used by their owner.
+    //
+    // Note that the PackageManager is responsible to set the is_public flag for
+    // primary apks and we do not check it here. In some cases, e.g. when
+    // compiling with a public profile from the .dm file the PackageManager will
+    // set is_public toghether with the profile guided compilation.
+    if (is_secondary_dex && is_public) {
         return Dex2oatFileWrapper();
     }
 
     // Open reference profile in read only mode as dex2oat does not get write permissions.
-    const std::string location = is_secondary_dex ? dex_path : pkgname;
-    unique_fd ufd = open_reference_profile(uid, location, /*read_write*/false, is_secondary_dex);
-    const auto& cleanup = [location, is_secondary_dex]() {
-        clear_reference_profile(location.c_str(), is_secondary_dex);
+    std::string location;
+    if (is_secondary_dex) {
+        location = dex_path;
+    } else {
+        if (profile_name == nullptr) {
+            // This path is taken for system server re-compilation lunched from ZygoteInit.
+            return Dex2oatFileWrapper();
+        } else {
+            location = profile_name;
+        }
+    }
+    unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false,
+            is_secondary_dex);
+    const auto& cleanup = [pkgname, location, is_secondary_dex]() {
+        clear_reference_profile(pkgname, location, is_secondary_dex);
     };
     return Dex2oatFileWrapper(ufd.release(), cleanup);
 }
 
 // Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
 // out_vdex_wrapper_fd. Returns true for success or false in case of errors.
-bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
         const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
         bool profile_guided, Dex2oatFileWrapper* in_vdex_wrapper_fd,
         Dex2oatFileWrapper* out_vdex_wrapper_fd) {
@@ -1348,6 +1515,39 @@
     return wrapper_fd;
 }
 
+// Creates RDONLY fds for oat and vdex files, if exist.
+// Returns false if it fails to create oat out path for the given apk path.
+// Note that the method returns true even if the files could not be opened.
+bool maybe_open_oat_and_vdex_file(const std::string& apk_path,
+                                  const std::string& oat_dir,
+                                  const std::string& instruction_set,
+                                  bool is_secondary_dex,
+                                  unique_fd* oat_file_fd,
+                                  unique_fd* vdex_file_fd) {
+    char oat_path[PKG_PATH_MAX];
+    if (!create_oat_out_path(apk_path.c_str(),
+                             instruction_set.c_str(),
+                             oat_dir.c_str(),
+                             is_secondary_dex,
+                             oat_path)) {
+        LOG(ERROR) << "Could not create oat out path for "
+                << apk_path << " with oat dir " << oat_dir;
+        return false;
+    }
+    oat_file_fd->reset(open(oat_path, O_RDONLY));
+    if (oat_file_fd->get() < 0) {
+        PLOG(INFO) << "installd cannot open oat file during dexopt" <<  oat_path;
+    }
+
+    std::string vdex_filename = create_vdex_filename(oat_path);
+    vdex_file_fd->reset(open(vdex_filename.c_str(), O_RDONLY));
+    if (vdex_file_fd->get() < 0) {
+        PLOG(INFO) << "installd cannot open vdex file during dexopt" <<  vdex_filename;
+    }
+
+    return true;
+}
+
 // Updates the access times of out_oat_path based on those from apk_path.
 void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
     struct stat input_stat;
@@ -1369,9 +1569,15 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
-        const std::string& compiler_filter, bool profile_was_updated, bool downgrade) {
-    static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
+static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
+        int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
+        bool profile_was_updated, bool downgrade,
+        const char* class_loader_context) {
+    CHECK_GE(zip_fd, 0);
+    const char* dexoptanalyzer_bin =
+            is_debug_runtime()
+                    ? "/system/bin/dexoptanalyzerd"
+                    : "/system/bin/dexoptanalyzer";
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
@@ -1381,36 +1587,56 @@
     }
 
     std::string dex_file_arg = "--dex-file=" + dex_file;
+    std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+    std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+    std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
     std::string isa_arg = "--isa=" + instruction_set;
     std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
     const char* assume_profile_changed = "--assume-profile-changed";
     const char* downgrade_flag = "--downgrade";
+    std::string class_loader_context_arg = "--class-loader-context=";
+    if (class_loader_context != nullptr) {
+        class_loader_context_arg += class_loader_context;
+    }
 
     // program name, dex file, isa, filter, the final NULL
-    const int argc = 5 +
+    const int argc = 6 +
         (profile_was_updated ? 1 : 0) +
-        (downgrade ? 1 : 0);
+        (vdex_fd >= 0 ? 1 : 0) +
+        (oat_fd >= 0 ? 1 : 0) +
+        (downgrade ? 1 : 0) +
+        (class_loader_context != nullptr ? 1 : 0);
     const char* argv[argc];
     int i = 0;
-    argv[i++] = DEXOPTANALYZER_BIN;
+    argv[i++] = dexoptanalyzer_bin;
     argv[i++] = dex_file_arg.c_str();
     argv[i++] = isa_arg.c_str();
     argv[i++] = compiler_filter_arg.c_str();
+    if (oat_fd >= 0) {
+        argv[i++] = oat_fd_arg.c_str();
+    }
+    if (vdex_fd >= 0) {
+        argv[i++] = vdex_fd_arg.c_str();
+    }
+    argv[i++] = zip_fd_arg.c_str();
     if (profile_was_updated) {
         argv[i++] = assume_profile_changed;
     }
     if (downgrade) {
         argv[i++] = downgrade_flag;
     }
+    if (class_loader_context != nullptr) {
+        argv[i++] = class_loader_context_arg.c_str();
+    }
     argv[i] = NULL;
 
-    execv(DEXOPTANALYZER_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", DEXOPTANALYZER_BIN, strerror(errno));
+    execv(dexoptanalyzer_bin, (char * const *)argv);
+    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
 }
 
 // Prepares the oat dir for the secondary dex files.
 static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
-        const char* instruction_set, std::string* oat_dir_out) {
+        const char* instruction_set) {
     unsigned long dirIndex = dex_path.rfind('/');
     if (dirIndex == std::string::npos) {
         LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
@@ -1427,10 +1653,8 @@
 
     char oat_dir[PKG_PATH_MAX];
     snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
-    oat_dir_out->assign(oat_dir);
 
-    // Create oat/isa output directory.
-    if (prepare_app_cache_dir(*oat_dir_out, instruction_set, oat_dir_mode, uid, uid) != 0) {
+    if (prepare_app_cache_dir(oat_dir, instruction_set, oat_dir_mode, uid, uid) != 0) {
         LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
         return false;
     }
@@ -1438,37 +1662,156 @@
     return true;
 }
 
-static int constexpr DEXOPTANALYZER_BIN_EXEC_ERROR = 200;
+// Return codes for identifying the reason why dexoptanalyzer was not invoked when processing
+// secondary dex files. This return codes are returned by the child process created for
+// analyzing secondary dex files in process_secondary_dex_dexopt.
 
-// Verifies the result of dexoptanalyzer executed for the apk_path.
+enum DexoptAnalyzerSkipCodes {
+  // The dexoptanalyzer was not invoked because of validation or IO errors.
+  // Specific errors are encoded in the name.
+  kSecondaryDexDexoptAnalyzerSkippedValidatePath = 200,
+  kSecondaryDexDexoptAnalyzerSkippedOpenZip = 201,
+  kSecondaryDexDexoptAnalyzerSkippedPrepareDir = 202,
+  kSecondaryDexDexoptAnalyzerSkippedOpenOutput = 203,
+  kSecondaryDexDexoptAnalyzerSkippedFailExec = 204,
+  // The dexoptanalyzer was not invoked because the dex file does not exist anymore.
+  kSecondaryDexDexoptAnalyzerSkippedNoFile = 205,
+};
+
+// Verifies the result of analyzing secondary dex files from process_secondary_dex_dexopt.
 // If the result is valid returns true and sets dexopt_needed_out to a valid value.
 // Returns false for errors or unexpected result values.
-static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
-            int* dexopt_needed_out) {
+// The result is expected to be either one of SECONDARY_DEX_* codes or a valid exit code
+// of dexoptanalyzer.
+static bool process_secondary_dexoptanalyzer_result(const std::string& dex_path, int result,
+            int* dexopt_needed_out, std::string* error_msg) {
     // The result values are defined in dexoptanalyzer.
     switch (result) {
-        case 0:  // no_dexopt_needed
+        case 0:  // dexoptanalyzer: no_dexopt_needed
             *dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
-        case 1:  // dex2oat_from_scratch
+        case 1:  // dexoptanalyzer: dex2oat_from_scratch
             *dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
-        case 5:  // dex2oat_for_bootimage_odex
+        case 5:  // dexoptanalyzer: dex2oat_for_bootimage_odex
             *dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
-        case 6:  // dex2oat_for_filter_odex
+        case 6:  // dexoptanalyzer: dex2oat_for_filter_odex
             *dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
-        case 7:  // dex2oat_for_relocation_odex
+        case 7:  // dexoptanalyzer: dex2oat_for_relocation_odex
             *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
-        case 2:  // dex2oat_for_bootimage_oat
-        case 3:  // dex2oat_for_filter_oat
-        case 4:  // dex2oat_for_relocation_oat
-            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
-                    << " Expected odex file status for secondary dex " << dex_path
-                    << " : dexoptanalyzer result=" << result;
-            return false;
-        default:
-            LOG(ERROR) << "Unexpected result for dexoptanalyzer " << dex_path
-                    << " exec_dexoptanalyzer result=" << result;
+        case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
+        case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
+        case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
+            *error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
+                                      " Expected odex file status for secondary dex %s"
+                                      " : dexoptanalyzer result=%d",
+                                      dex_path.c_str(),
+                                      result);
             return false;
     }
+
+    // Use a second switch for enum switch-case analysis.
+    switch (static_cast<DexoptAnalyzerSkipCodes>(result)) {
+        case kSecondaryDexDexoptAnalyzerSkippedNoFile:
+            // If the file does not exist there's no need for dexopt.
+            *dexopt_needed_out = NO_DEXOPT_NEEDED;
+            return true;
+
+        case kSecondaryDexDexoptAnalyzerSkippedValidatePath:
+            *error_msg = "Dexoptanalyzer path validation failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenZip:
+            *error_msg = "Dexoptanalyzer open zip failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedPrepareDir:
+            *error_msg = "Dexoptanalyzer dir preparation failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenOutput:
+            *error_msg = "Dexoptanalyzer open output failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedFailExec:
+            *error_msg = "Dexoptanalyzer failed to execute";
+            return false;
+    }
+
+    *error_msg = StringPrintf("Unexpected result from analyzing secondary dex %s result=%d",
+                              dex_path.c_str(),
+                              result);
+    return false;
+}
+
+enum SecondaryDexAccess {
+    kSecondaryDexAccessReadOk = 0,
+    kSecondaryDexAccessDoesNotExist = 1,
+    kSecondaryDexAccessPermissionError = 2,
+    kSecondaryDexAccessIOError = 3
+};
+
+static SecondaryDexAccess check_secondary_dex_access(const std::string& dex_path) {
+    // Check if the path exists and can be read. If not, there's nothing to do.
+    if (access(dex_path.c_str(), R_OK) == 0) {
+        return kSecondaryDexAccessReadOk;
+    } else {
+        if (errno == ENOENT) {
+            LOG(INFO) << "Secondary dex does not exist: " <<  dex_path;
+            return kSecondaryDexAccessDoesNotExist;
+        } else {
+            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+            return errno == EACCES
+                ? kSecondaryDexAccessPermissionError
+                : kSecondaryDexAccessIOError;
+        }
+    }
+}
+
+static bool is_file_public(const std::string& filename) {
+    struct stat file_stat;
+    if (stat(filename.c_str(), &file_stat) == 0) {
+        return (file_stat.st_mode & S_IROTH) != 0;
+    }
+    return false;
+}
+
+// Create the oat file structure for the secondary dex 'dex_path' and assign
+// the individual path component to the 'out_' parameters.
+static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
+        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path, std::string* error_msg) {
+    size_t dirIndex = dex_path.rfind('/');
+    if (dirIndex == std::string::npos) {
+        *error_msg = std::string("Unexpected dir structure for dex file ").append(dex_path);
+        return false;
+    }
+    // TODO(calin): we have similar computations in at lest 3 other places
+    // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
+    // using string append.
+    std::string apk_dir = dex_path.substr(0, dirIndex);
+    snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
+    snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
+
+    if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
+            /*is_secondary_dex*/true, out_oat_path)) {
+        *error_msg = std::string("Could not create oat path for secondary dex ").append(dex_path);
+        return false;
+    }
+    return true;
+}
+
+// Validate that the dexopt_flags contain a valid storage flag and convert that to an installd
+// recognized storage flags (FLAG_STORAGE_CE or FLAG_STORAGE_DE).
+static bool validate_dexopt_storage_flags(int dexopt_flags,
+                                          int* out_storage_flag,
+                                          std::string* error_msg) {
+    if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
+        *out_storage_flag = FLAG_STORAGE_CE;
+        if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+            *error_msg = "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+            return false;
+        }
+    } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+        *out_storage_flag = FLAG_STORAGE_DE;
+    } else {
+        *error_msg = "Secondary dex storage flag must be set";
+        return false;
+    }
+    return true;
 }
 
 // Processes the dex_path as a secondary dex files and return true if the path dex file should
@@ -1478,121 +1821,153 @@
 //   - is_public_out: whether or not the oat file should not be made public
 //   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
 //   - oat_dir_out: the oat dir path where the oat file should be stored
-//   - dex_path_out: the real path of the dex file
-static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
+static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, std::string* dex_path_out, bool downgrade) {
+        std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
+        /* out */ std::string* error_msg) {
+    LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
-
-    if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
-        storage_flag = FLAG_STORAGE_CE;
-        if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
-            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
-            return false;
-        }
-    } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
-        storage_flag = FLAG_STORAGE_DE;
-    } else {
-        LOG(ERROR) << "Secondary dex storage flag must be set";
+    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
+        LOG(ERROR) << *error_msg;
         return false;
     }
-
-    {
-        // As opposed to the primary apk, secondary dex files might contain symlinks.
-        // Resolve the path before passing it to the validate method to
-        // make sure the verification is done on the real location.
-        UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
-        if (dex_real_path_cstr == nullptr) {
-            PLOG(ERROR) << "Could not get the real path of the secondary dex file "
-                    << original_dex_path;
-            return false;
-        } else {
-            dex_path_out->assign(dex_real_path_cstr.get());
-        }
-    }
-    const std::string& dex_path = *dex_path_out;
-    if (!validate_dex_path_size(dex_path)) {
+    // Compute the oat dir as it's not easy to extract it from the child computation.
+    char oat_path[PKG_PATH_MAX];
+    char oat_dir[PKG_PATH_MAX];
+    char oat_isa_dir[PKG_PATH_MAX];
+    if (!create_secondary_dex_oat_layout(
+            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
+        LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
         return false;
     }
-    if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
-        LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-        return false;
-    }
-
-    // Check if the path exist. If not, there's nothing to do.
-    struct stat dex_path_stat;
-    if (stat(dex_path.c_str(), &dex_path_stat) != 0) {
-        if (errno == ENOENT) {
-            // Secondary dex files might be deleted any time by the app.
-            // Nothing to do if that's the case
-            ALOGV("Secondary dex does not exist %s", dex_path.c_str());
-            return NO_DEXOPT_NEEDED;
-        } else {
-            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
-        }
-    }
-
-    // Check if we should make the oat file public.
-    // Note that if the dex file is not public the compiled code cannot be made public.
-    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) &&
-            ((dex_path_stat.st_mode & S_IROTH) != 0);
-
-    // Prepare the oat directories.
-    if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
-        return false;
-    }
-
-    // Analyze profiles.
-    bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+    oat_dir_out->assign(oat_dir);
 
     pid_t pid = fork();
     if (pid == 0) {
         // child -- drop privileges before continuing.
         drop_capabilities(uid);
-        // Run dexoptanalyzer to get dexopt_needed code.
-        exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated,
-                            downgrade);
-        exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
+
+        // Validate the path structure.
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
+            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
+        }
+
+        // Open the dex file.
+        unique_fd zip_fd;
+        zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
+        if (zip_fd.get() < 0) {
+            if (errno == ENOENT) {
+                _exit(kSecondaryDexDexoptAnalyzerSkippedNoFile);
+            } else {
+                _exit(kSecondaryDexDexoptAnalyzerSkippedOpenZip);
+            }
+        }
+
+        // Prepare the oat directories.
+        if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
+            _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
+        }
+
+        // Open the vdex/oat files if any.
+        unique_fd oat_file_fd;
+        unique_fd vdex_file_fd;
+        if (!maybe_open_oat_and_vdex_file(dex_path,
+                                          *oat_dir_out,
+                                          instruction_set,
+                                          true /* is_secondary_dex */,
+                                          &oat_file_fd,
+                                          &vdex_file_fd)) {
+            _exit(kSecondaryDexDexoptAnalyzerSkippedOpenOutput);
+        }
+
+        // Analyze profiles.
+        bool profile_was_updated = analyze_profiles(uid, pkgname, dex_path,
+                /*is_secondary_dex*/true);
+
+        // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
+        exec_dexoptanalyzer(dex_path,
+                            vdex_file_fd.get(),
+                            oat_file_fd.get(),
+                            zip_fd.get(),
+                            instruction_set,
+                            compiler_filter, profile_was_updated,
+                            downgrade,
+                            class_loader_context);
+        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
+        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
-
     int result = wait_child(pid);
     if (!WIFEXITED(result)) {
-        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+        *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
+                                  dex_path.c_str(),
+                                  result);
+        LOG(ERROR) << *error_msg;
         return false;
     }
     result = WEXITSTATUS(result);
-    bool success = process_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+    // Check that we successfully executed dexoptanalyzer.
+    bool success = process_secondary_dexoptanalyzer_result(dex_path,
+                                                           result,
+                                                           dexopt_needed_out,
+                                                           error_msg);
+    if (!success) {
+        LOG(ERROR) << *error_msg;
+    }
+
+    LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;
+
     // Run dexopt only if needed or forced.
-    // Note that dexoptanalyzer is executed even if force compilation is enabled.
-    // We ignore its valid dexopNeeded result, but still check (in process_dexoptanalyzer_result)
-    // that we only get results for odex files (apk_dir/oat/isa/code.odex) and not
-    // for oat files from dalvik-cache.
-    if (success && ((dexopt_flags & DEXOPT_FORCE) != 0)) {
+    // Note that dexoptanalyzer is executed even if force compilation is enabled (because it
+    // makes the code simpler; force compilation is only needed during tests).
+    if (success &&
+        (result != kSecondaryDexDexoptAnalyzerSkippedNoFile) &&
+        ((dexopt_flags & DEXOPT_FORCE) != 0)) {
         *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
     }
 
+    // Check if we should make the oat file public.
+    // Note that if the dex file is not public the compiled code cannot be made public.
+    // It is ok to check this flag outside in the parent process.
+    *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);
+
     return success;
 }
 
+static std::string format_dexopt_error(int status, const char* dex_path) {
+  if (WIFEXITED(status)) {
+    int int_code = WEXITSTATUS(status);
+    const char* code_name = get_return_code_name(static_cast<DexoptReturnCodes>(int_code));
+    if (code_name != nullptr) {
+      return StringPrintf("Dex2oat invocation for %s failed: %s", dex_path, code_name);
+    }
+  }
+  return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
+}
+
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade) {
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
-    if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
-        LOG_FATAL("dexopt flags contains unknown fields\n");
-    }
+    CHECK(error_msg != nullptr);
+    CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
+        << "dexopt flags contains unknown fields: " << dexopt_flags;
 
     if (!validate_dex_path_size(dex_path)) {
+        *error_msg = StringPrintf("Failed to validate %s", dex_path);
         return -1;
     }
 
     if (class_loader_context != nullptr && strlen(class_loader_context) > PKG_PATH_MAX) {
-        LOG(ERROR) << "Class loader context exceeds the allowed size: " << class_loader_context;
+        *error_msg = StringPrintf("Class loader context exceeds the allowed size: %s",
+                                  class_loader_context);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1601,21 +1976,25 @@
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
     bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
     bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+    bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
+    bool enable_hidden_api_checks = (dexopt_flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) != 0;
+    bool generate_compact_dex = (dexopt_flags & DEXOPT_GENERATE_COMPACT_DEX) != 0;
+    bool generate_app_image = (dexopt_flags & DEXOPT_GENERATE_APP_IMAGE) != 0;
 
     // Check if we're dealing with a secondary dex file and if we need to compile it.
     std::string oat_dir_str;
-    std::string dex_real_path;
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                &dex_real_path,
-                downgrade)) {
+                downgrade, class_loader_context, error_msg)) {
             oat_dir = oat_dir_str.c_str();
-            dex_path = dex_real_path.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
             }
         } else {
+            if (error_msg->empty()) {  // TODO: Make this a CHECK.
+                *error_msg = "Failed processing secondary.";
+            }
             return -1;  // We had an error, logged in the process method.
         }
     } else {
@@ -1628,7 +2007,8 @@
     // Open the input file.
     unique_fd input_fd(open(dex_path, O_RDONLY, 0));
     if (input_fd.get() < 0) {
-        ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
+        *error_msg = StringPrintf("installd cannot open '%s' for input during dexopt", dex_path);
+        LOG(ERROR) << *error_msg;
         return -1;
     }
 
@@ -1637,14 +2017,16 @@
     Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
             instruction_set, is_secondary_dex, out_oat_path);
     if (out_oat_fd.get() < 0) {
+        *error_msg = "Could not open out oat file.";
         return -1;
     }
 
     // Open vdex files.
     Dex2oatFileWrapper in_vdex_fd;
     Dex2oatFileWrapper out_vdex_fd;
-    if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
-            is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+    if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
+            is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+        *error_msg = "Could not open vdex files.";
         return -1;
     }
 
@@ -1656,7 +2038,8 @@
     if (is_secondary_dex) {
         if (selinux_android_restorecon_pkgdir(oat_dir, se_info, uid,
                 SELINUX_ANDROID_RESTORECON_RECURSE)) {
-            LOG(ERROR) << "Failed to restorecon " << oat_dir;
+            *error_msg = std::string("Failed to restorecon ").append(oat_dir);
+            LOG(ERROR) << *error_msg;
             return -1;
         }
     }
@@ -1665,14 +2048,22 @@
     unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
 
     // Create the app image file if needed.
-    Dex2oatFileWrapper image_fd =
-            maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
+    Dex2oatFileWrapper image_fd = maybe_open_app_image(
+            out_oat_path, generate_app_image, is_public, uid, is_secondary_dex);
 
     // Open the reference profile if needed.
     Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
-            pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex);
+            pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
 
-    ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
+    unique_fd dex_metadata_fd;
+    if (dex_metadata_path != nullptr) {
+        dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
+        if (dex_metadata_fd.get() < 0) {
+            PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
+        }
+    }
+
+    LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
     pid_t pid = fork();
     if (pid == 0) {
@@ -1681,8 +2072,8 @@
 
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
-            ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
-            _exit(67);
+            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
+            _exit(DexoptReturnCodes::kFlock);
         }
 
         run_dex2oat(input_fd.get(),
@@ -1697,15 +2088,22 @@
                     compiler_filter,
                     debuggable,
                     boot_complete,
+                    background_job_compile,
                     reference_profile_fd.get(),
-                    class_loader_context);
-        _exit(68);   /* only get here on exec failure */
+                    class_loader_context,
+                    target_sdk_version,
+                    enable_hidden_api_checks,
+                    generate_compact_dex,
+                    dex_metadata_fd.get(),
+                    compilation_reason);
     } else {
         int res = wait_child(pid);
         if (res == 0) {
-            ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
         } else {
-            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
+            LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
+                         << std::hex << std::setw(4) << res << ", process failed";
+            *error_msg = format_dexopt_error(res, dex_path);
             return res;
         }
     }
@@ -1748,29 +2146,13 @@
     return false;
 }
 
-// Create the oat file structure for the secondary dex 'dex_path' and assign
-// the individual path component to the 'out_' parameters.
-static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
-        /*out*/char* out_oat_dir, /*out*/char* out_oat_isa_dir, /*out*/char* out_oat_path) {
-    size_t dirIndex = dex_path.rfind('/');
-    if (dirIndex == std::string::npos) {
-        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
-        return false;
-    }
-    // TODO(calin): we have similar computations in at lest 3 other places
-    // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
-    // use string append.
-    std::string apk_dir = dex_path.substr(0, dirIndex);
-    snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
-    snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
-
-    if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
-            /*is_secondary_dex*/true, out_oat_path)) {
-        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
-        return false;
-    }
-    return true;
-}
+enum ReconcileSecondaryDexResult {
+    kReconcileSecondaryDexExists = 0,
+    kReconcileSecondaryDexCleanedUp = 1,
+    kReconcileSecondaryDexValidationError = 2,
+    kReconcileSecondaryDexCleanUpError = 3,
+    kReconcileSecondaryDexAccessIOError = 4,
+};
 
 // Reconcile the secondary dex 'dex_path' and its generated oat files.
 // Return true if all the parameters are valid and the secondary dex file was
@@ -1784,36 +2166,15 @@
         const std::string& pkgname, int uid, const std::vector<std::string>& isas,
         const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
         /*out*/bool* out_secondary_dex_exists) {
-    // Set out to false to start with, just in case we have validation errors.
-    *out_secondary_dex_exists = false;
-    if (!validate_dex_path_size(dex_path)) {
-        return false;
-    }
-
+    *out_secondary_dex_exists = false;  // start by assuming the file does not exist.
     if (isas.size() == 0) {
         LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
         return false;
     }
 
-    const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
-
-    // Note that we cannot validate the package path here because the file might not exist
-    // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
-    // /data/data/ a lot of validations will fail if we attempt to check the package path.
-    // It is still ok to be more relaxed because any file removal is done after forking and
-    // dropping capabilities.
-    if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
-            uid, storage_flag, /*validate_package_path*/ false)) {
-        LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-        return false;
-    }
-
-    if (access(dex_path.c_str(), F_OK) == 0) {
-        // The path exists, nothing to do. The odex files (if any) will be left untouched.
-        *out_secondary_dex_exists = true;
-        return true;
-    } else if (errno != ENOENT) {
-        PLOG(ERROR) << "Failed to check access to secondary dex " << dex_path;
+    if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
+        LOG(ERROR) << "reconcile_secondary_dex_file called with invalid storage_flag: "
+                << storage_flag;
         return false;
     }
 
@@ -1821,23 +2182,40 @@
     // of the package user id. So we fork and drop capabilities in the child.
     pid_t pid = fork();
     if (pid == 0) {
-        // The secondary dex does not exist anymore. Clear any generated files.
+        /* child -- drop privileges before continuing */
+        drop_capabilities(uid);
+
+        const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+        if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+                uid, storage_flag)) {
+            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            _exit(kReconcileSecondaryDexValidationError);
+        }
+
+        SecondaryDexAccess access_check = check_secondary_dex_access(dex_path);
+        switch (access_check) {
+            case kSecondaryDexAccessDoesNotExist:
+                 // File does not exist. Proceed with cleaning.
+                break;
+            case kSecondaryDexAccessReadOk: _exit(kReconcileSecondaryDexExists);
+            case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
+            case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
+            default:
+                LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+                _exit(kReconcileSecondaryDexValidationError);
+        }
+
+        // The secondary dex does not exist anymore or it's. Clear any generated files.
         char oat_path[PKG_PATH_MAX];
         char oat_dir[PKG_PATH_MAX];
         char oat_isa_dir[PKG_PATH_MAX];
         bool result = true;
-        /* child -- drop privileges before continuing */
-        drop_capabilities(uid);
         for (size_t i = 0; i < isas.size(); i++) {
-            if (!create_secondary_dex_oat_layout(dex_path,
-                                                 isas[i],
-                                                 oat_dir,
-                                                 oat_isa_dir,
-                                                 oat_path)) {
-                LOG(ERROR) << "Could not create secondary odex layout: "
-                           << dex_path;
-                result = false;
-                continue;
+            std::string error_msg;
+            if (!create_secondary_dex_oat_layout(
+                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
+                LOG(ERROR) << error_msg;
+                _exit(kReconcileSecondaryDexValidationError);
             }
 
             // Delete oat/vdex/art files.
@@ -1847,9 +2225,9 @@
 
             // Delete profiles.
             std::string current_profile = create_current_profile_path(
-                multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
+                multiuser_get_user_id(uid), pkgname, dex_path, /*is_secondary*/true);
             std::string reference_profile = create_reference_profile_path(
-                dex_path, /*is_secondary*/true);
+                pkgname, dex_path, /*is_secondary*/true);
             result = unlink_if_exists(current_profile) && result;
             result = unlink_if_exists(reference_profile) && result;
 
@@ -1862,11 +2240,127 @@
             result = rmdir_if_empty(oat_isa_dir) && result;
             result = rmdir_if_empty(oat_dir) && result;
         }
-        result ? _exit(0) : _exit(1);
+        if (!result) {
+            PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+        }
+        _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
     }
 
     int return_code = wait_child(pid);
-    return return_code == 0;
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
+    } else {
+        return_code = WEXITSTATUS(return_code);
+    }
+
+    LOG(DEBUG) << "Reconcile secondary dex path " << dex_path << " result=" << return_code;
+
+    switch (return_code) {
+        case kReconcileSecondaryDexCleanedUp:
+        case kReconcileSecondaryDexValidationError:
+            // If we couldn't validate assume the dex file does not exist.
+            // This will purge the entry from the PM records.
+            *out_secondary_dex_exists = false;
+            return true;
+        case kReconcileSecondaryDexExists:
+            *out_secondary_dex_exists = true;
+            return true;
+        case kReconcileSecondaryDexAccessIOError:
+            // We had an access IO error.
+            // Return false so that we can try again.
+            // The value of out_secondary_dex_exists does not matter in this case and by convention
+            // is set to false.
+            *out_secondary_dex_exists = false;
+            return false;
+        default:
+            LOG(ERROR) << "Unexpected code from reconcile_secondary_dex_file: " << return_code;
+            *out_secondary_dex_exists = false;
+            return false;
+    }
+}
+
+// Compute and return the hash (SHA-256) of the secondary dex file at dex_path.
+// Returns true if all parameters are valid and the hash successfully computed and stored in
+// out_secondary_dex_hash.
+// Also returns true with an empty hash if the file does not currently exist or is not accessible to
+// the app.
+// For any other errors (e.g. if any of the parameters are invalid) returns false.
+bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid,
+        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+        std::vector<uint8_t>* out_secondary_dex_hash) {
+    out_secondary_dex_hash->clear();
+
+    const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+    if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
+        LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: "
+                << storage_flag;
+        return false;
+    }
+
+    // Pipe to get the hash result back from our child process.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    // Fork so that actual access to the files is done in the app's own UID, to ensure we only
+    // access data the app itself can access.
+    pid_t pid = fork();
+    if (pid == 0) {
+        // child -- drop privileges before continuing
+        drop_capabilities(uid);
+        pipe_read.reset();
+
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
+            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            _exit(DexoptReturnCodes::kHashValidatePath);
+        }
+
+        unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+        if (fd == -1) {
+            if (errno == EACCES || errno == ENOENT) {
+                // Not treated as an error.
+                _exit(0);
+            }
+            PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+            _exit(DexoptReturnCodes::kHashOpenPath);
+        }
+
+        SHA256_CTX ctx;
+        SHA256_Init(&ctx);
+
+        std::vector<uint8_t> buffer(65536);
+        while (true) {
+            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
+            if (bytes_read == 0) {
+                break;
+            } else if (bytes_read == -1) {
+                PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+                _exit(DexoptReturnCodes::kHashReadDex);
+            }
+
+            SHA256_Update(&ctx, buffer.data(), bytes_read);
+        }
+
+        std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
+        SHA256_Final(hash.data(), &ctx);
+        if (!WriteFully(pipe_write, hash.data(), hash.size())) {
+            _exit(DexoptReturnCodes::kHashWrite);
+        }
+
+        _exit(0);
+    }
+
+    // parent
+    pipe_write.reset();
+
+    out_secondary_dex_hash->resize(SHA256_DIGEST_LENGTH);
+    if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) {
+        out_secondary_dex_hash->clear();
+    }
+    return wait_child(pid) == 0;
 }
 
 // Helper for move_ab, so that we can have common failure-case cleanup.
@@ -2031,5 +2525,303 @@
     return return_value_oat && return_value_art && return_value_vdex;
 }
 
+static bool is_absolute_path(const std::string& path) {
+    if (path.find('/') != 0 || path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid absolute path " << path;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static bool is_valid_instruction_set(const std::string& instruction_set) {
+    // TODO: add explicit whitelisting of instruction sets
+    if (instruction_set.find('/') != std::string::npos) {
+        LOG(ERROR) << "Invalid instruction set " << instruction_set;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set) {
+    std::string oat_dir_ = oat_dir;
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(oat_dir_)) return false;
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string res_ = oat_dir_ + '/' + instruction_set + '/'
+            + apk_path_.substr(start + 1, end - start - 1) + ".odex";
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string oat_dir = apk_path_.substr(0, start + 1) + "oat";
+    return calculate_oat_file_path_default(path, oat_dir.c_str(), apk_path, instruction_set);
+}
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set) {
+    std::string src_ = src;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(src_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    for (auto it = src_.begin() + 1; it < src_.end(); ++it) {
+        if (*it == '/') {
+            *it = '@';
+        }
+    }
+
+    std::string res_ = android_data_dir + DALVIK_CACHE + '/' + instruction_set_ + src_
+            + DALVIK_CACHE_POSTFIX;
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
+bool open_classpath_files(const std::string& classpath, std::vector<unique_fd>* apk_fds,
+        std::vector<std::string>* dex_locations) {
+    std::vector<std::string> classpaths_elems = base::Split(classpath, ":");
+    for (const std::string& elem : classpaths_elems) {
+        unique_fd fd(TEMP_FAILURE_RETRY(open(elem.c_str(), O_RDONLY)));
+        if (fd < 0) {
+            PLOG(ERROR) << "Could not open classpath elem " << elem;
+            return false;
+        } else {
+            apk_fds->push_back(std::move(fd));
+            dex_locations->push_back(elem);
+        }
+    }
+    return true;
+}
+
+static bool create_app_profile_snapshot(int32_t app_id,
+                                        const std::string& package_name,
+                                        const std::string& profile_name,
+                                        const std::string& classpath) {
+    int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);
+
+    unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
+    if (snapshot_fd < 0) {
+        return false;
+    }
+
+    std::vector<unique_fd> profiles_fd;
+    unique_fd reference_profile_fd;
+    open_profile_files(app_shared_gid, package_name, profile_name, /*is_secondary_dex*/ false,
+            &profiles_fd, &reference_profile_fd);
+    if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
+        return false;
+    }
+
+    profiles_fd.push_back(std::move(reference_profile_fd));
+
+    // Open the class paths elements. These will be used to filter out profile data that does
+    // not belong to the classpath during merge.
+    std::vector<unique_fd> apk_fds;
+    std::vector<std::string> dex_locations;
+    if (!open_classpath_files(classpath, &apk_fds, &dex_locations)) {
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(app_shared_gid);
+        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+    }
+
+    /* parent */
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+        return false;
+    }
+
+    return true;
+}
+
+static bool create_boot_image_profile_snapshot(const std::string& package_name,
+                                               const std::string& profile_name,
+                                               const std::string& classpath) {
+    // The reference profile directory for the android package might not be prepared. Do it now.
+    const std::string ref_profile_dir =
+            create_primary_reference_profile_package_dir_path(package_name);
+    if (fs_prepare_dir(ref_profile_dir.c_str(), 0770, AID_SYSTEM, AID_SYSTEM) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << ref_profile_dir;
+        return false;
+    }
+
+    // Open and create the snapshot profile.
+    unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
+
+    // Collect all non empty profiles.
+    // The collection will traverse all applications profiles and find the non empty files.
+    // This has the potential of inspecting a large number of files and directories (depending
+    // on the number of applications and users). So there is a slight increase in the chance
+    // to get get occasionally I/O errors (e.g. for opening the file). When that happens do not
+    // fail the snapshot and aggregate whatever profile we could open.
+    //
+    // The profile snapshot is a best effort based on available data it's ok if some data
+    // from some apps is missing. It will be counter productive for the snapshot to fail
+    // because we could not open or read some of the files.
+    std::vector<std::string> profiles;
+    if (!collect_profiles(&profiles)) {
+        LOG(WARNING) << "There were errors while collecting the profiles for the boot image.";
+    }
+
+    // If we have no profiles return early.
+    if (profiles.empty()) {
+        return true;
+    }
+
+    // Open the classpath elements. These will be used to filter out profile data that does
+    // not belong to the classpath during merge.
+    std::vector<unique_fd> apk_fds;
+    std::vector<std::string> dex_locations;
+    if (!open_classpath_files(classpath, &apk_fds, &dex_locations)) {
+        return false;
+    }
+
+    // If we could not open any files from the classpath return an error.
+    if (apk_fds.empty()) {
+        LOG(ERROR) << "Could not open any of the classpath elements.";
+        return false;
+    }
+
+    // Aggregate the profiles in batches of kAggregationBatchSize.
+    // We do this to avoid opening a huge a amount of files.
+    static constexpr size_t kAggregationBatchSize = 10;
+
+    std::vector<unique_fd> profiles_fd;
+    for (size_t i = 0; i < profiles.size(); )  {
+        for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) {
+            unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY);
+            if (fd.get() >= 0) {
+                profiles_fd.push_back(std::move(fd));
+            }
+        }
+        pid_t pid = fork();
+        if (pid == 0) {
+            /* child -- drop privileges before continuing */
+            drop_capabilities(AID_SYSTEM);
+
+            // The introduction of new access flags into boot jars causes them to
+            // fail dex file verification.
+            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+        }
+
+        /* parent */
+        int return_code = wait_child(pid);
+        if (!WIFEXITED(return_code)) {
+            PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+            return false;
+        }
+        return true;
+    }
+    return true;
+}
+
+bool create_profile_snapshot(int32_t app_id, const std::string& package_name,
+        const std::string& profile_name, const std::string& classpath) {
+    if (app_id == -1) {
+        return create_boot_image_profile_snapshot(package_name, profile_name, classpath);
+    } else {
+        return create_app_profile_snapshot(app_id, package_name, profile_name, classpath);
+    }
+}
+
+bool prepare_app_profile(const std::string& package_name,
+                         userid_t user_id,
+                         appid_t app_id,
+                         const std::string& profile_name,
+                         const std::string& code_path,
+                         const std::unique_ptr<std::string>& dex_metadata) {
+    // Prepare the current profile.
+    std::string cur_profile  = create_current_profile_path(user_id, package_name, profile_name,
+            /*is_secondary_dex*/ false);
+    uid_t uid = multiuser_get_uid(user_id, app_id);
+    if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << cur_profile;
+        return false;
+    }
+
+    // Check if we need to install the profile from the dex metadata.
+    if (dex_metadata == nullptr) {
+        return true;
+    }
+
+    // We have a dex metdata. Merge the profile into the reference profile.
+    unique_fd ref_profile_fd = open_reference_profile(uid, package_name, profile_name,
+            /*read_write*/ true, /*is_secondary_dex*/ false);
+    unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY(
+            open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW)));
+    unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW)));
+    if (apk_fd < 0) {
+        PLOG(ERROR) << "Could not open code path " << code_path;
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        gid_t app_shared_gid = multiuser_get_shared_gid(user_id, app_id);
+        drop_capabilities(app_shared_gid);
+
+        // The copy and update takes ownership over the fds.
+        run_profman_copy_and_update(std::move(dex_metadata_fd),
+                                    std::move(ref_profile_fd),
+                                    std::move(apk_fd),
+                                    code_path);
+    }
+
+    /* parent */
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+        return false;
+    }
+    return true;
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 23446da..bb6fab3 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -17,6 +17,8 @@
 #ifndef DEXOPT_H_
 #define DEXOPT_H_
 
+#include "installd_constants.h"
+
 #include <sys/types.h>
 
 #include <cutils/multiuser.h>
@@ -31,28 +33,63 @@
 static constexpr int DEX2OAT_FOR_FILTER          = 3;
 static constexpr int DEX2OAT_FOR_RELOCATION      = 4;
 
-// Clear the reference profile for the primary apk of the given package.
-bool clear_primary_reference_profile(const std::string& pkgname);
-// Clear the current profile for the primary apk of the given package and user.
-bool clear_primary_current_profile(const std::string& pkgname, userid_t user);
-// Clear all current profile for the primary apk of the given package.
-bool clear_primary_current_profiles(const std::string& pkgname);
-
-bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
+// Clear the reference profile identified by the given profile name.
+bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name);
+// Clear the current profile identified by the given profile name (for single user).
+bool clear_primary_current_profile(const std::string& pkgname, const std::string& profile_name,
+         userid_t user);
+// Clear all current profiles identified by the given profile name (all users).
+bool clear_primary_current_profiles(const std::string& pkgname, const std::string& profile_name);
 
 // Decide if profile guided compilation is needed or not based on existing profiles.
-// The analysis is done for the primary apks (base + splits) of the given package.
+// The analysis is done for a single profile name (which corresponds to a single code path).
 // Returns true if there is enough information in the current profiles that makes it
 // worth to recompile the package.
 // If the return value is true all the current profiles would have been merged into
 // the reference profiles accessible with open_reference_profile().
-bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);
+bool analyze_primary_profiles(uid_t uid,
+                              const std::string& pkgname,
+                              const std::string& profile_name);
 
-bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+// Create a snapshot of the profile information for the given package profile.
+// If appId is -1, the method creates the profile snapshot for the boot image.
+//
+// The profile snapshot is the aggregation of all existing profiles (all current user
+// profiles & the reference profile) and is meant to capture the all the profile information
+// without performing a merge into the reference profile which might impact future dex2oat
+// compilations.
+// The snapshot is created next to the reference profile of the package and the
+// ownership is assigned to AID_SYSTEM.
+// The snapshot location is reference_profile_location.snapshot. If a snapshot is already
+// there, it will be truncated and overwritten.
+//
+// The classpath acts as filter: only profiling data belonging to elements of the classpath
+// will end up in the snapshot.
+bool create_profile_snapshot(int32_t app_id,
+                             const std::string& package,
+                             const std::string& profile_name,
+                             const std::string& classpath);
+
+bool dump_profiles(int32_t uid,
+                   const std::string& pkgname,
+                   const std::string& profile_name,
+                   const std::string& code_path);
 
 bool copy_system_profile(const std::string& system_profile,
                          uid_t packageUid,
-                         const std::string& data_profile_location);
+                         const std::string& pkgname,
+                         const std::string& profile_name);
+
+// Prepare the app profile for the given code path:
+//  - create the current profile using profile_name
+//  - merge the profile from the dex metadata file (if present) into
+//    the reference profile.
+bool prepare_app_profile(const std::string& package_name,
+                         userid_t user_id,
+                         appid_t app_id,
+                         const std::string& profile_name,
+                         const std::string& code_path,
+                         const std::unique_ptr<std::string>& dex_metadata);
 
 bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
 
@@ -61,10 +98,26 @@
         const std::unique_ptr<std::string>& volumeUuid, int storage_flag,
         /*out*/bool* out_secondary_dex_exists);
 
+bool hash_secondary_dex_file(const std::string& dex_path,
+        const std::string& pkgname, int uid, const std::unique_ptr<std::string>& volume_uuid,
+        int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
+
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade);
+        bool downgrade, int target_sdk_version, const char* profile_name,
+        const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set);
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set);
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set);
+
+bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
 
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
new file mode 100644
index 0000000..bbecfa4
--- /dev/null
+++ b/cmds/installd/dexopt_return_codes.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#include <dex2oat_return_codes.h>
+
+namespace android {
+namespace installd {
+
+// Constants for exit codes that installd code emits. These are failure situations before calling
+// any tools, e.g., in validation, and must not overlap with the exit codes of tools, so they
+// can be distinguished.
+enum DexoptReturnCodes : int {
+    kSetGid = 64,
+    kSetUid = 65,
+    kCapSet = 66,
+    kFlock = 67,
+    kProfmanExec = 68,
+    kSetSchedPolicy = 70,
+    kSetPriority = 71,
+    kDex2oatExec = 72,
+    kInstructionSetLength = 73,
+    kHashValidatePath = 74,
+    kHashOpenPath = 75,
+    kHashReadDex = 76,
+    kHashWrite = 77,
+};
+
+inline const char* get_installd_return_code_name(DexoptReturnCodes code) {
+    switch (code) {
+        case kSetGid:
+            return "setgid";
+        case kSetUid:
+            return "setuid";
+        case kCapSet:
+            return "capset";
+        case kFlock:
+            return "flock";
+        case kProfmanExec:
+            return "exec(profman)";
+        case kSetSchedPolicy:
+            return "setschedpolicy";
+        case kSetPriority:
+            return "setpriority";
+        case kDex2oatExec:
+            return "exec(dex2oat)";
+        case kInstructionSetLength:
+            return "instruction-set-length";
+        case kHashValidatePath:
+            return "hash(validate-path)";
+        case kHashOpenPath:
+            return "hash(open-path)";
+        case kHashReadDex:
+            return "hash(read-dex)";
+        case kHashWrite:
+            return "hash(write)";
+    }
+    return nullptr;
+}
+
+inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
+    switch (code) {
+        case art::dex2oat::ReturnCode::kNoFailure:
+            return "dex2oat success";
+        case art::dex2oat::ReturnCode::kOther:
+            return "unspecified dex2oat error";
+        case art::dex2oat::ReturnCode::kCreateRuntime:
+            return "dex2oat failed to create a runtime";
+    }
+    return nullptr;
+}
+
+// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
+// exit codes) as well as art::dex2oat::ReturnCode.
+inline const char* get_return_code_name(int code) {
+    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
+    // TODO: How could switch-case checks be used to enforce completeness?
+    switch (code) {
+        case kSetGid:
+        case kSetUid:
+        case kCapSet:
+        case kFlock:
+        case kProfmanExec:
+        case kSetSchedPolicy:
+        case kSetPriority:
+        case kDex2oatExec:
+        case kInstructionSetLength:
+        case kHashValidatePath:
+        case kHashOpenPath:
+        case kHashReadDex:
+        case kHashWrite:
+            break;
+        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
+        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
+        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
+            break;
+    }
+    const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
+    if (value != nullptr) {
+        return value;
+    }
+    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    return value;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index edcdb6a..b3a6daf 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -16,15 +16,15 @@
 
 #define LOG_TAG "installd"
 
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log.h>              // TODO: Move everything to base::logging.
-
 #include <globals.h>
 #include <installd_constants.h>
 #include <utils.h>
 
+#include <android-base/logging.h>
+
+#include <stdlib.h>
+#include <string.h>
+
 namespace android {
 namespace installd {
 
@@ -44,106 +44,78 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
-/* Directory records that are used in execution of commands. */
-dir_rec_t android_app_dir;
-dir_rec_t android_app_ephemeral_dir;
-dir_rec_t android_app_lib_dir;
-dir_rec_t android_app_private_dir;
-dir_rec_t android_asec_dir;
-dir_rec_t android_data_dir;
-dir_rec_t android_media_dir;
-dir_rec_t android_mnt_expand_dir;
-dir_rec_t android_profiles_dir;
+std::string android_app_dir;
+std::string android_app_ephemeral_dir;
+std::string android_app_lib_dir;
+std::string android_app_private_dir;
+std::string android_asec_dir;
+std::string android_data_dir;
+std::string android_media_dir;
+std::string android_mnt_expand_dir;
+std::string android_profiles_dir;
+std::string android_root_dir;
 
-dir_rec_array_t android_system_dirs;
+std::vector<std::string> android_system_dirs;
 
-/**
- * Initialize all the global variables that are used elsewhere. Returns 0 upon
- * success and -1 on error.
- */
-void free_globals() {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        if (android_system_dirs.dirs[i].path != NULL) {
-            free(android_system_dirs.dirs[i].path);
-        }
+bool init_globals_from_data_and_root() {
+    const char* data_path = getenv("ANDROID_DATA");
+    if (data_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_DATA";
+        return false;
     }
+    const char* root_path = getenv("ANDROID_ROOT");
+    if (root_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_ROOT";
+        return false;
+    }
+    return init_globals_from_data_and_root(data_path, root_path);
+}
 
-    free(android_system_dirs.dirs);
+static std::string ensure_trailing_slash(const std::string& path) {
+    if (path.rfind('/') != path.size() - 1) {
+        return path + '/';
+    } else {
+        return path;
+    }
 }
 
 bool init_globals_from_data_and_root(const char* data, const char* root) {
     // Get the android data directory.
-    if (get_path_from_string(&android_data_dir, data) < 0) {
-        return false;
-    }
+    android_data_dir = ensure_trailing_slash(data);
+
+    // Get the android root directory.
+    android_root_dir = ensure_trailing_slash(root);
 
     // Get the android app directory.
-    if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_dir = android_data_dir + APP_SUBDIR;
 
     // Get the android protected app directory.
-    if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;
 
     // Get the android ephemeral app directory.
-    if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;
 
     // Get the android app native library directory.
-    if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;
 
     // Get the sd-card ASEC mount point.
-    if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
-        return false;
-    }
+    android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));
 
     // Get the android media directory.
-    if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
-        return false;
-    }
+    android_media_dir = android_data_dir + MEDIA_SUBDIR;
 
     // Get the android external app directory.
-    if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
-        return false;
-    }
+    android_mnt_expand_dir = "/mnt/expand/";
 
     // Get the android profiles directory.
-    if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
-        return false;
-    }
+    android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
     // Take note of the system and vendor directories.
-    android_system_dirs.count = 4;
-
-    android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-    if (android_system_dirs.dirs == NULL) {
-        ALOGE("Couldn't allocate array for dirs; aborting\n");
-        return false;
-    }
-
-    dir_rec_t android_root_dir;
-    if (get_path_from_string(&android_root_dir, root) < 0) {
-        return false;
-    }
-
-    android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
-    android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
-
-    android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
-    android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
-
-    android_system_dirs.dirs[2].path = strdup("/vendor/app/");
-    android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
-
-    android_system_dirs.dirs[3].path = strdup("/oem/app/");
-    android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+    android_system_dirs.clear();
+    android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
+    android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
+    android_system_dirs.push_back("/vendor/app/");
+    android_system_dirs.push_back("/oem/app/");
 
     return true;
 }
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index c90beec..633e33b 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -19,40 +19,29 @@
 #define GLOBALS_H_
 
 #include <inttypes.h>
+#include <string>
+#include <vector>
 
 namespace android {
 namespace installd {
 
-/* constants */
-
 // Name of the environment variable that contains the asec mountpoint.
 static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
 
-/* data structures */
+extern std::string android_app_dir;
+extern std::string android_app_ephemeral_dir;
+extern std::string android_app_lib_dir;
+extern std::string android_app_private_dir;
+extern std::string android_asec_dir;
+extern std::string android_data_dir;
+extern std::string android_media_dir;
+extern std::string android_mnt_expand_dir;
+extern std::string android_profiles_dir;
+extern std::string android_root_dir;
 
-struct dir_rec_t {
-    char* path;
-    size_t len;
-};
+extern std::vector<std::string> android_system_dirs;
 
-struct dir_rec_array_t {
-    size_t count;
-    dir_rec_t* dirs;
-};
-
-extern dir_rec_t android_app_dir;
-extern dir_rec_t android_app_ephemeral_dir;
-extern dir_rec_t android_app_lib_dir;
-extern dir_rec_t android_app_private_dir;
-extern dir_rec_t android_asec_dir;
-extern dir_rec_t android_data_dir;
-extern dir_rec_t android_media_dir;
-extern dir_rec_t android_mnt_expand_dir;
-extern dir_rec_t android_profiles_dir;
-
-extern dir_rec_array_t android_system_dirs;
-
-void free_globals();
+bool init_globals_from_data_and_root();
 bool init_globals_from_data_and_root(const char* data, const char* root);
 
 }  // namespace installd
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 35936a2..95ed2ff 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "installd_constants.h"
 #include "installd_deps.h"  // Need to fill in requirements of commands.
@@ -50,133 +51,22 @@
     return property_get(key, value, default_value);
 }
 
-// Compute the output path of
-bool calculate_oat_file_path(char path[PKG_PATH_MAX],
-                             const char *oat_dir,
-                             const char *apk_path,
-                             const char *instruction_set) {
-    const char *file_name_start;
-    const char *file_name_end;
-
-    file_name_start = strrchr(apk_path, '/');
-    if (file_name_start == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
-        return false;
-    }
-    file_name_end = strrchr(apk_path, '.');
-    if (file_name_end < file_name_start) {
-        SLOGE("apk_path '%s' has no extension\n", apk_path);
-        return false;
-    }
-
-    // Calculate file_name
-    int file_name_len = file_name_end - file_name_start - 1;
-    char file_name[file_name_len + 1];
-    memcpy(file_name, file_name_start + 1, file_name_len);
-    file_name[file_name_len] = '\0';
-
-    // <apk_parent_dir>/oat/<isa>/<file_name>.odex
-    snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
-    return true;
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+        const char *instruction_set) {
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
 }
 
-/*
- * Computes the odex file for the given apk_path and instruction_set.
- * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
- *
- * Returns false if it failed to determine the odex file path.
- */
-bool calculate_odex_file_path(char path[PKG_PATH_MAX],
-                              const char *apk_path,
-                              const char *instruction_set) {
-    if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
-            + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
-        SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
-        return false;
-    }
-
-    strcpy(path, apk_path);
-    char *end = strrchr(path, '/');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
-        return false;
-    }
-    const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
-
-    strcpy(end + 1, "oat/");       // path = /system/framework/oat/\0
-    strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
-    strcat(path, apk_end);         // path = /system/framework/oat/<isa>/whatever.jar\0
-    end = strrchr(path, '.');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no extension.\n", apk_path);
-        return false;
-    }
-    strcpy(end + 1, "odex");
-    return true;
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
 }
 
-bool create_cache_path(char path[PKG_PATH_MAX],
-                       const char *src,
-                       const char *instruction_set) {
-    /* demand that we are an absolute path */
-    if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
-        return false;
-    }
-
-    size_t srclen = strlen(src);
-
-    if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
-        return false;
-    }
-
-    size_t dstlen =
-        android_data_dir.len +
-        strlen(DALVIK_CACHE) +
-        1 +
-        strlen(instruction_set) +
-        srclen +
-        strlen(DALVIK_CACHE_POSTFIX) + 2;
-
-    if (dstlen > PKG_PATH_MAX) {
-        return false;
-    }
-
-    sprintf(path,"%s%s/%s/%s",
-            android_data_dir.path,
-            DALVIK_CACHE,
-            instruction_set,
-            src + 1 /* skip the leading / */);
-
-    char* tmp =
-            path +
-            android_data_dir.len +
-            strlen(DALVIK_CACHE) +
-            1 +
-            strlen(instruction_set) + 1;
-
-    for(; *tmp; tmp++) {
-        if (*tmp == '/') {
-            *tmp = '@';
-        }
-    }
-
-    strcat(path, DALVIK_CACHE_POSTFIX);
-    return true;
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
 }
 
 static bool initialize_globals() {
-    const char* data_path = getenv("ANDROID_DATA");
-    if (data_path == nullptr) {
-        SLOGE("Could not find ANDROID_DATA");
-        return false;
-    }
-    const char* root_path = getenv("ANDROID_ROOT");
-    if (root_path == nullptr) {
-        SLOGE("Could not find ANDROID_ROOT");
-        return false;
-    }
-
-    return init_globals_from_data_and_root(data_path, root_path);
+    return init_globals_from_data_and_root();
 }
 
 static int initialize_directories() {
@@ -184,7 +74,7 @@
 
     // Read current filesystem layout version to handle upgrade paths
     char version_path[PATH_MAX];
-    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
 
     int oldVersion;
     if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
@@ -206,7 +96,7 @@
         SLOGD("Upgrading to /data/misc/user directories");
 
         char misc_dir[PATH_MAX];
-        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
 
         char keychain_added_dir[PATH_MAX];
         snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
@@ -227,7 +117,7 @@
                     if ((name[1] == '.') && (name[2] == 0)) continue;
                 }
 
-                uint32_t user_id = atoi(name);
+                uint32_t user_id = std::stoi(name);
 
                 // /data/misc/user/<user_id>
                 if (ensure_config_user_dirs(user_id) == -1) {
@@ -281,7 +171,7 @@
     return res;
 }
 
-static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
     va_list ap;
     int priority;
 
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 2597c79..c928631 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -49,6 +49,12 @@
 constexpr int DEXOPT_FORCE          = 1 << 6;
 constexpr int DEXOPT_STORAGE_CE     = 1 << 7;
 constexpr int DEXOPT_STORAGE_DE     = 1 << 8;
+// Tells the compiler that it is invoked from the background service.  This
+// controls whether extra debugging flags can be used (taking more compile time.)
+constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
+constexpr int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
+constexpr int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
+constexpr int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
 
 /* all known values for dexopt flags */
 constexpr int DEXOPT_MASK =
@@ -59,7 +65,11 @@
     | DEXOPT_SECONDARY_DEX
     | DEXOPT_FORCE
     | DEXOPT_STORAGE_CE
-    | DEXOPT_STORAGE_DE;
+    | DEXOPT_STORAGE_DE
+    | DEXOPT_IDLE_BACKGROUND_JOB
+    | DEXOPT_ENABLE_HIDDEN_API_CHECKS
+    | DEXOPT_GENERATE_COMPACT_DEX
+    | DEXOPT_GENERATE_APP_IMAGE;
 
 // NOTE: keep in sync with StorageManager
 constexpr int FLAG_STORAGE_DE = 1 << 0;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 09e1a00..96d8c47 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -43,6 +43,7 @@
 #include "globals.h"
 #include "installd_constants.h"
 #include "installd_deps.h"  // Need to fill in requirements of commands.
+#include "otapreopt_parameters.h"
 #include "otapreopt_utils.h"
 #include "system_properties.h"
 #include "utils.h"
@@ -78,8 +79,13 @@
 static_assert(DEXOPT_FORCE          == 1 << 6, "DEXOPT_FORCE unexpected.");
 static_assert(DEXOPT_STORAGE_CE     == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
 static_assert(DEXOPT_STORAGE_DE     == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
+static_assert(DEXOPT_ENABLE_HIDDEN_API_CHECKS == 1 << 10,
+        "DEXOPT_ENABLE_HIDDEN_API_CHECKS unexpected");
+static_assert(DEXOPT_GENERATE_COMPACT_DEX == 1 << 11, "DEXOPT_GENERATE_COMPACT_DEX unexpected");
+static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE unexpected");
 
-static_assert(DEXOPT_MASK           == 0x1fe, "DEXOPT_MASK unexpected.");
+static_assert(DEXOPT_MASK           == (0x1dfe | DEXOPT_IDLE_BACKGROUND_JOB),
+              "DEXOPT_MASK unexpected.");
 
 
 
@@ -146,41 +152,25 @@
                 return 0;
             }
             // Copy in the default value.
-            strncpy(value, default_value, kPropertyValueMax - 1);
+            strlcpy(value, default_value, kPropertyValueMax - 1);
             value[kPropertyValueMax - 1] = 0;
             return strlen(default_value);// TODO: Need to truncate?
         }
-        size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
-        strncpy(value, prop_value->data(), size);
-        value[size] = 0;
-        return static_cast<int>(size);
+        size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
+        strlcpy(value, prop_value->data(), size);
+        return static_cast<int>(size - 1);
     }
 
     std::string GetOTADataDirectory() const {
-        return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), target_slot_.c_str());
+        return StringPrintf("%s/%s", GetOtaDirectoryPrefix().c_str(), GetTargetSlot().c_str());
     }
 
     const std::string& GetTargetSlot() const {
-        return target_slot_;
+        return parameters_.target_slot;
     }
 
 private:
 
-    struct Parameters {
-        const char *apk_path;
-        uid_t uid;
-        const char *pkgName;
-        const char *instruction_set;
-        int dexopt_needed;
-        const char* oat_dir;
-        int dexopt_flags;
-        const char* compiler_filter;
-        const char* volume_uuid;
-        const char* shared_libraries;
-        const char* se_info;
-        bool downgrade;
-    };
-
     bool ReadSystemProperties() {
         static constexpr const char* kPropertyFiles[] = {
                 "/default.prop", "/system/build.prop"
@@ -304,338 +294,7 @@
     }
 
     bool ReadArguments(int argc, char** argv) {
-        // Expected command line:
-        //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
-
-        const char* target_slot_arg = argv[1];
-        if (target_slot_arg == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        // Sanitize value. Only allow (a-zA-Z0-9_)+.
-        target_slot_ = target_slot_arg;
-        if (!ValidateTargetSlotSuffix(target_slot_)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << target_slot_;
-            return false;
-        }
-
-        // Check for version or "dexopt" next.
-        if (argv[2] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-
-        if (std::string("dexopt").compare(argv[2]) == 0) {
-            // This is version 1 (N) or pre-versioning version 2.
-            constexpr int kV2ArgCount =   1   // "otapreopt"
-                                        + 1   // slot
-                                        + 1   // "dexopt"
-                                        + 1   // apk_path
-                                        + 1   // uid
-                                        + 1   // pkg
-                                        + 1   // isa
-                                        + 1   // dexopt_needed
-                                        + 1   // oat_dir
-                                        + 1   // dexopt_flags
-                                        + 1   // filter
-                                        + 1   // volume
-                                        + 1   // libs
-                                        + 1;  // seinfo
-            if (argc == kV2ArgCount) {
-                return ReadArgumentsV2(argc, argv, false);
-            } else {
-                return ReadArgumentsV1(argc, argv);
-            }
-        }
-
-        uint32_t version;
-        if (!ParseUInt(argv[2], &version)) {
-            LOG(ERROR) << "Could not parse version: " << argv[2];
-            return false;
-        }
-
-        switch (version) {
-            case 2:
-                return ReadArgumentsV2(argc, argv, true);
-            case 3:
-                return ReadArgumentsV3(argc, argv);
-
-            default:
-                LOG(ERROR) << "Unsupported version " << version;
-                return false;
-        }
-    }
-
-    bool ReadArgumentsV2(int argc ATTRIBUTE_UNUSED, char** argv, bool versioned) {
-        size_t dexopt_index = versioned ? 3 : 2;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        // Set downgrade to false. It is only relevant when downgrading compiler
-        // filter, which is not the case during ota.
-        package_parameters_.downgrade = false;
-
-        if (param_index != 11) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    bool ReadArgumentsV3(int argc ATTRIBUTE_UNUSED, char** argv) {
-        size_t dexopt_index = 3;
-
-        // Check for "dexopt".
-        if (argv[dexopt_index] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[dexopt_index + 1 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4:
-                    package_parameters_.dexopt_needed = atoi(param);
-                    break;
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6:
-                    package_parameters_.dexopt_flags = atoi(param);
-                    break;
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                case 10:
-                    package_parameters_.se_info = ParseNull(param);
-                    break;
-
-                case 11:
-                    package_parameters_.downgrade = ParseBool(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        if (param_index != 12) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        return true;
-    }
-
-    static int ReplaceMask(int input, int old_mask, int new_mask) {
-        return (input & old_mask) != 0 ? new_mask : 0;
-    }
-
-    bool ReadArgumentsV1(int argc ATTRIBUTE_UNUSED, char** argv) {
-        // Check for "dexopt".
-        if (argv[2] == nullptr) {
-            LOG(ERROR) << "Missing parameters";
-            return false;
-        }
-        if (std::string("dexopt").compare(argv[2]) != 0) {
-            LOG(ERROR) << "Expected \"dexopt\"";
-            return false;
-        }
-
-        size_t param_index = 0;
-        for (;; ++param_index) {
-            const char* param = argv[3 + param_index];
-            if (param == nullptr) {
-                break;
-            }
-
-            switch (param_index) {
-                case 0:
-                    package_parameters_.apk_path = param;
-                    break;
-
-                case 1:
-                    package_parameters_.uid = atoi(param);
-                    break;
-
-                case 2:
-                    package_parameters_.pkgName = param;
-                    break;
-
-                case 3:
-                    package_parameters_.instruction_set = param;
-                    break;
-
-                case 4: {
-                    // Version 1 had:
-                    //   DEXOPT_DEX2OAT_NEEDED       = 1
-                    //   DEXOPT_PATCHOAT_NEEDED      = 2
-                    //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
-                    // We will simply use DEX2OAT_FROM_SCRATCH.
-                    package_parameters_.dexopt_needed = DEX2OAT_FROM_SCRATCH;
-                    break;
-                }
-
-                case 5:
-                    package_parameters_.oat_dir = param;
-                    break;
-
-                case 6: {
-                    // Version 1 had:
-                    constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
-                    // Note: DEXOPT_SAFEMODE has been removed.
-                    // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
-                    constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
-                    constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
-                    constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
-                    constexpr int OLD_DEXOPT_OTA            = 1 << 6;
-                    int input = atoi(param);
-                    package_parameters_.dexopt_flags =
-                            ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
-                            ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
-                            ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
-                            ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
-                            ReplaceMask(input, OLD_DEXOPT_OTA, 0);
-                    break;
-                }
-
-                case 7:
-                    package_parameters_.compiler_filter = param;
-                    break;
-
-                case 8:
-                    package_parameters_.volume_uuid = ParseNull(param);
-                    break;
-
-                case 9:
-                    package_parameters_.shared_libraries = ParseNull(param);
-                    break;
-
-                default:
-                    LOG(ERROR) << "Too many arguments, got " << param;
-                    return false;
-            }
-        }
-
-        if (param_index != 10) {
-            LOG(ERROR) << "Not enough parameters";
-            return false;
-        }
-
-        // Set se_info to null. It is only relevant for secondary dex files, which we won't
-        // receive from a v1 A side.
-        package_parameters_.se_info = nullptr;
-
-        // Set downgrade to false. It is only relevant when downgrading compiler
-        // filter, which is not the case during ota.
-        package_parameters_.downgrade = false;
-
-        return true;
+        return parameters_.ReadArguments(argc, const_cast<const char**>(argv));
     }
 
     void PrepareEnvironment() {
@@ -651,11 +310,11 @@
     // Ensure that we have the right boot image. The first time any app is
     // compiled, we'll try to generate it.
     bool PrepareBootImage(bool force) const {
-        if (package_parameters_.instruction_set == nullptr) {
+        if (parameters_.instruction_set == nullptr) {
             LOG(ERROR) << "Instruction set missing.";
             return false;
         }
-        const char* isa = package_parameters_.instruction_set;
+        const char* isa = parameters_.instruction_set;
 
         // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
@@ -696,7 +355,7 @@
 
         std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
         if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
-          return PatchoatBootImage(art_path, isa);
+          return PatchoatBootImage(isa_path, isa);
         } else {
           // No preopted boot image. Try to compile.
           return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
@@ -765,14 +424,14 @@
         CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
     }
 
-    bool PatchoatBootImage(const std::string& art_path, const char* isa) const {
+    bool PatchoatBootImage(const std::string& output_dir, const char* isa) const {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
 
         std::vector<std::string> cmd;
         cmd.push_back("/system/bin/patchoat");
 
         cmd.push_back("--input-image-location=/system/framework/boot.art");
-        cmd.push_back(StringPrintf("--output-image-file=%s", art_path.c_str()));
+        cmd.push_back(StringPrintf("--output-image-directory=%s", output_dir.c_str()));
 
         cmd.push_back(StringPrintf("--instruction-set=%s", isa));
 
@@ -879,17 +538,18 @@
         //       jar content must be exactly the same).
 
         //       (This is ugly as it's the only thing where we need to understand the contents
-        //        of package_parameters_, but it beats postponing the decision or using the call-
+        //        of parameters_, but it beats postponing the decision or using the call-
         //        backs to do weird things.)
-        const char* apk_path = package_parameters_.apk_path;
+        const char* apk_path = parameters_.apk_path;
         CHECK(apk_path != nullptr);
-        if (StartsWith(apk_path, android_root_.c_str())) {
+        if (StartsWith(apk_path, android_root_)) {
             const char* last_slash = strrchr(apk_path, '/');
             if (last_slash != nullptr) {
                 std::string path(apk_path, last_slash - apk_path + 1);
                 CHECK(EndsWith(path, "/"));
                 path = path + "oat";
                 if (access(path.c_str(), F_OK) == 0) {
+                    LOG(INFO) << "Skipping A/B OTA preopt of already preopted package " << apk_path;
                     return true;
                 }
             }
@@ -901,27 +561,34 @@
         // this tool will wipe the OTA artifact cache and try again (for robustness after
         // a failed OTA with remaining cache artifacts).
         if (access(apk_path, F_OK) != 0) {
-            LOG(WARNING) << "Skipping preopt of non-existing package " << apk_path;
+            LOG(WARNING) << "Skipping A/B OTA preopt of non-existing package " << apk_path;
             return true;
         }
 
         return false;
     }
 
-    // Run dexopt with the parameters of package_parameters_.
+    // Run dexopt with the parameters of parameters_.
+    // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
-        return dexopt(package_parameters_.apk_path,
-                      package_parameters_.uid,
-                      package_parameters_.pkgName,
-                      package_parameters_.instruction_set,
-                      package_parameters_.dexopt_needed,
-                      package_parameters_.oat_dir,
-                      package_parameters_.dexopt_flags,
-                      package_parameters_.compiler_filter,
-                      package_parameters_.volume_uuid,
-                      package_parameters_.shared_libraries,
-                      package_parameters_.se_info,
-                      package_parameters_.downgrade);
+        std::string dummy;
+        return dexopt(parameters_.apk_path,
+                      parameters_.uid,
+                      parameters_.pkgName,
+                      parameters_.instruction_set,
+                      parameters_.dexopt_needed,
+                      parameters_.oat_dir,
+                      parameters_.dexopt_flags,
+                      parameters_.compiler_filter,
+                      parameters_.volume_uuid,
+                      parameters_.shared_libraries,
+                      parameters_.se_info,
+                      parameters_.downgrade,
+                      parameters_.target_sdk_version,
+                      parameters_.profile_name,
+                      parameters_.dex_metadata_path,
+                      parameters_.compilation_reason,
+                      &dummy);
     }
 
     int RunPreopt() {
@@ -952,12 +619,12 @@
 
         // If this was a profile-guided run, we may have profile version issues. Try to downgrade,
         // if possible.
-        if ((package_parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
+        if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
             return dexopt_result;
         }
 
         LOG(WARNING) << "Downgrading compiler filter in an attempt to progress compilation";
-        package_parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
+        parameters_.dexopt_flags &= ~DEXOPT_PROFILE_GUIDED;
         return Dexopt();
     }
 
@@ -1082,13 +749,12 @@
     SystemProperties system_properties_;
 
     // Some select properties that are always needed.
-    std::string target_slot_;
     std::string android_root_;
     std::string android_data_;
     std::string boot_classpath_;
     std::string asec_mountpoint_;
 
-    Parameters package_parameters_;
+    OTAPreoptParameters parameters_;
 
     // Store environment values we need to set.
     std::vector<std::string> environ_;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 2030997..e90cf3b 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -59,6 +59,12 @@
 // The file descriptor denoted by status-fd will be closed. The rest of the parameters will
 // be passed on to otapreopt in the chroot.
 static int otapreopt_chroot(const int argc, char **arg) {
+    // Validate arguments
+    // We need the command, status channel and target slot, at a minimum.
+    if(argc < 3) {
+        PLOG(ERROR) << "Not enough arguments.";
+        exit(208);
+    }
     // Close all file descriptors. They are coming from the caller, we do not want to pass them
     // on across our fork/exec into a different domain.
     // 1) Default descriptors.
@@ -108,14 +114,29 @@
         LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
         exit(207);
     }
-    std::string vendor_partition = StringPrintf("/dev/block/bootdevice/by-name/vendor%s",
-                                                arg[2]);
-    int vendor_result = mount(vendor_partition.c_str(),
-                              "/postinstall/vendor",
-                              "ext4",
-                              MS_RDONLY,
-                              /* data */ nullptr);
-    UNUSED(vendor_result);
+    {
+      std::string vendor_partition = StringPrintf("/dev/block/by-name/vendor%s",
+                                                  arg[2]);
+      int vendor_result = mount(vendor_partition.c_str(),
+                                "/postinstall/vendor",
+                                "ext4",
+                                MS_RDONLY,
+                                /* data */ nullptr);
+      UNUSED(vendor_result);
+    }
+
+    // Try to mount the product partition. update_engine doesn't do this for us, but we
+    // want it for product APKs. Same notes as vendor above.
+    {
+      std::string product_partition = StringPrintf("/dev/block/by-name/product%s",
+                                                   arg[2]);
+      int product_result = mount(product_partition.c_str(),
+                                 "/postinstall/product",
+                                 "ext4",
+                                 MS_RDONLY,
+                                 /* data */ nullptr);
+      UNUSED(product_result);
+    }
 
     // Chdir into /postinstall.
     if (chdir("/postinstall") != 0) {
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
new file mode 100644
index 0000000..cf3de01
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -0,0 +1,367 @@
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "otapreopt_parameters.h"
+
+#include <android-base/logging.h>
+
+#include "dexopt.h"
+#include "installd_constants.h"
+#include "otapreopt_utils.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "otapreopt"
+#endif
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+    if (strcmp(in, "true") == 0) {
+        return true;
+    }
+    return false;
+}
+
+static const char* ParseNull(const char* arg) {
+    return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+static bool ParseUInt(const char* in, uint32_t* out) {
+    char* end;
+    long long int result = strtoll(in, &end, 0);
+    if (in == end || *end != '\0') {
+        return false;
+    }
+    if (result < std::numeric_limits<uint32_t>::min() ||
+            std::numeric_limits<uint32_t>::max() < result) {
+        return false;
+    }
+    *out = static_cast<uint32_t>(result);
+    return true;
+}
+
+bool OTAPreoptParameters::ReadArguments(int argc, const char** argv) {
+    // Expected command line:
+    //   target-slot [version] dexopt {DEXOPT_PARAMETERS}
+
+    const char* target_slot_arg = argv[1];
+    if (target_slot_arg == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    // Sanitize value. Only allow (a-zA-Z0-9_)+.
+    target_slot = target_slot_arg;
+    if (!ValidateTargetSlotSuffix(target_slot)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << target_slot;
+        return false;
+    }
+
+    // Check for version or "dexopt" next.
+    if (argv[2] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+
+    if (std::string("dexopt").compare(argv[2]) == 0) {
+        // This is version 1 (N) or pre-versioning version 2.
+        constexpr int kV2ArgCount =   1   // "otapreopt"
+                                    + 1   // slot
+                                    + 1   // "dexopt"
+                                    + 1   // apk_path
+                                    + 1   // uid
+                                    + 1   // pkg
+                                    + 1   // isa
+                                    + 1   // dexopt_needed
+                                    + 1   // oat_dir
+                                    + 1   // dexopt_flags
+                                    + 1   // filter
+                                    + 1   // volume
+                                    + 1   // libs
+                                    + 1;  // seinfo
+        if (argc == kV2ArgCount) {
+            return ReadArgumentsPostV1(2, argv, false);
+        } else {
+            return ReadArgumentsV1(argv);
+        }
+    }
+
+    uint32_t version;
+    if (!ParseUInt(argv[2], &version)) {
+        LOG(ERROR) << "Could not parse version: " << argv[2];
+        return false;
+    }
+
+    return ReadArgumentsPostV1(version, argv, true);
+}
+
+static int ReplaceMask(int input, int old_mask, int new_mask) {
+    return (input & old_mask) != 0 ? new_mask : 0;
+}
+
+void OTAPreoptParameters::SetDefaultsForPostV1Arguments() {
+    // Set se_info to null. It is only relevant for secondary dex files, which we won't
+    // receive from a v1 A side.
+    se_info = nullptr;
+
+    // Set downgrade to false. It is only relevant when downgrading compiler
+    // filter, which is not the case during ota.
+    downgrade = false;
+
+    // Set target_sdk_version to 0, ie the platform SDK version. This is
+    // conservative and may force some classes to verify at runtime.
+    target_sdk_version = 0;
+
+    // Set the profile name to the primary apk profile.
+    profile_name = "primary.prof";
+
+    // By default we don't have a dex metadata file.
+    dex_metadata_path = nullptr;
+
+    // The compilation reason is ab-ota (match the system property pm.dexopt.ab-ota)
+    compilation_reason = "ab-ota";
+
+    // Flag is enabled by default for A/B otas.
+    dexopt_flags = DEXOPT_GENERATE_COMPACT_DEX;
+}
+
+bool OTAPreoptParameters::ReadArgumentsV1(const char** argv) {
+    // Check for "dexopt".
+    if (argv[2] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    if (std::string("dexopt").compare(argv[2]) != 0) {
+        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[2];
+        return false;
+    }
+
+    SetDefaultsForPostV1Arguments();
+
+    size_t param_index = 0;
+    for (;; ++param_index) {
+        const char* param = argv[3 + param_index];
+        if (param == nullptr) {
+            break;
+        }
+
+        switch (param_index) {
+            case 0:
+                apk_path = param;
+                break;
+
+            case 1:
+                uid = atoi(param);
+                break;
+
+            case 2:
+                pkgName = param;
+                break;
+
+            case 3:
+                instruction_set = param;
+                break;
+
+            case 4: {
+                // Version 1 had:
+                //   DEXOPT_DEX2OAT_NEEDED       = 1
+                //   DEXOPT_PATCHOAT_NEEDED      = 2
+                //   DEXOPT_SELF_PATCHOAT_NEEDED = 3
+                // We will simply use DEX2OAT_FROM_SCRATCH.
+                dexopt_needed = DEX2OAT_FROM_SCRATCH;
+                break;
+            }
+
+            case 5:
+                oat_dir = param;
+                break;
+
+            case 6: {
+                // Version 1 had:
+                constexpr int OLD_DEXOPT_PUBLIC         = 1 << 1;
+                // Note: DEXOPT_SAFEMODE has been removed.
+                // constexpr int OLD_DEXOPT_SAFEMODE       = 1 << 2;
+                constexpr int OLD_DEXOPT_DEBUGGABLE     = 1 << 3;
+                constexpr int OLD_DEXOPT_BOOTCOMPLETE   = 1 << 4;
+                constexpr int OLD_DEXOPT_PROFILE_GUIDED = 1 << 5;
+                constexpr int OLD_DEXOPT_OTA            = 1 << 6;
+                static_assert(DEXOPT_GENERATE_COMPACT_DEX > OLD_DEXOPT_OTA, "must not overlap");
+                int input = atoi(param);
+                dexopt_flags |=
+                        ReplaceMask(input, OLD_DEXOPT_PUBLIC, DEXOPT_PUBLIC) |
+                        ReplaceMask(input, OLD_DEXOPT_DEBUGGABLE, DEXOPT_DEBUGGABLE) |
+                        ReplaceMask(input, OLD_DEXOPT_BOOTCOMPLETE, DEXOPT_BOOTCOMPLETE) |
+                        ReplaceMask(input, OLD_DEXOPT_PROFILE_GUIDED, DEXOPT_PROFILE_GUIDED) |
+                        ReplaceMask(input, OLD_DEXOPT_OTA, 0);
+                break;
+            }
+
+            case 7:
+                compiler_filter = param;
+                break;
+
+            case 8:
+                volume_uuid = ParseNull(param);
+                break;
+
+            case 9:
+                shared_libraries = ParseNull(param);
+                break;
+
+            default:
+                LOG(ERROR) << "Too many arguments, got " << param;
+                return false;
+        }
+    }
+
+    if (param_index != 10) {
+        LOG(ERROR) << "Not enough parameters";
+        return false;
+    }
+
+    return true;
+}
+
+bool OTAPreoptParameters::ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned) {
+    size_t num_args_expected = 0;
+    switch (version) {
+        case 2: num_args_expected = 11; break;
+        case 3: num_args_expected = 12; break;
+        case 4: num_args_expected = 13; break;
+        case 5: num_args_expected = 14; break;
+        case 6: num_args_expected = 15; break;
+        case 7:
+        // Version 8 adds a new dexopt flag: DEXOPT_GENERATE_COMPACT_DEX
+        case 8: num_args_expected = 16; break;
+        // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE
+        case 9: num_args_expected = 16; break;
+        default:
+            LOG(ERROR) << "Don't know how to read arguments for version " << version;
+            return false;
+    }
+    size_t dexopt_index = versioned ? 3 : 2;
+
+    // Check for "dexopt".
+    if (argv[dexopt_index] == nullptr) {
+        LOG(ERROR) << "Missing parameters";
+        return false;
+    }
+    if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+        LOG(ERROR) << "Expected \"dexopt\" but found: " << argv[dexopt_index];
+        return false;
+    }
+
+    // Validate the number of arguments.
+    size_t num_args_actual = 0;
+    while (argv[dexopt_index + 1 + num_args_actual] != nullptr) {
+        num_args_actual++;
+    }
+
+    if (num_args_actual != num_args_expected) {
+        LOG(ERROR) << "Invalid number of arguments. expected="
+                << num_args_expected << " actual=" << num_args_actual;
+        return false;
+    }
+
+    // The number of arguments is OK.
+    // Configure the default values for the parameters that were added after V1.
+    // The default values will be overwritten in case they are passed as arguments.
+    SetDefaultsForPostV1Arguments();
+
+    for (size_t param_index = 0; param_index < num_args_actual; ++param_index) {
+        const char* param = argv[dexopt_index + 1 + param_index];
+        switch (param_index) {
+            case 0:
+                apk_path = param;
+                break;
+
+            case 1:
+                uid = atoi(param);
+                break;
+
+            case 2:
+                pkgName = param;
+                break;
+
+            case 3:
+                instruction_set = param;
+                break;
+
+            case 4:
+                dexopt_needed = atoi(param);
+                break;
+
+            case 5:
+                oat_dir = param;
+                break;
+
+            case 6:
+                dexopt_flags = atoi(param);
+                // Add CompactDex generation flag for versions less than 8 since it wasn't passed
+                // from the package manager. Only conditionally set the flag here so that it can
+                // be fully controlled by the package manager.
+                dexopt_flags |= (version < 8) ? DEXOPT_GENERATE_COMPACT_DEX : 0u;
+                break;
+
+            case 7:
+                compiler_filter = param;
+                break;
+
+            case 8:
+                volume_uuid = ParseNull(param);
+                break;
+
+            case 9:
+                shared_libraries = ParseNull(param);
+                break;
+
+            case 10:
+                se_info = ParseNull(param);
+                break;
+
+            case 11:
+                downgrade = ParseBool(param);
+                break;
+
+            case 12:
+                target_sdk_version = atoi(param);
+                break;
+
+            case 13:
+                profile_name = ParseNull(param);
+                break;
+
+            case 14:
+                dex_metadata_path = ParseNull(param);
+                break;
+
+            case 15:
+                compilation_reason = ParseNull(param);
+                break;
+
+            default:
+                LOG(FATAL) << "Should not get here. Did you call ReadArguments "
+                        << "with the right expectation? index=" << param_index
+                        << " num_args=" << num_args_actual;
+                return false;
+        }
+    }
+
+    return true;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/otapreopt_parameters.h b/cmds/installd/otapreopt_parameters.h
new file mode 100644
index 0000000..a2f6e44
--- /dev/null
+++ b/cmds/installd/otapreopt_parameters.h
@@ -0,0 +1,61 @@
+/*
+ ** Copyright 2018, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef OTAPREOPT_PARAMETERS_H_
+#define OTAPREOPT_PARAMETERS_H_
+
+#include <string>
+#include <sys/types.h>
+
+namespace android {
+namespace installd {
+
+class OTAPreoptParameters {
+  public:
+    bool ReadArguments(int argc, const char** argv);
+
+  private:
+    bool ReadArgumentsV1(const char** argv);
+    bool ReadArgumentsPostV1(uint32_t version, const char** argv, bool versioned);
+
+    void SetDefaultsForPostV1Arguments();
+    const char* apk_path;
+    uid_t uid;
+    const char* pkgName;
+    const char* instruction_set;
+    int dexopt_needed;
+    const char* oat_dir;
+    int dexopt_flags;
+    const char* compiler_filter;
+    const char* volume_uuid;
+    const char* shared_libraries;
+    const char* se_info;
+    bool downgrade;
+    int target_sdk_version;
+    const char* profile_name;
+    const char* dex_metadata_path;
+    const char* compilation_reason;
+
+    std::string target_slot;
+
+    friend class OTAPreoptService;
+    friend class OTAPreoptTest;
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  //  OTAPREOPT_PARAMETERS_H_
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 630c1f3..7438d3d 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -3,15 +3,16 @@
     name: "installd_utils_test",
     clang: true,
     srcs: ["installd_utils_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libbase",
-        "liblog",
         "libutils",
         "libcutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
     ],
 }
 
@@ -19,18 +20,20 @@
     name: "installd_cache_test",
     clang: true,
     srcs: ["installd_cache_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
-        "liblog",
-        "liblogwrap",
         "libselinux",
         "libutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
+        "liblogwrap",
     ],
 }
 
@@ -38,17 +41,57 @@
     name: "installd_service_test",
     clang: true,
     srcs: ["installd_service_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
-        "liblog",
-        "liblogwrap",
         "libselinux",
         "libutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
+        "liblogwrap",
     ],
 }
+
+cc_test {
+    name: "installd_dexopt_test",
+    clang: true,
+    srcs: ["installd_dexopt_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libselinux",
+        "libutils",
+    ],
+    static_libs: [
+        "libdiskusage",
+        "libinstalld",
+        "liblog",
+        "liblogwrap",
+    ],
+}
+
+cc_test {
+    name: "installd_otapreopt_test",
+    clang: true,
+    srcs: ["installd_otapreopt_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "liblog",
+        "libotapreoptparameters"
+    ],
+}
+
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
new file mode 100644
index 0000000..279bce8
--- /dev/null
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+
+#include <cutils/properties.h>
+
+#include <gtest/gtest.h>
+
+#include <selinux/android.h>
+#include <selinux/avc.h>
+
+#include "dexopt.h"
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "tests/test_utils.h"
+#include "utils.h"
+
+using android::base::ReadFully;
+using android::base::unique_fd;
+
+namespace android {
+namespace installd {
+
+// TODO(calin): try to dedup this code.
+#if defined(__arm__)
+static const std::string kRuntimeIsa = "arm";
+#elif defined(__aarch64__)
+static const std::string kRuntimeIsa = "arm64";
+#elif defined(__mips__) && !defined(__LP64__)
+static const std::string kRuntimeIsa = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const std::string kRuntimeIsa = "mips64";
+#elif defined(__i386__)
+static const std::string kRuntimeIsa = "x86";
+#elif defined(__x86_64__)
+static const std::string kRuntimeIsa = "x86_64";
+#else
+static const std::string kRuntimeIsa = "none";
+#endif
+
+int get_property(const char *key, char *value, const char *default_value) {
+    return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+        const char *instruction_set) {
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
+}
+
+static void run_cmd(const std::string& cmd) {
+    system(cmd.c_str());
+}
+
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+    ::mkdir(path.c_str(), mode);
+    ::chown(path.c_str(), owner, group);
+    ::chmod(path.c_str(), mode);
+}
+
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
+    va_list ap;
+    int priority;
+
+    switch (type) {
+        case SELINUX_WARNING:
+            priority = ANDROID_LOG_WARN;
+            break;
+        case SELINUX_INFO:
+            priority = ANDROID_LOG_INFO;
+            break;
+        default:
+            priority = ANDROID_LOG_ERROR;
+            break;
+    }
+    va_start(ap, fmt);
+    LOG_PRI_VA(priority, "SELinux", fmt, ap);
+    va_end(ap);
+    return 0;
+}
+
+static bool init_selinux() {
+    int selinux_enabled = (is_selinux_enabled() > 0);
+
+    union selinux_callback cb;
+    cb.func_log = log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+
+    if (selinux_enabled && selinux_status_open(true) < 0) {
+        LOG(ERROR) << "Could not open selinux status; exiting";
+        return false;
+    }
+
+    return true;
+}
+
+// Base64 encoding of a simple dex files with 2 methods.
+static const char kDexFile[] =
+    "UEsDBBQAAAAIAOiOYUs9y6BLCgEAABQCAAALABwAY2xhc3Nlcy5kZXhVVAkAA/Ns+lkOHv1ZdXgL"
+    "AAEEI+UCAASIEwAAS0mt4DIwNmX4qpn7j/2wA7v7N+ZvoQpCJRlVx5SWa4YaiDAxMBQwMDBUhJkI"
+    "MUBBDyMDAzsDRJwFxAdioBDDHAYEYAbiFUAM1M5wAIhFGCGKDIDYAogdgNgDiH2BOAiI0xghekDm"
+    "sQIxGxQzM6ACRijNhCbOhCZfyohdPYyuh8szgtVkMkLsLhAAqeCDi+ejibPZZOZlltgxsDnqZSWW"
+    "JTKwOUFoZh9HayDhZM0g5AMS0M9JzEvX90/KSk0usWZgDAMaws5nAyXBzmpoYGlgAjsAyJoBMp0b"
+    "zQ8gGhbOTEhhzYwU3qxIYc2GFN6MClC/AhUyKUDMAYU9M1Qc5F8GKBscVgIQM0FxCwBQSwECHgMU"
+    "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
+    "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
+
+
+class DexoptTest : public testing::Test {
+protected:
+    static constexpr bool kDebug = false;
+    static constexpr uid_t kSystemUid = 1000;
+    static constexpr uid_t kSystemGid = 1000;
+    static constexpr int32_t kOSdkVersion = 25;
+    static constexpr int32_t kAppDataFlags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+    static constexpr int32_t kTestUserId = 0;
+    static constexpr uid_t kTestAppId = 19999;
+
+    const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+    const uid_t kTestAppGid = multiuser_get_shared_gid(kTestUserId, kTestAppId);
+
+    InstalldNativeService* service_;
+    std::unique_ptr<std::string> volume_uuid_;
+    std::string package_name_;
+    std::string apk_path_;
+    std::string app_apk_dir_;
+    std::string app_private_dir_ce_;
+    std::string app_private_dir_de_;
+    std::string se_info_;
+    std::string app_oat_dir_;
+
+    int64_t ce_data_inode_;
+
+    std::string secondary_dex_ce_;
+    std::string secondary_dex_ce_link_;
+    std::string secondary_dex_de_;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+        // Initialize the globals holding the file system main paths (/data/, /system/ etc..).
+        // This is needed in order to compute the application and profile paths.
+        ASSERT_TRUE(init_globals_from_data_and_root());
+        // Initialize selinux log callbacks.
+        // This ensures that selinux is up and running and re-directs the selinux messages
+        // to logcat (in order to make it easier to investigate test results).
+        ASSERT_TRUE(init_selinux());
+        service_ = new InstalldNativeService();
+
+        volume_uuid_ = nullptr;
+        package_name_ = "com.installd.test.dexopt";
+        se_info_ = "default";
+        app_apk_dir_ = android_app_dir + package_name_;
+
+        create_mock_app();
+    }
+
+    virtual void TearDown() {
+        if (!kDebug) {
+            service_->destroyAppData(
+                volume_uuid_, package_name_, kTestUserId, kAppDataFlags, ce_data_inode_);
+            run_cmd("rm -rf " + app_apk_dir_);
+            run_cmd("rm -rf " + app_private_dir_ce_);
+            run_cmd("rm -rf " + app_private_dir_de_);
+        }
+        delete service_;
+    }
+
+    void create_mock_app() {
+        // Create the oat dir.
+        app_oat_dir_ = app_apk_dir_ + "/oat";
+        mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755);
+        service_->createOatDir(app_oat_dir_, kRuntimeIsa);
+
+        // Copy the primary apk.
+        apk_path_ = app_apk_dir_ + "/base.jar";
+        ASSERT_TRUE(WriteBase64ToFile(kDexFile, apk_path_, kSystemUid, kSystemGid, 0644));
+
+        // Create the app user data.
+        ASSERT_TRUE(service_->createAppData(
+            volume_uuid_,
+            package_name_,
+            kTestUserId,
+            kAppDataFlags,
+            kTestAppUid,
+            se_info_,
+            kOSdkVersion,
+            &ce_data_inode_).isOk());
+
+        // Create a secondary dex file on CE storage
+        const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str();
+        app_private_dir_ce_ = create_data_user_ce_package_path(
+                volume_uuid_cstr, kTestUserId, package_name_.c_str());
+        secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar";
+        ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_ce_, kTestAppUid, kTestAppGid, 0600));
+        std::string app_private_dir_ce_link = create_data_user_ce_package_path_as_user_link(
+                volume_uuid_cstr, kTestUserId, package_name_.c_str());
+        secondary_dex_ce_link_ = app_private_dir_ce_link + "/secondary_ce.jar";
+
+        // Create a secondary dex file on DE storage.
+        app_private_dir_de_ = create_data_user_de_package_path(
+                volume_uuid_cstr, kTestUserId, package_name_.c_str());
+        secondary_dex_de_ = app_private_dir_de_ + "/secondary_de.jar";
+        ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_de_, kTestAppUid, kTestAppGid, 0600));
+
+        // Fix app data uid.
+        ASSERT_TRUE(service_->fixupAppData(volume_uuid_, kTestUserId).isOk());
+    }
+
+
+    std::string GetSecondaryDexArtifact(const std::string& path, const std::string& type) {
+        std::string::size_type end = path.rfind('.');
+        std::string::size_type start = path.rfind('/', end);
+        return path.substr(0, start) + "/oat/" + kRuntimeIsa + "/" +
+                path.substr(start + 1, end - start) + type;
+    }
+
+    void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
+            bool should_binder_call_succeed, bool should_dex_be_compiled = true,
+            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
+        if (uid == -1) {
+            uid = kTestAppUid;
+        }
+        std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
+        int32_t dexopt_needed = 0;  // does not matter;
+        std::unique_ptr<std::string> out_path = nullptr;  // does not matter
+        int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
+        std::string compiler_filter = "speed-profile";
+        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+        std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
+        bool downgrade = false;
+        int32_t target_sdk_version = 0;  // default
+        std::unique_ptr<std::string> profile_name_ptr = nullptr;
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
+        std::unique_ptr<std::string> compilation_reason_ptr = nullptr;
+
+        binder::Status result = service_->dexopt(path,
+                                                 uid,
+                                                 package_name_ptr,
+                                                 kRuntimeIsa,
+                                                 dexopt_needed,
+                                                 out_path,
+                                                 dex_flags,
+                                                 compiler_filter,
+                                                 volume_uuid_,
+                                                 class_loader_context_ptr,
+                                                 se_info_ptr,
+                                                 downgrade,
+                                                 target_sdk_version,
+                                                 profile_name_ptr,
+                                                 dm_path_ptr,
+                                                 compilation_reason_ptr);
+        ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+        int expected_access = should_dex_be_compiled ? 0 : -1;
+        std::string odex = GetSecondaryDexArtifact(path, "odex");
+        std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+        std::string art = GetSecondaryDexArtifact(path, "art");
+        ASSERT_EQ(expected_access, access(odex.c_str(), R_OK));
+        ASSERT_EQ(expected_access, access(vdex.c_str(), R_OK));
+        ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
+    }
+
+    void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
+            bool should_binder_call_succeed, bool should_dex_exist, bool should_dex_be_deleted,
+            int32_t uid = -1, std::string* package_override = nullptr) {
+        if (uid == -1) {
+            uid = kTestAppUid;
+        }
+        std::vector<std::string> isas;
+        isas.push_back(kRuntimeIsa);
+        bool out_secondary_dex_exists = false;
+        binder::Status result = service_->reconcileSecondaryDexFile(
+            path,
+            package_override == nullptr ? package_name_ : *package_override,
+            uid,
+            isas,
+            volume_uuid_,
+            storage_flag,
+            &out_secondary_dex_exists);
+
+        ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+        ASSERT_EQ(should_dex_exist, out_secondary_dex_exists);
+
+        int expected_access = should_dex_be_deleted ? -1 : 0;
+        std::string odex = GetSecondaryDexArtifact(path, "odex");
+        std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+        std::string art = GetSecondaryDexArtifact(path, "art");
+        ASSERT_EQ(expected_access, access(odex.c_str(), F_OK));
+        ASSERT_EQ(expected_access, access(vdex.c_str(), F_OK));
+        ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
+    }
+
+    void CheckFileAccess(const std::string& file, uid_t uid, gid_t gid, mode_t mode) {
+        struct stat st;
+        ASSERT_EQ(0, stat(file.c_str(), &st));
+        ASSERT_EQ(uid, st.st_uid);
+        ASSERT_EQ(gid, st.st_gid);
+        ASSERT_EQ(mode, st.st_mode);
+    }
+
+    void CompilePrimaryDexOk(std::string compiler_filter,
+                             int32_t dex_flags,
+                             const char* oat_dir,
+                             int32_t uid,
+                             int32_t dexopt_needed,
+                             binder::Status* binder_result = nullptr,
+                             const char* dm_path = nullptr,
+                             bool downgrade = false) {
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          true,
+                          binder_result);
+    }
+
+    void CompilePrimaryDexFail(std::string compiler_filter,
+                               int32_t dex_flags,
+                               const char* oat_dir,
+                               int32_t uid,
+                               int32_t dexopt_needed,
+                               binder::Status* binder_result = nullptr,
+                               const char* dm_path = nullptr,
+                               bool downgrade = false) {
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          false,
+                          binder_result);
+    }
+
+    void CompilePrimaryDex(std::string compiler_filter,
+                           int32_t dex_flags,
+                           const char* oat_dir,
+                           int32_t uid,
+                           int32_t dexopt_needed,
+                           const char* dm_path,
+                           bool downgrade,
+                           bool should_binder_call_succeed,
+                           /*out */ binder::Status* binder_result) {
+        std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
+        std::unique_ptr<std::string> out_path(
+                oat_dir == nullptr ? nullptr : new std::string(oat_dir));
+        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+        std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
+        int32_t target_sdk_version = 0;  // default
+        std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
+        std::unique_ptr<std::string> dm_path_ptr = nullptr;
+        if (dm_path != nullptr) {
+            dm_path_ptr.reset(new std::string(dm_path));
+        }
+        std::unique_ptr<std::string> compilation_reason_ptr(new std::string("test-reason"));
+
+        bool prof_result;
+        binder::Status prof_binder_result = service_->prepareAppProfile(
+                package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
+                /*dex_metadata*/ nullptr, &prof_result);
+
+        ASSERT_TRUE(prof_binder_result.isOk()) << prof_binder_result.toString8().c_str();
+        ASSERT_TRUE(prof_result);
+
+        binder::Status result = service_->dexopt(apk_path_,
+                                                 uid,
+                                                 package_name_ptr,
+                                                 kRuntimeIsa,
+                                                 dexopt_needed,
+                                                 out_path,
+                                                 dex_flags,
+                                                 compiler_filter,
+                                                 volume_uuid_,
+                                                 class_loader_context_ptr,
+                                                 se_info_ptr,
+                                                 downgrade,
+                                                 target_sdk_version,
+                                                 profile_name_ptr,
+                                                 dm_path_ptr,
+                                                 compilation_reason_ptr);
+        ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+
+        if (!should_binder_call_succeed) {
+            if (binder_result != nullptr) {
+                *binder_result = result;
+            }
+            return;
+        }
+        // Check the access to the compiler output.
+        //  - speed-profile artifacts are not world-wide readable.
+        //  - files are owned by the system uid.
+        std::string odex = GetPrimaryDexArtifact(oat_dir, apk_path_, "odex");
+        std::string vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex");
+        std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art");
+
+        bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
+        mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
+        CheckFileAccess(odex, kSystemUid, uid, mode);
+        CheckFileAccess(vdex, kSystemUid, uid, mode);
+
+        if (compiler_filter == "speed-profile") {
+            CheckFileAccess(art, kSystemUid, uid, mode);
+        }
+        if (binder_result != nullptr) {
+            *binder_result = result;
+        }
+    }
+
+    std::string GetPrimaryDexArtifact(const char* oat_dir,
+                                      const std::string& dex_path,
+                                      const std::string& type) {
+        if (oat_dir == nullptr) {
+            std::string path = dex_path;
+            for (auto it = path.begin() + 1; it < path.end(); ++it) {
+                if (*it == '/') {
+                    *it = '@';
+                }
+            }
+            return android_data_dir + DALVIK_CACHE + '/' + kRuntimeIsa + "/" + path
+                    + "@classes.dex";
+        } else {
+            std::string::size_type name_end = dex_path.rfind('.');
+            std::string::size_type name_start = dex_path.rfind('/');
+            return std::string(oat_dir) + "/" + kRuntimeIsa + "/" +
+                    dex_path.substr(name_start + 1, name_end - name_start) + type;
+        }
+    }
+};
+
+
+TEST_F(DexoptTest, DexoptSecondaryCe) {
+    LOG(INFO) << "DexoptSecondaryCe";
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+        /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryCeLink) {
+    LOG(INFO) << "DexoptSecondaryCeLink";
+    CompileSecondaryDex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
+        /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryDe) {
+    LOG(INFO) << "DexoptSecondaryDe";
+    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+        /*binder_ok*/ true, /*compile_ok*/ true);
+}
+
+TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
+    LOG(INFO) << "DexoptSecondaryDoesNotExist";
+    // If the file validates but does not exist we do not treat it as an error.
+    binder::Status status;
+    CompileSecondaryDex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
+        /*binder_ok*/ true,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(), "No error");
+}
+
+TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
+    LOG(INFO) << "DexoptSecondaryStorageValidationError";
+    binder::Status status;
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+}
+
+TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
+    LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
+    binder::Status status;
+    CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+}
+
+TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
+    LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
+    binder::Status status;
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+        /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
+    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
+}
+
+TEST_F(DexoptTest, DexoptPrimaryPublic) {
+    LOG(INFO) << "DexoptPrimaryPublic";
+    CompilePrimaryDexOk("verify",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+}
+
+TEST_F(DexoptTest, DexoptPrimaryFailedInvalidFilter) {
+    LOG(INFO) << "DexoptPrimaryFailedInvalidFilter";
+    binder::Status status;
+    CompilePrimaryDexFail("awesome-filter",
+                          DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
+                          app_oat_dir_.c_str(),
+                          kTestAppGid,
+                          DEX2OAT_FROM_SCRATCH,
+                          &status);
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): \'256: Dex2oat invocation for "
+                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
+}
+
+TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
+    LOG(INFO) << "DexoptPrimaryProfileNonPublic";
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+}
+
+TEST_F(DexoptTest, DexoptPrimaryProfilePublic) {
+    LOG(INFO) << "DexoptPrimaryProfilePublic";
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+}
+
+TEST_F(DexoptTest, DexoptPrimaryBackgroundOk) {
+    LOG(INFO) << "DexoptPrimaryBackgroundOk";
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+}
+
+class PrimaryDexReCompilationTest : public DexoptTest {
+  public:
+    virtual void SetUp() {
+        DexoptTest::SetUp();
+        CompilePrimaryDexOk("verify",
+                            DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+                            app_oat_dir_.c_str(),
+                            kTestAppGid,
+                            DEX2OAT_FROM_SCRATCH);
+        std::string odex = GetSecondaryDexArtifact(apk_path_, "odex");
+        std::string vdex = GetSecondaryDexArtifact(apk_path_, "vdex");
+
+        first_compilation_odex_fd_.reset(open(odex.c_str(), O_RDONLY));
+        first_compilation_vdex_fd_.reset(open(vdex.c_str(), O_RDONLY));
+    }
+
+    virtual void TearDown() {
+        first_compilation_odex_fd_.reset(-1);
+        first_compilation_vdex_fd_.reset(-1);
+        DexoptTest::TearDown();
+    }
+
+  protected:
+    unique_fd first_compilation_odex_fd_;
+    unique_fd first_compilation_vdex_fd_;
+};
+
+TEST_F(PrimaryDexReCompilationTest, DexoptPrimaryUpdateInPlaceVdex) {
+    LOG(INFO) << "DexoptPrimaryUpdateInPlaceVdex";
+
+    CompilePrimaryDexOk("verify",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PUBLIC,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FOR_BOOT_IMAGE);
+}
+
+class ReconcileTest : public DexoptTest {
+    virtual void SetUp() {
+        DexoptTest::SetUp();
+        CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+            /*binder_ok*/ true, /*compile_ok*/ true);
+        CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+            /*binder_ok*/ true, /*compile_ok*/ true);
+    }
+};
+
+TEST_F(ReconcileTest, ReconcileSecondaryCeExists) {
+    LOG(INFO) << "ReconcileSecondaryCeExists";
+    reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+        /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryCeLinkExists) {
+    LOG(INFO) << "ReconcileSecondaryCeLinkExists";
+    reconcile_secondary_dex(secondary_dex_ce_link_, FLAG_STORAGE_CE,
+        /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryDeExists) {
+    LOG(INFO) << "ReconcileSecondaryDeExists";
+    reconcile_secondary_dex(secondary_dex_de_, FLAG_STORAGE_DE,
+        /*binder_ok*/ true, /*dex_ok */ true, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryDeDoesNotExist) {
+    LOG(INFO) << "ReconcileSecondaryDeDoesNotExist";
+    run_cmd("rm -rf " + secondary_dex_de_);
+    reconcile_secondary_dex(secondary_dex_de_, FLAG_STORAGE_DE,
+        /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ true);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryStorageValidationError) {
+    // Validation errors will not clean the odex/vdex/art files but will mark
+    // the file as non existent so that the PM knows it should purge it from its
+    // records.
+    LOG(INFO) << "ReconcileSecondaryStorageValidationError";
+    reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_DE,
+        /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryAppOwnershipValidationError) {
+    LOG(INFO) << "ReconcileSecondaryAppOwnershipValidationError";
+    // Attempt to reconcile the dex files of the test app from a different app.
+    std::string another_app = "another.app";
+    reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+        /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid, &another_app);
+}
+
+TEST_F(ReconcileTest, ReconcileSecondaryAcessViaDifferentUidError) {
+    LOG(INFO) << "ReconcileSecondaryAcessViaDifferentUidError";
+    reconcile_secondary_dex(secondary_dex_ce_, FLAG_STORAGE_CE,
+        /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid);
+}
+
+class ProfileTest : public DexoptTest {
+  protected:
+    std::string cur_profile_;
+    std::string ref_profile_;
+    std::string snap_profile_;
+
+    static constexpr const char* kPrimaryProfile = "primary.prof";
+
+    virtual void SetUp() {
+        DexoptTest::SetUp();
+        cur_profile_ = create_current_profile_path(
+                kTestUserId, package_name_, kPrimaryProfile, /*is_secondary_dex*/ false);
+        ref_profile_ = create_reference_profile_path(package_name_, kPrimaryProfile,
+                /*is_secondary_dex*/ false);
+        snap_profile_ = create_snapshot_profile_path(package_name_, kPrimaryProfile);
+    }
+
+    void SetupProfile(const std::string& path, uid_t uid, gid_t gid, mode_t mode,
+            int32_t num_dex) {
+        run_cmd("profman --generate-test-profile-seed=" + std::to_string(num_dex) +
+                " --generate-test-profile-num-dex=" + std::to_string(num_dex) +
+                " --generate-test-profile=" + path);
+        ::chmod(path.c_str(), mode);
+        ::chown(path.c_str(), uid, gid);
+    }
+
+    void SetupProfiles(bool setup_ref) {
+        SetupProfile(cur_profile_, kTestAppUid, kTestAppGid, 0600, 1);
+        if (setup_ref) {
+            SetupProfile(ref_profile_, kTestAppUid, kTestAppGid, 0600, 2);
+        }
+    }
+
+    void createProfileSnapshot(int32_t appid, const std::string& package_name,
+            bool expected_result) {
+        bool result;
+        binder::Status binder_result = service_->createProfileSnapshot(
+                appid, package_name, kPrimaryProfile, apk_path_, &result);
+        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_EQ(expected_result, result);
+
+        if (!expected_result) {
+            // Do not check the files if we expect to fail.
+            return;
+        }
+
+        // Check that the snapshot was created witht he expected acess flags.
+        CheckFileAccess(snap_profile_, kSystemUid, kSystemGid, 0600 | S_IFREG);
+
+        // The snapshot should be equivalent to the merge of profiles.
+        std::string expected_profile_content = snap_profile_ + ".expected";
+        run_cmd("rm -f " + expected_profile_content);
+        run_cmd("touch " + expected_profile_content);
+        run_cmd("profman --profile-file=" + cur_profile_ +
+                " --profile-file=" + ref_profile_ +
+                " --reference-profile-file=" + expected_profile_content +
+                " --apk=" + apk_path_);
+
+        ASSERT_TRUE(AreFilesEqual(expected_profile_content, snap_profile_));
+
+        pid_t pid = fork();
+        if (pid == 0) {
+            /* child */
+            TransitionToSystemServer();
+
+            // System server should be able to open the the spanshot.
+            unique_fd fd(open(snap_profile_.c_str(), O_RDONLY));
+            ASSERT_TRUE(fd > -1) << "Failed to open profile as kSystemUid: " << strerror(errno);
+            _exit(0);
+        }
+        /* parent */
+        ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+    }
+
+    void mergePackageProfiles(const std::string& package_name,
+                              const std::string& code_path,
+                              bool expected_result) {
+        bool result;
+        binder::Status binder_result = service_->mergeProfiles(
+                kTestAppUid, package_name, code_path, &result);
+        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_EQ(expected_result, result);
+
+        if (!expected_result) {
+            // Do not check the files if we expect to fail.
+            return;
+        }
+
+        // Check that the snapshot was created witht he expected acess flags.
+        CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+
+        // The snapshot should be equivalent to the merge of profiles.
+        std::string ref_profile_content = ref_profile_ + ".expected";
+        run_cmd("rm -f " + ref_profile_content);
+        run_cmd("touch " + ref_profile_content);
+        run_cmd("profman --profile-file=" + cur_profile_ +
+                " --profile-file=" + ref_profile_ +
+                " --reference-profile-file=" + ref_profile_content);
+
+        ASSERT_TRUE(AreFilesEqual(ref_profile_content, ref_profile_));
+    }
+
+    // TODO(calin): add dex metadata tests once the ART change is merged.
+    void preparePackageProfile(const std::string& package_name, const std::string& profile_name,
+            bool expected_result) {
+        bool result;
+        binder::Status binder_result = service_->prepareAppProfile(
+                package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
+                /*dex_metadata*/ nullptr, &result);
+        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_EQ(expected_result, result);
+
+        if (!expected_result) {
+            // Do not check the files if we expect to fail.
+            return;
+        }
+
+        std::string code_path_cur_prof = create_current_profile_path(
+                kTestUserId, package_name, profile_name, /*is_secondary_dex*/ false);
+        std::string code_path_ref_profile = create_reference_profile_path(package_name,
+                profile_name, /*is_secondary_dex*/ false);
+
+        // Check that we created the current profile.
+        CheckFileAccess(code_path_cur_prof, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+
+        // Without dex metadata we don't generate a reference profile.
+        ASSERT_EQ(-1, access(code_path_ref_profile.c_str(), R_OK));
+    }
+
+  protected:
+    void TransitionToSystemServer() {
+        ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
+        int32_t res = selinux_android_setcontext(
+                kSystemUid, true, se_info_.c_str(), "system_server");
+        ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
+    }
+
+    bool AreFilesEqual(const std::string& file1, const std::string& file2) {
+        std::vector<uint8_t> content1;
+        std::vector<uint8_t> content2;
+
+        if (!ReadAll(file1, &content1)) return false;
+        if (!ReadAll(file2, &content2)) return false;
+        return content1 == content2;
+    }
+
+    bool ReadAll(const std::string& file, std::vector<uint8_t>* content) {
+        unique_fd fd(open(file.c_str(), O_RDONLY));
+        if (fd < 0) {
+            PLOG(ERROR) << "Failed to open " << file;
+            return false;
+        }
+        struct stat st;
+        if (fstat(fd, &st) != 0) {
+            PLOG(ERROR) << "Failed to stat " << file;
+            return false;
+        }
+        content->resize(st.st_size);
+        bool result = ReadFully(fd, content->data(), content->size());
+        if (!result) {
+            PLOG(ERROR) << "Failed to read " << file;
+        }
+        return result;
+    }
+};
+
+TEST_F(ProfileTest, ProfileSnapshotOk) {
+    LOG(INFO) << "ProfileSnapshotOk";
+
+    SetupProfiles(/*setup_ref*/ true);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+// The reference profile is created on the fly. We need to be able to
+// snapshot without one.
+TEST_F(ProfileTest, ProfileSnapshotOkNoReference) {
+    LOG(INFO) << "ProfileSnapshotOkNoReference";
+
+    SetupProfiles(/*setup_ref*/ false);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotFailWrongPackage) {
+    LOG(INFO) << "ProfileSnapshotFailWrongPackage";
+
+    SetupProfiles(/*setup_ref*/ true);
+    createProfileSnapshot(kTestAppId, "not.there", /*expected_result*/ false);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotDestroySnapshot) {
+    LOG(INFO) << "ProfileSnapshotDestroySnapshot";
+
+    SetupProfiles(/*setup_ref*/ true);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
+
+    binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, kPrimaryProfile);
+    ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+    struct stat st;
+    ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
+    ASSERT_EQ(ENOENT, errno);
+}
+
+TEST_F(ProfileTest, ProfileMergeOk) {
+    LOG(INFO) << "ProfileMergeOk";
+
+    SetupProfiles(/*setup_ref*/ true);
+    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
+}
+
+// The reference profile is created on the fly. We need to be able to
+// merge without one.
+TEST_F(ProfileTest, ProfileMergeOkNoReference) {
+    LOG(INFO) << "ProfileMergeOkNoReference";
+
+    SetupProfiles(/*setup_ref*/ false);
+    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfileMergeFailWrongPackage) {
+    LOG(INFO) << "ProfileMergeFailWrongPackage";
+
+    SetupProfiles(/*setup_ref*/ true);
+    mergePackageProfiles("not.there", "primary.prof", /*expected_result*/ false);
+}
+
+TEST_F(ProfileTest, ProfileDirOk) {
+    LOG(INFO) << "ProfileDirOk";
+
+    std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+            kTestUserId, package_name_);
+    std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+            kPrimaryProfile, /*is_secondary_dex*/false);
+    std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+    CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
+// Verify that the profile directories are fixed up during an upgrade.
+// (The reference profile directory is prepared lazily).
+TEST_F(ProfileTest, ProfileDirOkAfterFixup) {
+    LOG(INFO) << "ProfileDirOkAfterFixup";
+
+    std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+            kTestUserId, package_name_);
+    std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+            kPrimaryProfile, /*is_secondary_dex*/false);
+    std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+    // Simulate a pre-P setup by changing the owner to kTestAppGid and permissions to 0700.
+    ASSERT_EQ(0, chown(ref_profile_dir.c_str(), kTestAppGid, kTestAppGid));
+    ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
+
+    // Run createAppData again which will offer to fix-up the profile directories.
+    ASSERT_TRUE(service_->createAppData(
+            volume_uuid_,
+            package_name_,
+            kTestUserId,
+            kAppDataFlags,
+            kTestAppUid,
+            se_info_,
+            kOSdkVersion,
+            &ce_data_inode_).isOk());
+
+    // Check the file access.
+    CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
+TEST_F(ProfileTest, ProfilePrepareOk) {
+    LOG(INFO) << "ProfilePrepareOk";
+    preparePackageProfile(package_name_, "split.prof", /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfilePrepareFailInvalidPackage) {
+    LOG(INFO) << "ProfilePrepareFailInvalidPackage";
+    preparePackageProfile("not.there.package", "split.prof", /*expected_result*/ false);
+}
+
+TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) {
+    LOG(INFO) << "ProfilePrepareFailProfileChangedUid";
+    SetupProfiles(/*setup_ref*/ false);
+    // Change the uid on the profile to trigger a failure.
+    ::chown(cur_profile_.c_str(), kTestAppUid + 1, kTestAppGid + 1);
+    preparePackageProfile(package_name_, "primary.prof", /*expected_result*/ false);
+}
+
+
+class BootProfileTest : public ProfileTest {
+  public:
+    virtual void setup() {
+        ProfileTest::SetUp();
+        intial_android_profiles_dir = android_profiles_dir;
+    }
+
+    virtual void TearDown() {
+        android_profiles_dir = intial_android_profiles_dir;
+        ProfileTest::TearDown();
+    }
+
+    void UpdateAndroidProfilesDir(const std::string& profile_dir) {
+        android_profiles_dir = profile_dir;
+        // We need to create the reference profile directory in the new profile dir.
+        run_cmd("mkdir -p " + profile_dir + "/ref");
+    }
+
+    void createBootImageProfileSnapshot(const std::string& classpath, bool expected_result) {
+        bool result;
+        binder::Status binder_result = service_->createProfileSnapshot(
+                -1, "android", "android.prof", classpath, &result);
+        ASSERT_TRUE(binder_result.isOk());
+        ASSERT_EQ(expected_result, result);
+
+        if (!expected_result) {
+            // Do not check the files if we expect to fail.
+            return;
+        }
+
+        // Check that the snapshot was created with he expected access flags.
+        const std::string boot_profile = create_snapshot_profile_path("android", "android.prof");
+        CheckFileAccess(boot_profile, kSystemUid, kSystemGid, 0600 | S_IFREG);
+
+        pid_t pid = fork();
+        if (pid == 0) {
+            /* child */
+            TransitionToSystemServer();
+
+            // System server should be able to open the snapshot.
+            unique_fd fd(open(boot_profile.c_str(), O_RDONLY));
+            ASSERT_TRUE(fd > -1) << "Failed to open profile as kSystemUid: " << strerror(errno);
+            _exit(0);
+        }
+        /* parent */
+        ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+    }
+  protected:
+    std::string intial_android_profiles_dir;
+};
+
+TEST_F(BootProfileTest, BootProfileSnapshotOk) {
+    LOG(INFO) << "BootProfileSnapshotOk";
+    char* boot_classpath = getenv("BOOTCLASSPATH");
+    ASSERT_TRUE(boot_classpath != nullptr);
+    createBootImageProfileSnapshot(boot_classpath, /*expected_result*/ true);
+}
+
+TEST_F(BootProfileTest, BootProfileSnapshotFailEmptyClasspath) {
+    LOG(INFO) << "BootProfileSnapshotFailEmptyClasspath";
+
+    createBootImageProfileSnapshot(/*boot_classpath*/ "", /*expected_result*/ false);
+}
+
+TEST_F(BootProfileTest, BootProfileSnapshotOkNoProfiles) {
+    LOG(INFO) << "BootProfileSnapshotOkNoProfiles";
+    char* boot_classpath = getenv("BOOTCLASSPATH");
+    ASSERT_TRUE(boot_classpath != nullptr);
+
+    // The app_apk_dir has no profiles. So we shouldn't be able to merge anything.
+    // Still, this is not a failure case.
+    UpdateAndroidProfilesDir(app_apk_dir_);
+    createBootImageProfileSnapshot(boot_classpath, /*expected_result*/ true);
+}
+
+// Verify that profile collection.
+TEST_F(BootProfileTest, CollectProfiles) {
+    LOG(INFO) << "CollectProfiles";
+
+    // Create some profile directories mimicking the real profile structure.
+    run_cmd("mkdir -p " + app_private_dir_de_ + "/profiles/ref");
+    run_cmd("mkdir -p " + app_private_dir_de_ + "/profiles/cur/0/");
+    run_cmd("mkdir -p " + app_private_dir_de_ + "/profiles/cur/1/");
+    // Create an empty profile.
+    run_cmd("touch " + app_private_dir_de_ + "/profiles/cur/1/primary.prof");
+    // Create a random file.
+    run_cmd("touch " + app_private_dir_de_ + "/profiles/cur/0/non.profile.file");
+
+    // Create some non-empty profiles.
+    std::string current_prof = app_private_dir_de_ + "/profiles/cur/0/primary.prof";
+    run_cmd("echo 1 > " + current_prof);
+    std::string ref_prof = app_private_dir_de_ + "/profiles/ref/primary.prof";
+    run_cmd("echo 1 > " + ref_prof);
+
+    UpdateAndroidProfilesDir(app_private_dir_de_ + "/profiles");
+
+    std::vector<std::string> profiles;
+    collect_profiles(&profiles);
+
+    // Only two profiles should be in the output.
+    ASSERT_EQ(2u, profiles.size());
+    ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), current_prof) != profiles.end());
+    ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
new file mode 100644
index 0000000..b518507
--- /dev/null
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -0,0 +1,231 @@
+/**
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "installd_constants.h"
+#include "otapreopt_parameters.h"
+
+namespace android {
+namespace installd {
+
+static bool ParseBool(const char* in) {
+    if (strcmp(in, "true") == 0) {
+        return true;
+    }
+    return false;
+}
+
+static const char* ParseNull(const char* arg) {
+    return (strcmp(arg, "!") == 0) ? nullptr : arg;
+}
+
+class OTAPreoptTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:f", 1);
+        android::base::InitLogging(nullptr, android::base::StderrLogger);
+    }
+
+    void verifyPackageParameters(const OTAPreoptParameters& params,
+                                 uint32_t version,
+                                 bool versioned,
+                                 const char** args) {
+        //  otapreopt target-slot [version] dexopt {DEXOPT_PARAMETERS}
+        int i = 0;
+        if (version > 2 || (version == 2 && versioned)) {
+            i += 4;
+        } else {
+            i += 3;
+        }
+        ASSERT_STREQ(params.target_slot.c_str(), args[1]);
+        ASSERT_STREQ(params.apk_path, args[i++]);
+        ASSERT_EQ(params.uid, static_cast<uid_t>(atoi(args[i++])));
+        ASSERT_STREQ(params.pkgName, args[i++]);
+        ASSERT_STREQ(params.instruction_set, args[i++]);
+        ASSERT_EQ(params.dexopt_needed, atoi(args[i++]));
+        ASSERT_STREQ(params.oat_dir, args[i++]);
+        const int dexopt_flags = atoi(args[i++]);
+        ASSERT_STREQ(params.compiler_filter, args[i++]);
+        ASSERT_STREQ(params.volume_uuid, ParseNull(args[i++]));
+        ASSERT_STREQ(params.shared_libraries, ParseNull(args[i++]));
+        if (version > 1) {
+            ASSERT_STREQ(params.se_info, ParseNull(args[i++]));
+        } else {
+            ASSERT_EQ(params.se_info, nullptr);
+        }
+        if (version > 2) {
+            ASSERT_EQ(params.downgrade, ParseBool(args[i++]));
+        } else {
+            ASSERT_FALSE(params.downgrade);
+        }
+        if (version > 3) {
+            ASSERT_EQ(params.target_sdk_version, atoi(args[i++]));
+        } else {
+            ASSERT_EQ(params.target_sdk_version, 0);
+        }
+        if (version > 4) {
+            ASSERT_STREQ(params.profile_name, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.profile_name, "primary.prof");
+        }
+        if (version > 5) {
+            ASSERT_STREQ(params.dex_metadata_path, ParseNull(args[i++]));
+        } else {
+            ASSERT_EQ(params.dex_metadata_path, nullptr);
+        }
+        if (version > 6) {
+            ASSERT_STREQ(params.compilation_reason, ParseNull(args[i++]));
+        } else {
+            ASSERT_STREQ(params.compilation_reason, "ab-ota");
+        }
+        if (version > 7) {
+            ASSERT_EQ(params.dexopt_flags, dexopt_flags);
+        } else {
+            ASSERT_EQ(params.dexopt_flags, dexopt_flags | DEXOPT_GENERATE_COMPACT_DEX);
+        }
+    }
+
+    const char* getVersionCStr(uint32_t version) {
+        switch (version) {
+            case 1: return "1";
+            case 2: return "2";
+            case 3: return "3";
+            case 4: return "4";
+            case 5: return "5";
+            case 6: return "6";
+            case 7: return "7";
+            case 8: return "8";
+            case 9: return "9";
+        }
+        return nullptr;
+    }
+
+    std::vector<const char*> getArgs(uint32_t version, bool versioned) {
+        std::vector<const char*> args;
+        args.push_back("otapreopt");  // "otapreopt"
+        args.push_back("a");  // slot
+        if (versioned) {
+            args.push_back(getVersionCStr(version));
+        }
+        args.push_back("dexopt");  // "dexopt"
+        args.push_back("foo.apk");  // apk_path
+        args.push_back("123");  // uid
+        args.push_back("pkgname");  // pkg
+        args.push_back("arm");  // isa
+        args.push_back("1");  // dexopt_needed (DEX2OAT_FROM_SCRATCH)
+        args.push_back("oat_dir");  // oat_dir
+        args.push_back("0");  // dexopt_flags
+        args.push_back("speed");  // filter
+        args.push_back("!");  // volume
+        args.push_back("shared.lib");  // libs
+
+        if (version > 1) {
+            args.push_back("!");  // seinfo
+        }
+        if (version > 2) {
+            args.push_back("true");  // downgrade
+        }
+        if (version > 3) {
+            args.push_back("28");  // sdk_version
+        }
+        if (version > 4) {
+            args.push_back("split_a.prof");  // profile_name
+        }
+        if (version > 5) {
+            args.push_back("dex_metadata.dm");  // dex_metadata_path
+        }
+        if (version > 6) {
+            args.push_back("ab-ota-test");  // compilation_reason
+        }
+        args.push_back(nullptr);  // we have to end with null.
+        return args;
+    }
+
+    void VerifyReadArguments(uint32_t version, bool versioned) {
+        OTAPreoptParameters params;
+        std::vector<const char*> args = getArgs(version, versioned);
+        ASSERT_TRUE(params.ReadArguments(args.size() - 1, args.data()));
+        verifyPackageParameters(params, version, versioned, args.data());
+    }
+};
+
+TEST_F(OTAPreoptTest, ReadArgumentsV1) {
+    VerifyReadArguments(1, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2Unversioned) {
+    VerifyReadArguments(2, false);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV2) {
+    VerifyReadArguments(2, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV3) {
+    VerifyReadArguments(3, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV4) {
+    VerifyReadArguments(4, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV5) {
+    VerifyReadArguments(5, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV6) {
+    VerifyReadArguments(6, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV7) {
+    VerifyReadArguments(7, true);
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailToManyArgs) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(5, true);
+    args[2] = "3";  // pretend it's version 3. It should fail since there are too many args.
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInsufficientArgs) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(4, true);
+    args[2] = "5";  // pretend it's version 5. It should fail since there are insufficient args.
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidDexopt) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(4, true);
+    args[3] = "dexopt-invalid";
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsFailInvalidSlot) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(3, true);
+    args[1] = "invalid-slot???";
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 34818f6..a5af5d7 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sstream>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/statvfs.h>
@@ -25,6 +26,7 @@
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
 
@@ -41,37 +43,33 @@
     return property_get(key, value, default_value);
 }
 
-bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *oat_dir ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool create_cache_path(char path[PKG_PATH_MAX],
-        const char *src,
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
         const char *instruction_set) {
-    // Not really a valid path but it's good enough for testing.
-    sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
-    return true;
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
+}
+
+static std::string get_full_path(const char* path) {
+    return StringPrintf("/data/local/tmp/user/0/%s", path);
 }
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::mkdir(fullPath, mode);
-    ::chown(fullPath, owner, group);
-    ::chmod(fullPath, mode);
+    const std::string fullPath = get_full_path(path);
+    ::mkdir(fullPath.c_str(), mode);
+    ::chown(fullPath.c_str(), owner, group);
+    ::chmod(fullPath.c_str(), mode);
 }
 
 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
-    int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(),
-            O_RDWR | O_CREAT, mode);
+    int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
     ::fchown(fd, owner, group);
     ::fchmod(fd, mode);
     ::close(fd);
@@ -79,13 +77,13 @@
 
 static int stat_gid(const char* path) {
     struct stat buf;
-    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    ::stat(get_full_path(path).c_str(), &buf);
     return buf.st_gid;
 }
 
 static int stat_mode(const char* path) {
     struct stat buf;
-    ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf);
+    ::stat(get_full_path(path).c_str(), &buf);
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
@@ -102,6 +100,8 @@
         testUuid = std::make_unique<std::string>();
         *testUuid = std::string(kTestUuid);
         system("mkdir -p /data/local/tmp/user/0");
+
+        init_globals_from_data_and_root();
     }
 
     virtual void TearDown() {
@@ -153,12 +153,91 @@
     EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
 }
 
-TEST_F(ServiceTest, RmDexNoDalvikCache) {
-    LOG(INFO) << "RmDexNoDalvikCache";
+TEST_F(ServiceTest, HashSecondaryDex) {
+    LOG(INFO) << "HashSecondaryDex";
 
-    // Try to remove a non existing dalvik cache dex. The call should be
-    // successful because there's nothing to remove.
-    EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 32U);
+
+    std::ostringstream output;
+    output << std::hex << std::setfill('0');
+    for (auto b : result) {
+        output << std::setw(2) << +b;
+    }
+
+    // This is the SHA256 of an empty string (sha256sum /dev/null)
+    EXPECT_EQ(output.str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_NoSuch) {
+    LOG(INFO) << "HashSecondaryDex_NoSuch";
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 0U);
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
+    LOG(INFO) << "HashSecondaryDex_Unreadable";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0300);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_TRUE(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+
+    EXPECT_EQ(result.size(), 0U);
+}
+
+TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
+    LOG(INFO) << "HashSecondaryDex_WrongApp";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+
+    std::vector<uint8_t> result;
+    std::string dexPath = get_full_path("com.example/foo/file");
+    EXPECT_FALSE(service->hashSecondaryDexFile(
+        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+}
+
+TEST_F(ServiceTest, CalculateOat) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
+}
+
+TEST_F(ServiceTest, CalculateOdex) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+}
+
+TEST_F(ServiceTest, CalculateCache) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 46ed85f..bcdd03e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <android-base/logging.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -27,11 +28,12 @@
 #define LOG_TAG "utils_test"
 
 #define TEST_DATA_DIR "/data/"
+#define TEST_ROOT_DIR "/system/"
 #define TEST_APP_DIR "/data/app/"
 #define TEST_APP_PRIVATE_DIR "/data/app-private/"
 #define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
 #define TEST_ASEC_DIR "/mnt/asec/"
-#define TEST_EXPAND_DIR "/mnt/expand/"
+#define TEST_EXPAND_DIR "/mnt/expand/00000000-0000-0000-0000-000000000000/"
 
 #define TEST_SYSTEM_DIR1 "/system/app/"
 #define TEST_SYSTEM_DIR2 "/vendor/app/"
@@ -44,39 +46,13 @@
 class UtilsTest : public testing::Test {
 protected:
     virtual void SetUp() {
-        android_app_dir.path = (char*) TEST_APP_DIR;
-        android_app_dir.len = strlen(TEST_APP_DIR);
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
 
-        android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
-        android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
-
-        android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
-        android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
-
-        android_data_dir.path = (char*) TEST_DATA_DIR;
-        android_data_dir.len = strlen(TEST_DATA_DIR);
-
-        android_asec_dir.path = (char*) TEST_ASEC_DIR;
-        android_asec_dir.len = strlen(TEST_ASEC_DIR);
-
-        android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
-        android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
-
-        android_system_dirs.count = 2;
-
-        android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-        android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
-        android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
-
-        android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
-        android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
-
-        android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
-        android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
+        init_globals_from_data_and_root(TEST_DATA_DIR, TEST_ROOT_DIR);
     }
 
     virtual void TearDown() {
-        free(android_system_dirs.dirs);
     }
 
     std::string create_too_long_path(const std::string& seed) {
@@ -140,6 +116,41 @@
             << bad_path5 << " should be rejected as a invalid path";
 }
 
+TEST_F(UtilsTest, IsValidApkPath_TopDir) {
+    EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example"));
+    EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example"));
+    EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example"));
+    EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_TopFile) {
+    EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk"));
+    EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk"));
+    EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk"));
+    EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDir) {
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat"));
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDir) {
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64"));
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) {
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex"));
+    EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex"));
+    EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex"));
+}
+
 TEST_F(UtilsTest, IsValidApkPath_Private) {
     // Internal directories
     const char *private1 = TEST_APP_PRIVATE_DIR "example.apk";
@@ -192,12 +203,6 @@
             << badasec1 << " should be rejected as a invalid path";
 }
 
-TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) {
-    const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk";
-    EXPECT_EQ(-1, validate_apk_path(badasec2))
-            << badasec2 << " should be rejected as a invalid path";
-}
-
 TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) {
     const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk";
     EXPECT_EQ(-1, validate_apk_path(badasec3))
@@ -276,184 +281,6 @@
             << badapp2 << " should be rejected not a system path";
 }
 
-TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
-            << "Should not allow NULL as a path.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, ""))
-            << "Should not allow empty paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
-            << "Should not allow relative paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
-    dir_rec_t test1;
-
-    EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
-            << "Should be able to canonicalize directory /mnt/asec";
-    EXPECT_STREQ("/mnt/asec/", test1.path)
-            << "/mnt/asec should be canonicalized to /mnt/asec/";
-    EXPECT_EQ(10, (ssize_t) test1.len)
-            << "path len should be equal to the length of /mnt/asec/ (10)";
-    free(test1.path);
-}
-
-TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
-    dir_rec_t test3;
-    EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
-            << "Should be able to canonicalize directory /data/app/";
-    EXPECT_STREQ("/data/app/", test3.path)
-            << "/data/app/ should be canonicalized to /data/app/";
-    EXPECT_EQ(10, (ssize_t) test3.len)
-            << "path len should be equal to the length of /data/app/ (10)";
-    free(test3.path);
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t pkgnameSize = PKG_NAME_MAX;
-    char pkgname[pkgnameSize + 1];
-    memset(pkgname, 'a', pkgnameSize);
-    pkgname[1] = '.';
-    pkgname[pkgnameSize] = '\0';
-
-    EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
-            << "Should successfully be able to create package name.";
-
-    std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX;
-    size_t offset = prefix.length();
-
-    EXPECT_STREQ(pkgname, path + offset)
-             << "Package path should be a really long string of a's";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t postfixSize = PKG_PATH_MAX;
-    char postfix[postfixSize + 1];
-    memset(postfix, 'a', postfixSize);
-    postfix[postfixSize] = '\0';
-
-    EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
-            << "Should return error because postfix is too long.";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
-            << "Should return error because postfix is too long.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + PRIMARY_USER_PREFIX
-                    + "com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/data/";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
-            << "Should successfully create package path.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + SECONDARY_USER_PREFIX
-                    + "1/com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/user/";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Primary) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
-            << "Should be able to create move path for primary user";
-
-    EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
-            << "Primary user package directory should be created correctly";
-}
-
-
-TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_app_name = create_too_long_path("com.example");
-    EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_leaf_name = create_too_long_path("leaf_");
-    EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CopyAndAppend_Normal) {
-    //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
-    dir_rec_t dst;
-    dir_rec_t src;
-
-    src.path = (char*) "/data/";
-    src.len = strlen(src.path);
-
-    EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
-            << "Should return error because postfix is too long.";
-
-    EXPECT_STREQ("/data/app/", dst.path)
-            << "Appended path should be correct";
-
-    EXPECT_EQ(10, (ssize_t) dst.len)
-            << "Appended path should be length of '/data/app/' (10)";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_Normal) {
-    size_t dst_size = 10;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully again";
-
-    EXPECT_STREQ("FOOFOO", dst)
-            << "String should append correctly again";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
-    size_t dst_size = 5;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
-            << "String should fail because it's too large to fit";
-}
-
 TEST_F(UtilsTest, CreateDataPath) {
     EXPECT_EQ("/data", create_data_path(nullptr));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
@@ -545,28 +372,50 @@
 }
 
 TEST_F(UtilsTest, CreatePrimaryCurrentProfile) {
-    std::string expected =
+    std::string expected_base =
         create_primary_current_profile_package_dir_path(0, "com.example") + "/primary.prof";
-    EXPECT_EQ(expected,
-            create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false));
+    EXPECT_EQ(expected_base,
+            create_current_profile_path(/*user*/0, "com.example", "primary.prof",
+                    /*is_secondary*/false));
+
+    std::string expected_split =
+        create_primary_current_profile_package_dir_path(0, "com.example") + "/split.prof";
+    EXPECT_EQ(expected_split,
+            create_current_profile_path(/*user*/0, "com.example", "split.prof",
+                    /*is_secondary*/false));
 }
 
 TEST_F(UtilsTest, CreatePrimaryReferenceProfile) {
-    std::string expected =
+    std::string expected_base =
         create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof";
-    EXPECT_EQ(expected,
-            create_reference_profile_path("com.example", /*is_secondary*/false));
+    EXPECT_EQ(expected_base,
+            create_reference_profile_path("com.example", "primary.prof", /*is_secondary*/false));
+
+    std::string expected_split =
+        create_primary_reference_profile_package_dir_path("com.example") + "/split.prof";
+    EXPECT_EQ(expected_split,
+            create_reference_profile_path("com.example", "split.prof", /*is_secondary*/false));
+}
+
+TEST_F(UtilsTest, CreateProfileSnapshot) {
+    std::string expected_base =
+        create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof.snapshot";
+    EXPECT_EQ(expected_base, create_snapshot_profile_path("com.example", "primary.prof"));
+
+    std::string expected_split =
+        create_primary_reference_profile_package_dir_path("com.example") + "/split.prof.snapshot";
+    EXPECT_EQ(expected_split, create_snapshot_profile_path("com.example", "split.prof"));
 }
 
 TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
     EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof",
-            create_current_profile_path(/*user*/0,
+            create_current_profile_path(/*user*/0, "com.example",
                     "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
 }
 
 TEST_F(UtilsTest, CreateSecondaryReferenceProfile) {
     EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.prof",
-            create_reference_profile_path(
+            create_reference_profile_path("com.example",
                     "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
 }
 
@@ -587,6 +436,7 @@
 TEST_F(UtilsTest, ValidateSecondaryDexFilesPath) {
     std::string package_name = "com.test.app";
     std::string app_dir_ce_user_0 = "/data/data/" + package_name;
+    std::string app_dir_ce_user_0_link = "/data/user/0/" + package_name;
     std::string app_dir_ce_user_10 = "/data/user/10/" + package_name;
 
     std::string app_dir_de_user_0 = "/data/user_de/0/" + package_name;
@@ -608,6 +458,8 @@
     // Standard path for user 0 on CE storage.
     pass_secondary_dex_validation(
         package_name, app_dir_ce_user_0 + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
+    pass_secondary_dex_validation(
+        package_name, app_dir_ce_user_0_link + "/ce0.dex", app_uid_for_user_0, FLAG_STORAGE_CE);
     // Standard path for user 10 on CE storage.
     pass_secondary_dex_validation(
         package_name, app_dir_ce_user_10 + "/ce10.dex", app_uid_for_user_10, FLAG_STORAGE_CE);
@@ -653,5 +505,29 @@
         package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE);
 }
 
+TEST_F(UtilsTest, ValidateApkPath) {
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example"));
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file"));
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir//file"));
+}
+
+TEST_F(UtilsTest, ValidateApkPathSubdirs) {
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example//file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file"));
+    EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
new file mode 100644
index 0000000..b8785c6
--- /dev/null
+++ b/cmds/installd/tests/test_utils.h
@@ -0,0 +1,134 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+
+#include <android-base/logging.h>
+#include <selinux/android.h>
+
+uint8_t kBase64Map[256] = {
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+     52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+    255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
+      7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
+     19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
+    255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+     49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255
+};
+
+uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+    CHECK(dst_size != nullptr);
+    std::vector<uint8_t> tmp;
+    uint32_t t = 0, y = 0;
+    int g = 3;
+    for (size_t i = 0; src[i] != '\0'; ++i) {
+        uint8_t c = kBase64Map[src[i] & 0xFF];
+        if (c == 255) continue;
+        // the final = symbols are read and used to trim the remaining bytes
+        if (c == 254) {
+            c = 0;
+            // prevent g < 0 which would potentially allow an overflow later
+            if (--g < 0) {
+                *dst_size = 0;
+                return nullptr;
+            }
+        } else if (g != 3) {
+            // we only allow = to be at the end
+            *dst_size = 0;
+            return nullptr;
+        }
+        t = (t << 6) | c;
+        if (++y == 4) {
+            tmp.push_back((t >> 16) & 255);
+            if (g > 1) {
+                tmp.push_back((t >> 8) & 255);
+            }
+            if (g > 2) {
+                tmp.push_back(t & 255);
+            }
+            y = t = 0;
+        }
+    }
+    if (y != 0) {
+        *dst_size = 0;
+        return nullptr;
+    }
+    std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
+    *dst_size = tmp.size();
+    std::copy(tmp.begin(), tmp.end(), dst.get());
+    return dst.release();
+}
+
+bool WriteBase64ToFile(const char* base64, const std::string& file,
+        uid_t uid, gid_t gid, int mode) {
+    CHECK(base64 != nullptr);
+    size_t length;
+    std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+    CHECK(bytes != nullptr);
+
+
+    int fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+
+    if (fd < 0) {
+        PLOG(ERROR) << "Could not open file " << file;
+        return false;
+    }
+
+    size_t wrote = 0;
+    while (wrote < length) {
+        ssize_t cur = write(fd, bytes.get() + wrote, length - wrote);
+        if (cur == -1) {
+            PLOG(ERROR) << "Could not write file " << file;
+            return false;
+        }
+        wrote += cur;
+    }
+
+    if (::chown(file.c_str(), uid, gid) != 0) {
+        PLOG(ERROR) << "Could not chown file " << file;
+        return false;
+    }
+    if (::chmod(file.c_str(), mode) != 0) {
+        PLOG(ERROR) << "Could not chmod file " << file;
+        return false;
+    }
+    return true;
+}
+
+// TODO(calin): fix dexopt drop_capabilities and move to general utils (b/69678790).
+bool DropCapabilities(uid_t uid, gid_t gid) {
+    if (setgid(gid) != 0) {
+        PLOG(ERROR) << "setgid failed: " <<  gid;
+        return false;
+    }
+    if (setuid(uid) != 0) {
+        PLOG(ERROR) << "setuid failed: " <<  uid;
+        return false;
+    }
+    // drop capabilities
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    if (capset(&capheader, &capdata[0]) < 0) {
+        PLOG(ERROR) << "capset failed";
+        return false;
+    }
+
+    return true;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index dd32ac6..1ff45e4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -26,7 +26,9 @@
 #include <sys/statvfs.h>
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <log/log.h>
@@ -40,7 +42,9 @@
 
 #define DEBUG_XATTRS 0
 
+using android::base::EndsWith;
 using android::base::StringPrintf;
+using android::base::unique_fd;
 
 namespace android {
 namespace installd {
@@ -87,6 +91,20 @@
             create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
 }
 
+/**
+ * Create the path name where package data should be stored for the given
+ * volume UUID, package name, and user ID. An empty UUID is assumed to be
+ * internal storage.
+ * Compared to create_data_user_ce_package_path this method always return the
+ * ".../user/..." directory.
+ */
+std::string create_data_user_ce_package_path_as_user_link(
+        const char* volume_uuid, userid_t userid, const char* package_name) {
+    check_package_name(package_name);
+    std::string data(create_data_path(volume_uuid));
+    return StringPrintf("%s/user/%u/%s", data.c_str(), userid, package_name);
+}
+
 std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user,
         const char* package_name, ino_t ce_data_inode) {
     // For testing purposes, rely on the inode when defined; this could be
@@ -129,24 +147,6 @@
             create_data_user_de_path(volume_uuid, user).c_str(), package_name);
 }
 
-int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
-        const char *postfix, userid_t userid) {
-    if (!is_valid_package_name(pkgname)) {
-        path[0] = '\0';
-        return -1;
-    }
-
-    std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
-    const char* tmp = _tmp.c_str();
-    if (strlen(tmp) >= PKG_PATH_MAX) {
-        path[0] = '\0';
-        return -1;
-    } else {
-        strcpy(path, tmp);
-        return 0;
-    }
-}
-
 std::string create_data_path(const char* volume_uuid) {
     if (volume_uuid == nullptr) {
         return "/data";
@@ -213,7 +213,7 @@
 }
 
 std::string create_primary_cur_profile_dir_path(userid_t userid) {
-    return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+    return StringPrintf("%s/cur/%u", android_profiles_dir.c_str(), userid);
 }
 
 std::string create_primary_current_profile_package_dir_path(userid_t user,
@@ -224,12 +224,12 @@
 }
 
 std::string create_primary_ref_profile_dir_path() {
-    return StringPrintf("%s/ref", android_profiles_dir.path);
+    return StringPrintf("%s/ref", android_profiles_dir.c_str());
 }
 
 std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
     check_package_name(package_name.c_str());
-    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+    return StringPrintf("%s/ref/%s", android_profiles_dir.c_str(), package_name.c_str());
 }
 
 std::string create_data_dalvik_cache_path() {
@@ -239,7 +239,7 @@
 // Keep profile paths in sync with ActivityThread and LoadedApk.
 const std::string PROFILE_EXT = ".prof";
 const std::string CURRENT_PROFILE_EXT = ".cur";
-const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+const std::string SNAPSHOT_PROFILE_EXT = ".snapshot";
 
 // Gets the parent directory and the file name for the given secondary dex path.
 // Returns true on success, false on failure (if the dex_path does not have the expected
@@ -259,8 +259,8 @@
    return true;
 }
 
-std::string create_current_profile_path(userid_t user, const std::string& location,
-        bool is_secondary_dex) {
+std::string create_current_profile_path(userid_t user, const std::string& package_name,
+        const std::string& location, bool is_secondary_dex) {
     if (is_secondary_dex) {
         // Secondary dex current profiles are stored next to the dex files under the oat folder.
         std::string dex_dir;
@@ -272,12 +272,14 @@
                 PROFILE_EXT.c_str());
     } else {
         // Profiles for primary apks are under /data/misc/profiles/cur.
-        std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
-        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+        std::string profile_dir = create_primary_current_profile_package_dir_path(
+                user, package_name);
+        return StringPrintf("%s/%s", profile_dir.c_str(), location.c_str());
     }
 }
 
-std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
+std::string create_reference_profile_path(const std::string& package_name,
+        const std::string& location, bool is_secondary_dex) {
     if (is_secondary_dex) {
         // Secondary dex reference profiles are stored next to the dex files under the oat folder.
         std::string dex_dir;
@@ -288,11 +290,18 @@
                 dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
     } else {
         // Reference profiles for primary apks are stored in /data/misc/profile/ref.
-        std::string profile_dir = create_primary_reference_profile_package_dir_path(location);
-        return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+        std::string profile_dir = create_primary_reference_profile_package_dir_path(package_name);
+        return StringPrintf("%s/%s", profile_dir.c_str(), location.c_str());
     }
 }
 
+std::string create_snapshot_profile_path(const std::string& package,
+        const std::string& profile_name) {
+    std::string ref_profile = create_reference_profile_path(package, profile_name,
+            /*is_secondary_dex*/ false);
+    return ref_profile + SNAPSHOT_PROFILE_EXT;
+}
+
 std::vector<userid_t> get_known_users(const char* volume_uuid) {
     std::vector<userid_t> users;
 
@@ -378,20 +387,6 @@
     return 0;
 }
 
-int create_move_path(char path[PKG_PATH_MAX],
-    const char* pkgname,
-    const char* leaf,
-    userid_t userid ATTRIBUTE_UNUSED)
-{
-    if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
-            >= PKG_PATH_MAX) {
-        return -1;
-    }
-
-    sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
-    return 0;
-}
-
 /**
  * Checks whether the package name is valid. Returns -1 on error and
  * 0 on success.
@@ -756,27 +751,47 @@
     }
 }
 
+void remove_path_xattr(const std::string& path, const char* inode_xattr) {
+    if (removexattr(path.c_str(), inode_xattr) && errno != ENODATA) {
+        PLOG(ERROR) << "Failed to remove xattr " << inode_xattr << " at " << path;
+    }
+}
+
 /**
  * Validate that the path is valid in the context of the provided directory.
  * The path is allowed to have at most one subdirectory and no indirections
  * to top level directories (i.e. have "..").
  */
-static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
-    size_t dir_len = dir->len;
-    const char* subdir = strchr(path + dir_len, '/');
-
-    // Only allow the path to have at most one subdirectory.
-    if (subdir != NULL) {
-        ++subdir;
-        if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
-            ALOGE("invalid apk path '%s' (subdir?)\n", path);
-            return -1;
-        }
+static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
+    // Argument sanity checking
+    if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
+            || dir.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid directory " << dir;
+        return -1;
+    }
+    if (path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid path " << path;
+        return -1;
     }
 
-    // Directories can't have a period directly after the directory markers to prevent "..".
-    if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
-        ALOGE("invalid apk path '%s' (trickery)\n", path);
+    if (path.compare(0, dir.size(), dir) != 0) {
+        // Common case, path isn't under directory
+        return -1;
+    }
+
+    // Count number of subdirectories
+    auto pos = path.find('/', dir.size());
+    int count = 0;
+    while (pos != std::string::npos) {
+        auto next = path.find('/', pos + 1);
+        if (next > pos + 1) {
+            count++;
+        }
+        pos = next;
+    }
+
+    if (count > maxSubdirs) {
+        LOG(ERROR) << "Invalid path depth " << path << " when tested against " << dir;
         return -1;
     }
 
@@ -788,20 +803,17 @@
  * if it is a system app or -1 if it is not.
  */
 int validate_system_app_path(const char* path) {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        const size_t dir_len = android_system_dirs.dirs[i].len;
-        if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
-            return validate_path(android_system_dirs.dirs + i, path, 1);
+    std::string path_ = path;
+    for (const auto& dir : android_system_dirs) {
+        if (validate_path(dir, path, 1) == 0) {
+            return 0;
         }
     }
-
     return -1;
 }
 
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
-        const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
+        const char* volume_uuid, int uid, int storage_flag) {
     CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
 
     // Empty paths are not allowed.
@@ -815,16 +827,20 @@
     // The path should be at most PKG_PATH_MAX long.
     if (dex_path.size() > PKG_PATH_MAX) { return false; }
 
-    if (validate_package_path) {
-        // If we are asked to validate the package path check that
-        // the dex_path is under the app data directory.
-        std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+    // The dex_path should be under the app data directory.
+    std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
             ? create_data_user_ce_package_path(
                     volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
             : create_data_user_de_package_path(
                     volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
 
-        if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+    if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+        // The check above might fail if the dex file is accessed via the /data/user/0 symlink.
+        // If that's the case, attempt to validate against the user data link.
+        std::string app_private_dir_symlink = create_data_user_ce_package_path_as_user_link(
+                volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+        if (strncmp(dex_path.c_str(), app_private_dir_symlink.c_str(),
+                app_private_dir_symlink.size()) != 0) {
             return false;
         }
     }
@@ -834,116 +850,30 @@
 }
 
 /**
- * Get the contents of a environment variable that contains a path. Caller
- * owns the string that is inserted into the directory record. Returns
- * 0 on success and -1 on error.
- */
-int get_path_from_env(dir_rec_t* rec, const char* var) {
-    const char* path = getenv(var);
-    int ret = get_path_from_string(rec, path);
-    if (ret < 0) {
-        ALOGW("Problem finding value for environment variable %s\n", var);
-    }
-    return ret;
-}
-
-/**
- * Puts the string into the record as a directory. Appends '/' to the end
- * of all paths. Caller owns the string that is inserted into the directory
- * record. A null value will result in an error.
- *
- * Returns 0 on success and -1 on error.
- */
-int get_path_from_string(dir_rec_t* rec, const char* path) {
-    if (path == NULL) {
-        return -1;
-    } else {
-        const size_t path_len = strlen(path);
-        if (path_len <= 0) {
-            return -1;
-        }
-
-        // Make sure path is absolute.
-        if (path[0] != '/') {
-            return -1;
-        }
-
-        if (path[path_len - 1] == '/') {
-            // Path ends with a forward slash. Make our own copy.
-
-            rec->path = strdup(path);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            rec->len = path_len;
-        } else {
-            // Path does not end with a slash. Generate a new string.
-            char *dst;
-
-            // Add space for slash and terminating null.
-            size_t dst_size = path_len + 2;
-
-            rec->path = (char*) malloc(dst_size);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            dst = rec->path;
-
-            if (append_and_increment(&dst, path, &dst_size) < 0
-                    || append_and_increment(&dst, "/", &dst_size)) {
-                ALOGE("Error canonicalizing path");
-                return -1;
-            }
-
-            rec->len = dst - rec->path;
-        }
-    }
-    return 0;
-}
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
-    dst->len = src->len + strlen(suffix);
-    const size_t dstSize = dst->len + 1;
-    dst->path = (char*) malloc(dstSize);
-
-    if (dst->path == NULL
-            || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
-                    != (ssize_t) dst->len) {
-        ALOGE("Could not allocate memory to hold appended path; aborting\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
  * Check whether path points to a valid path for an APK file. The path must
  * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
  * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
  * is encountered.
  */
-static int validate_apk_path_internal(const char *path, int maxSubdirs) {
-    const dir_rec_t* dir = NULL;
-    if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
-        dir = &android_app_dir;
-    } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
-        dir = &android_app_private_dir;
-    } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
-        dir = &android_app_ephemeral_dir;
-    } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
-        dir = &android_asec_dir;
-    } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
-        dir = &android_mnt_expand_dir;
-        if (maxSubdirs < 2) {
-            maxSubdirs = 2;
+static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
+    if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_asec_dir, path, maxSubdirs) == 0) {
+        return 0;
+    } else if (android::base::StartsWith(path, android_mnt_expand_dir)) {
+        // Rewrite the path as if it were on internal storage, and test that
+        size_t end = path.find('/', android_mnt_expand_dir.size() + 1);
+        if (end != std::string::npos) {
+            auto modified = path;
+            modified.replace(0, end + 1, android_data_dir);
+            return validate_apk_path_internal(modified, maxSubdirs);
         }
-    } else {
-        return -1;
     }
-
-    return validate_path(dir, path, maxSubdirs);
+    return -1;
 }
 
 int validate_apk_path(const char* path) {
@@ -954,48 +884,6 @@
     return validate_apk_path_internal(path, 3 /* maxSubdirs */);
 }
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size) {
-    ssize_t ret = strlcpy(*dst, src, *dst_size);
-    if (ret < 0 || (size_t) ret >= *dst_size) {
-        return -1;
-    }
-    *dst += ret;
-    *dst_size -= ret;
-    return 0;
-}
-
-char *build_string2(const char *s1, const char *s2) {
-    if (s1 == NULL || s2 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len = len_s1 + len_s2 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-
-    return result;
-}
-
-char *build_string3(const char *s1, const char *s2, const char *s3) {
-    if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len_s3 = strlen(s3);
-    int len = len_s1 + len_s2 + len_s3 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-    strcpy(result + len_s1 + len_s2, s3);
-
-    return result;
-}
-
 int ensure_config_user_dirs(userid_t userid) {
     // writable by system, readable by any app within the same user
     const int uid = multiuser_get_uid(userid, AID_SYSTEM);
@@ -1068,7 +956,7 @@
     } else {
         // Mismatched GID/mode is recoverable; fall through to update
         LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
-                << " but expected " << gid;
+                << "/" << actual_mode << " but expected " << gid << "/" << target_mode;
     }
 
     // Directory is owned correctly, but GID or mode mismatch means it's
@@ -1104,5 +992,75 @@
     return 0;
 }
 
+// Collect all non empty profiles from the given directory and puts then into profile_paths.
+// The profiles are identified based on PROFILE_EXT extension.
+// If a subdirectory or profile file cannot be opened the method logs a warning and moves on.
+// It returns true if there were no errors at all, and false otherwise.
+static bool collect_profiles(DIR* d,
+                             const std::string& current_path,
+                             std::vector<std::string>* profiles_paths) {
+    int32_t dir_fd = dirfd(d);
+    if (dir_fd < 0) {
+        return false;
+    }
+
+    bool result = true;
+    struct dirent* dir_entry;
+    while ((dir_entry = readdir(d))) {
+        std::string name = dir_entry->d_name;
+        std::string local_path = current_path + "/" + name;
+
+        if (dir_entry->d_type == DT_REG) {
+            // Check if this is a non empty profile file.
+            if (EndsWith(name, PROFILE_EXT)) {
+                struct stat st;
+                if (stat(local_path.c_str(), &st) != 0) {
+                    PLOG(WARNING) << "Cannot stat local path " << local_path;
+                    result = false;
+                    continue;
+                } else if (st.st_size > 0) {
+                    profiles_paths->push_back(local_path);
+                }
+            }
+        } else if (dir_entry->d_type == DT_DIR) {
+            // always skip "." and ".."
+            if (name == "." || name == "..") {
+                continue;
+            }
+
+            unique_fd subdir_fd(openat(dir_fd, name.c_str(),
+                    O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+            if (subdir_fd < 0) {
+                PLOG(WARNING) << "Could not open dir path " << local_path;
+                result = false;
+                continue;
+            }
+
+            DIR* subdir = fdopendir(subdir_fd);
+            if (subdir == NULL) {
+                PLOG(WARNING) << "Could not open dir path " << local_path;
+                result = false;
+                continue;
+            }
+            bool new_result = collect_profiles(subdir, local_path, profiles_paths);
+            result = result && new_result;
+            if (closedir(subdir) != 0) {
+                PLOG(WARNING) << "Could not close dir path " << local_path;
+            }
+        }
+    }
+
+    return result;
+}
+
+bool collect_profiles(std::vector<std::string>* profiles_paths) {
+    DIR* d = opendir(android_profiles_dir.c_str());
+    if (d == NULL) {
+        return false;
+    } else {
+        return collect_profiles(d, android_profiles_dir, profiles_paths);
+    }
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index e938042..5829c4f 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,23 +36,16 @@
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
 
-#define APPLY_HARD_QUOTAS 1
+#define APPLY_HARD_QUOTAS 0
 
 namespace android {
 namespace installd {
 
-struct dir_rec_t;
-
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
 constexpr const char* kXattrCacheGroup = "user.cache_group";
 constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
-int create_pkg_path(char path[PKG_PATH_MAX],
-                    const char *pkgname,
-                    const char *postfix,
-                    userid_t userid);
-
 std::string create_data_path(const char* volume_uuid);
 
 std::string create_data_app_path(const char* volume_uuid);
@@ -67,6 +60,8 @@
         userid_t user, const char* package_name, ino_t ce_data_inode);
 std::string create_data_user_de_package_path(const char* volume_uuid,
         userid_t user, const char* package_name);
+std::string create_data_user_ce_package_path_as_user_link(
+        const char* volume_uuid, userid_t userid, const char* package_name);
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -85,9 +80,17 @@
 std::string create_primary_reference_profile_package_dir_path(const std::string& package_name);
 
 std::string create_current_profile_path(
-        userid_t user, const std::string& package_name, bool is_secondary_dex);
+        userid_t user,
+        const std::string& package_name,
+        const std::string& location,
+        bool is_secondary_dex);
 std::string create_reference_profile_path(
-        const std::string& package_name, bool is_secondary_dex);
+        const std::string& package_name,
+        const std::string& location,
+        bool is_secondary_dex);
+std::string create_snapshot_profile_path(
+        const std::string& package,
+        const std::string& profile_name);
 
 std::vector<userid_t> get_known_users(const char* volume_uuid);
 
@@ -96,11 +99,6 @@
 
 int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
 
-int create_move_path(char path[PKG_PATH_MAX],
-                     const char* pkgname,
-                     const char* leaf,
-                     userid_t userid);
-
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
@@ -122,25 +120,15 @@
 
 int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
 std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
+void remove_path_xattr(const std::string& path, const char* inode_xattr);
 
 int validate_system_app_path(const char* path);
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
-        const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
-
-int get_path_from_env(dir_rec_t* rec, const char* var);
-
-int get_path_from_string(dir_rec_t* rec, const char* path);
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
+        const char* volume_uuid, int uid, int storage_flag);
 
 int validate_apk_path(const char *path);
 int validate_apk_path_subdirs(const char *path);
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size);
-
-char *build_string2(const char *s1, const char *s2);
-char *build_string3(const char *s1, const char *s2, const char *s3);
-
 int ensure_config_user_dirs(userid_t userid);
 
 int wait_child(pid_t pid);
@@ -148,6 +136,12 @@
 int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
         uid_t uid, gid_t gid);
 
+// Collect all non empty profiles from the global profile directory and
+// put then into profile_paths. The profiles are identified based on PROFILE_EXT extension.
+// If a subdirectory or profile file cannot be opened the method logs a warning and moves on.
+// It returns true if there were no errors at all, and false otherwise.
+bool collect_profiles(std::vector<std::string>* profiles_paths);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index 36bbdf5..e1e2204 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -18,6 +18,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := ip-up-vpn.c
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_MODULE := ip-up-vpn
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 67b5b46..93d878b 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -20,16 +20,27 @@
         "libutils",
         "libhidlbase",
         "libhidltransport",
+        "libhidl-gen-hash",
         "libhidl-gen-utils",
         "libvintf",
     ],
+    static_libs: [
+        "libprocpartition",
+    ],
     srcs: [
         "DebugCommand.cpp",
+        "HelpCommand.cpp",
         "Lshal.cpp",
         "ListCommand.cpp",
         "PipeRelay.cpp",
+        "TableEntry.cpp",
+        "TextTable.cpp",
         "utils.cpp",
     ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 }
 
 cc_defaults {
@@ -37,10 +48,15 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
+        "libhidl-gen-utils",
         "libhidltransport",
         "liblshal",
         "libutils",
-    ]
+    ],
+    static_libs: [
+        "libprocpartition",
+    ],
+    cflags: ["-Wall", "-Werror"],
 }
 
 cc_binary {
@@ -59,6 +75,7 @@
         "libgmock"
     ],
     shared_libs: [
+        "libvintf",
         "android.hardware.tests.baz@1.0"
     ],
     srcs: [
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
new file mode 100644
index 0000000..4f128ab
--- /dev/null
+++ b/cmds/lshal/Command.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_COMMAND_H_
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+// Base class for all *Commands
+class Command {
+public:
+    Command(Lshal& lshal) : mLshal(lshal) {}
+    virtual ~Command() = default;
+    // Expect optind to be set by Lshal::main and points to the next argument
+    // to process.
+    virtual Status main(const Arg &arg) = 0;
+
+    virtual void usage() const = 0;
+
+    // e.g. "list"
+    virtual std::string getName() const = 0;
+
+    // e.g. "list HALs"
+    virtual std::string getSimpleDescription() const = 0;
+
+protected:
+    Lshal& mLshal;
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index 672cad6..dd8812d 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -18,17 +18,31 @@
 
 #include "Lshal.h"
 
+#include <hidl-util/FQName.h>
+
 namespace android {
 namespace lshal {
 
-DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+std::string DebugCommand::getName() const {
+    return "debug";
 }
 
-Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+std::string DebugCommand::getSimpleDescription() const {
+    return "Debug a specified HAL.";
+}
+
+Status DebugCommand::parseArgs(const Arg &arg) {
     if (optind >= arg.argc) {
-        mLshal.usage(command);
         return USAGE;
     }
+
+    // Optargs cannnot be used because the flag should not be considered set
+    // if it should really be contained in mOptions.
+    if (std::string(arg.argv[optind]) == "-E") {
+        mExcludesParentInstances = true;
+        optind++;
+    }
+
     mInterfaceName = arg.argv[optind];
     ++optind;
     for (; optind < arg.argc; ++optind) {
@@ -37,18 +51,41 @@
     return OK;
 }
 
-Status DebugCommand::main(const std::string &command, const Arg &arg) {
-    Status status = parseArgs(command, arg);
+Status DebugCommand::main(const Arg &arg) {
+    Status status = parseArgs(arg);
     if (status != OK) {
         return status;
     }
+
     auto pair = splitFirst(mInterfaceName, '/');
+
+    FQName fqName(pair.first);
+    if (!fqName.isValid() || fqName.isIdentifier() || !fqName.isFullyQualified()) {
+        mLshal.err() << "Invalid fully-qualified name '" << pair.first << "'\n\n";
+        return USAGE;
+    }
+
     return mLshal.emitDebugInfo(
             pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+            mExcludesParentInstances,
             mLshal.out().buf(),
             mLshal.err());
 }
 
+void DebugCommand::usage() const {
+
+    static const std::string debug =
+            "debug:\n"
+            "    lshal debug [-E] <interface> [options [options [...]]] \n"
+            "        Print debug information of a specified interface.\n"
+            "        -E: excludes debug output if HAL is actually a subclass.\n"
+            "        <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+            "            If instance name is missing `default` is used.\n"
+            "        options: space separated options to IBase::debug.\n";
+
+    mLshal.err() << debug;
+}
+
 }  // namespace lshal
 }  // namespace android
 
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index fa0f0fa..6e12008 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -21,6 +21,7 @@
 
 #include <android-base/macros.h>
 
+#include "Command.h"
 #include "utils.h"
 
 namespace android {
@@ -28,17 +29,24 @@
 
 class Lshal;
 
-class DebugCommand {
+class DebugCommand : public Command {
 public:
-    DebugCommand(Lshal &lshal);
-    Status main(const std::string &command, const Arg &arg);
+    DebugCommand(Lshal &lshal) : Command(lshal) {}
+    ~DebugCommand() = default;
+    Status main(const Arg &arg) override;
+    void usage() const override;
+    std::string getSimpleDescription() const override;
+    std::string getName() const override;
 private:
-    Status parseArgs(const std::string &command, const Arg &arg);
+    Status parseArgs(const Arg &arg);
 
-    Lshal &mLshal;
     std::string mInterfaceName;
     std::vector<std::string> mOptions;
 
+    // Outputs the actual descriptor of a hal instead of the debug output
+    // if the arguments provided are a superclass of the actual hal impl.
+    bool mExcludesParentInstances;
+
     DISALLOW_COPY_AND_ASSIGN(DebugCommand);
 };
 
diff --git a/cmds/lshal/HelpCommand.cpp b/cmds/lshal/HelpCommand.cpp
new file mode 100644
index 0000000..6773ace
--- /dev/null
+++ b/cmds/lshal/HelpCommand.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HelpCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+std::string HelpCommand::GetName() {
+    return "help";
+}
+
+std::string HelpCommand::getSimpleDescription() const {
+    return "Print help message.";
+}
+
+Status HelpCommand::main(const Arg &arg) {
+    if (optind >= arg.argc) {
+        // `lshal help` prints global usage.
+        mLshal.usage();
+        return OK;
+    }
+    (void)usageOfCommand(arg.argv[optind]);
+    return OK;
+}
+
+Status HelpCommand::usageOfCommand(const std::string& c) const {
+    if (c.empty()) {
+        mLshal.usage();
+        return USAGE;
+    }
+    auto command = mLshal.selectCommand(c);
+    if (command == nullptr) {
+        // from HelpCommand::main, `lshal help unknown`
+        mLshal.usage();
+        return USAGE;
+    }
+
+    command->usage();
+    return USAGE;
+
+}
+
+void HelpCommand::usage() const {
+    mLshal.err()
+            << "help:" << std::endl
+            << "    lshal -h" << std::endl
+            << "    lshal --help" << std::endl
+            << "    lshal help" << std::endl
+            << "        Print this help message" << std::endl;
+    mLshal.forEachCommand([&](const Command* e) {
+        mLshal.err() << "    lshal help " << e->getName() << std::endl
+                     << "        Print help message for " << e->getName() << std::endl;
+    });
+
+}
+
+}  // namespace lshal
+}  // namespace android
+
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
new file mode 100644
index 0000000..cc709f8
--- /dev/null
+++ b/cmds/lshal/HelpCommand.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "Command.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class HelpCommand : public Command {
+public:
+    HelpCommand(Lshal &lshal) : Command(lshal) {}
+    ~HelpCommand() = default;
+    Status main(const Arg &arg) override;
+    void usage() const override;
+    std::string getSimpleDescription() const override;
+    std::string getName() const override { return GetName(); }
+    static std::string GetName();
+    Status usageOfCommand(const std::string& c) const;
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_HELP_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 7c6cfd9..ff22048 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -25,12 +25,15 @@
 #include <sstream>
 #include <regex>
 
+#include <android-base/file.h>
 #include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-hash/Hash.h>
 #include <hidl-util/FQName.h>
 #include <private/android_filesystem_config.h>
 #include <sys/stat.h>
 #include <vintf/HalManifest.h>
+#include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
 
 #include "Lshal.h"
@@ -39,22 +42,35 @@
 #include "utils.h"
 
 using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceManager;
 
 namespace android {
 namespace lshal {
 
-ListCommand::ListCommand(Lshal &lshal) : mLshal(lshal), mErr(lshal.err()), mOut(lshal.out()) {
+vintf::SchemaType toSchemaType(Partition p) {
+    return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
 }
 
-std::string getCmdline(pid_t pid) {
-    std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
-    std::string cmdline;
-    if (!ifs.is_open()) {
-        return "";
-    }
-    ifs >> cmdline;
-    return cmdline;
+NullableOStream<std::ostream> ListCommand::out() const {
+    return mLshal.out();
+}
+
+NullableOStream<std::ostream> ListCommand::err() const {
+    return mLshal.err();
+}
+
+std::string ListCommand::GetName() {
+    return "list";
+}
+std::string ListCommand::getSimpleDescription() const {
+    return "List HALs.";
+}
+
+std::string ListCommand::parseCmdline(pid_t pid) const {
+    return android::procpartition::getCmdline(pid);
 }
 
 const std::string &ListCommand::getCmdline(pid_t pid) {
@@ -62,7 +78,7 @@
     if (pair != mCmdlines.end()) {
         return pair->second;
     }
-    mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+    mCmdlines[pid] = parseCmdline(pid);
     return mCmdlines[pid];
 }
 
@@ -73,7 +89,43 @@
     }), pids->end());
 }
 
-bool scanBinderContext(pid_t pid,
+Partition ListCommand::getPartition(pid_t pid) {
+    auto it = mPartitions.find(pid);
+    if (it != mPartitions.end()) {
+        return it->second;
+    }
+    Partition partition = android::procpartition::getPartition(pid);
+    mPartitions.emplace(pid, partition);
+    return partition;
+}
+
+// Give sensible defaults when nothing can be inferred from runtime.
+// process: Partition inferred from executable location or cmdline.
+Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
+    if (fqName.inPackage("vendor") ||
+        fqName.inPackage("com")) {
+        return Partition::VENDOR;
+    }
+
+    if (fqName.inPackage("android.frameworks") ||
+        fqName.inPackage("android.system") ||
+        fqName.inPackage("android.hidl")) {
+        return Partition::SYSTEM;
+    }
+
+    // Some android.hardware HALs are served from system. Check the value from executable
+    // location / cmdline first.
+    if (fqName.inPackage("android.hardware")) {
+        if (process != Partition::UNKNOWN) {
+            return process;
+        }
+        return Partition::VENDOR;
+    }
+
+    return process;
+}
+
+static bool scanBinderContext(pid_t pid,
         const std::string &contextName,
         std::function<void(const std::string&)> eachLine) {
     std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
@@ -113,7 +165,7 @@
             uint64_t ptr;
             if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
                 // Should not reach here, but just be tolerant.
-                mErr << "Could not parse number " << ptrString << std::endl;
+                err() << "Could not parse number " << ptrString << std::endl;
                 return;
             }
             const std::string proc = " proc ";
@@ -122,7 +174,7 @@
                 for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
                     int32_t pid;
                     if (!::android::base::ParseInt(pidStr, &pid)) {
-                        mErr << "Could not parse number " << pidStr << std::endl;
+                        err() << "Could not parse number " << pidStr << std::endl;
                         return;
                     }
                     pidInfo->refPids[ptr].push_back(pid);
@@ -159,6 +211,16 @@
     });
 }
 
+const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+    auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+    if (pair.second /* did insertion take place? */) {
+        if (!getPidInfo(serverPid, &pair.first->second)) {
+            return nullptr;
+        }
+    }
+    return &pair.first->second;
+}
+
 // Must process hwbinder services first, then passthrough services.
 void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
     f(mServicesTable);
@@ -183,6 +245,9 @@
                 entry.clientCmdlines.push_back(this->getCmdline(pid));
             }
         }
+        for (TableEntry& entry : table) {
+            entry.partition = getPartition(entry.serverPid);
+        }
     });
     // use a double for loop here because lshal doesn't care about efficiency.
     for (TableEntry &packageEntry : mImplementationsTable) {
@@ -204,44 +269,19 @@
             }
         }
     }
-}
 
-void ListCommand::printLine(
-        const std::string &interfaceName,
-        const std::string &transport,
-        const std::string &arch,
-        const std::string &threadUsage,
-        const std::string &server,
-        const std::string &serverCmdline,
-        const std::string &address,
-        const std::string &clients,
-        const std::string &clientCmdlines) const {
-    if (mSelectedColumns & ENABLE_INTERFACE_NAME)
-        mOut << std::setw(80) << interfaceName << "\t";
-    if (mSelectedColumns & ENABLE_TRANSPORT)
-        mOut << std::setw(10) << transport << "\t";
-    if (mSelectedColumns & ENABLE_ARCH)
-        mOut << std::setw(5) << arch << "\t";
-    if (mSelectedColumns & ENABLE_THREADS) {
-        mOut << std::setw(8) << threadUsage << "\t";
-    }
-    if (mSelectedColumns & ENABLE_SERVER_PID) {
-        if (mEnableCmdlines) {
-            mOut << std::setw(15) << serverCmdline << "\t";
-        } else {
-            mOut << std::setw(5)  << server << "\t";
-        }
-    }
-    if (mSelectedColumns & ENABLE_SERVER_ADDR)
-        mOut << std::setw(16) << address << "\t";
-    if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
-        if (mEnableCmdlines) {
-            mOut << std::setw(0)  << clientCmdlines;
-        } else {
-            mOut << std::setw(0)  << clients;
-        }
-    }
-    mOut << std::endl;
+    mServicesTable.setDescription(
+            "All binderized services (registered services through hwservicemanager)");
+    mPassthroughRefTable.setDescription(
+            "All interfaces that getService() has ever return as a passthrough interface;\n"
+            "PIDs / processes shown below might be inaccurate because the process\n"
+            "might have relinquished the interface or might have died.\n"
+            "The Server / Server CMD column can be ignored.\n"
+            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+            "the library and successfully fetched the passthrough implementation.");
+    mImplementationsTable.setDescription(
+            "All available passthrough implementations (all -impl.so files).\n"
+            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
 }
 
 static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
@@ -254,23 +294,12 @@
     return false;
 }
 
-void ListCommand::dumpVintf() const {
+void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
     using vintf::operator|=;
-    mOut << "<!-- " << std::endl
-         << "    This is a skeleton device manifest. Notes: " << std::endl
-         << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
-         << "    2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
-         << "       only hwbinder is shown." << std::endl
-         << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
-         << "       <interface> declared; users will have to write them by hand." << std::endl
-         << "    4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
-         << "       higher minor version if they have the same name and major version." << std::endl
-         << "    5. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
-         << "       is removed from the manifest file and written by assemble_vintf" << std::endl
-         << "       at build time." << std::endl
-         << "-->" << std::endl;
+    using vintf::operator<<;
 
     vintf::HalManifest manifest;
+    manifest.setType(toSchemaType(mVintfPartition));
     forEachTable([this, &manifest] (const Table &table) {
         for (const TableEntry &entry : table) {
 
@@ -283,16 +312,27 @@
             auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
             FQName fqName(splittedFqInstanceName.first);
             if (!fqName.isValid()) {
-                mErr << "Warning: '" << splittedFqInstanceName.first
+                err() << "Warning: '" << splittedFqInstanceName.first
                      << "' is not a valid FQName." << std::endl;
                 continue;
             }
-            // Strip out system libs.
-            if (fqName.inPackage("android.hidl") ||
-                fqName.inPackage("android.frameworks") ||
-                fqName.inPackage("android.system")) {
+
+            if (fqName.package() == gIBaseFqName.package()) {
+                continue; // always remove IBase from manifest
+            }
+
+            Partition partition = resolvePartition(entry.partition, fqName);
+
+            if (partition == Partition::UNKNOWN) {
+                err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
+                      << ". It is removed from the generated manifest." << std::endl;
                 continue;
             }
+
+            if (partition != mVintfPartition) {
+                continue; // strip out instances that is in a different partition.
+            }
+
             std::string interfaceName =
                     &table == &mImplementationsTable ? "" : fqName.name();
             std::string instanceName =
@@ -316,12 +356,12 @@
                         arch = vintf::Arch::ARCH_32_64; break;
                     case lshal::ARCH_UNKNOWN: // fallthrough
                     default:
-                        mErr << "Warning: '" << fqName.package()
+                        err() << "Warning: '" << fqName.package()
                              << "' doesn't have bitness info, assuming 32+64." << std::endl;
                         arch = vintf::Arch::ARCH_32_64;
                 }
             } else {
-                mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+                err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
                 continue;
             }
 
@@ -329,7 +369,7 @@
             for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
                 if (hal->transport() != transport) {
                     if (transport != vintf::Transport::PASSTHROUGH) {
-                        mErr << "Fatal: should not reach here. Generated result may be wrong for '"
+                        err() << "Fatal: should not reach here. Generated result may be wrong for '"
                              << hal->name << "'."
                              << std::endl;
                     }
@@ -338,8 +378,7 @@
                 }
                 if (findAndBumpVersion(hal, version)) {
                     if (&table != &mImplementationsTable) {
-                        hal->interfaces[interfaceName].name = interfaceName;
-                        hal->interfaces[interfaceName].instances.insert(instanceName);
+                        hal->insertLegacyInstance(interfaceName, instanceName);
                     }
                     hal->transportArch.arch |= arch;
                     done = true;
@@ -349,41 +388,35 @@
             if (done) {
                 continue; // to next TableEntry
             }
-            decltype(vintf::ManifestHal::interfaces) interfaces;
+            vintf::ManifestHal manifestHal{
+                    vintf::HalFormat::HIDL,
+                    std::string{fqName.package()},
+                    {version},
+                    {transport, arch},
+                    {}};
             if (&table != &mImplementationsTable) {
-                interfaces[interfaceName].name = interfaceName;
-                interfaces[interfaceName].instances.insert(instanceName);
+                manifestHal.insertLegacyInstance(interfaceName, instanceName);
             }
-            if (!manifest.add(vintf::ManifestHal{
-                    .format = vintf::HalFormat::HIDL,
-                    .name = fqName.package(),
-                    .versions = {version},
-                    .transportArch = {transport, arch},
-                    .interfaces = interfaces})) {
-                mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+            if (!manifest.add(std::move(manifestHal))) {
+                err() << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
             }
         }
     });
-    mOut << vintf::gHalManifestConverter(manifest);
+    out << "<!-- " << std::endl
+         << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
+         << INIT_VINTF_NOTES
+         << "-->" << std::endl;
+    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_NO_FQNAME);
 }
 
-static const std::string &getArchString(Architecture arch) {
-    static const std::string sStr64 = "64";
-    static const std::string sStr32 = "32";
-    static const std::string sStrBoth = "32+64";
-    static const std::string sStrUnknown = "";
-    switch (arch) {
-        case ARCH64:
-            return sStr64;
-        case ARCH32:
-            return sStr32;
-        case ARCH_BOTH:
-            return sStrBoth;
-        case ARCH_UNKNOWN: // fall through
-        default:
-            return sStrUnknown;
-    }
-}
+std::string ListCommand::INIT_VINTF_NOTES{
+    "    1. If a HAL is supported in both hwbinder and passthrough transport, \n"
+    "       only hwbinder is shown.\n"
+    "    2. It is likely that HALs in passthrough transport does not have\n"
+    "       <interface> declared; users will have to write them by hand.\n"
+    "    3. A HAL with lower minor version can be overridden by a HAL with\n"
+    "       higher minor version if they have the same name and major version.\n"
+};
 
 static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
     switch (a) {
@@ -397,68 +430,55 @@
     }
 }
 
-void ListCommand::dumpTable() {
-    mServicesTable.description =
-            "All binderized services (registered services through hwservicemanager)";
-    mPassthroughRefTable.description =
-            "All interfaces that getService() has ever return as a passthrough interface;\n"
-            "PIDs / processes shown below might be inaccurate because the process\n"
-            "might have relinquished the interface or might have died.\n"
-            "The Server / Server CMD column can be ignored.\n"
-            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
-            "the library and successfully fetched the passthrough implementation.";
-    mImplementationsTable.description =
-            "All available passthrough implementations (all -impl.so files)";
-    forEachTable([this] (const Table &table) {
-        if (!mNeat) {
-            mOut << table.description << std::endl;
-        }
-        mOut << std::left;
-        if (!mNeat) {
-            printLine("Interface", "Transport", "Arch", "Thread Use", "Server",
-                      "Server CMD", "PTR", "Clients", "Clients CMD");
-        }
+void ListCommand::dumpTable(const NullableOStream<std::ostream>& out) const {
+    if (mNeat) {
+        MergedTable({&mServicesTable, &mPassthroughRefTable, &mImplementationsTable})
+            .createTextTable().dump(out.buf());
+        return;
+    }
 
-        for (const auto &entry : table) {
-            printLine(entry.interfaceName,
-                    entry.transport,
-                    getArchString(entry.arch),
-                    entry.getThreadUsage(),
-                    entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
-                    entry.serverCmdline,
-                    entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
-                    join(entry.clientPids, " "),
-                    join(entry.clientCmdlines, ";"));
+    forEachTable([this, &out](const Table &table) {
 
-            // We're only interested in dumping debug info for already
-            // instantiated services. There's little value in dumping the
-            // debug info for a service we create on the fly, so we only operate
-            // on the "mServicesTable".
-            if (mEmitDebugInfo && &table == &mServicesTable) {
-                auto pair = splitFirst(entry.interfaceName, '/');
-                mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
-                        NullableOStream<std::ostream>(nullptr));
-            }
+        // We're only interested in dumping debug info for already
+        // instantiated services. There's little value in dumping the
+        // debug info for a service we create on the fly, so we only operate
+        // on the "mServicesTable".
+        std::function<std::string(const std::string&)> emitDebugInfo = nullptr;
+        if (mEmitDebugInfo && &table == &mServicesTable) {
+            emitDebugInfo = [this](const auto& iName) {
+                std::stringstream ss;
+                auto pair = splitFirst(iName, '/');
+                mLshal.emitDebugInfo(pair.first, pair.second, {},
+                                     false /* excludesParentInstances */, ss,
+                                     NullableOStream<std::ostream>(nullptr));
+                return ss.str();
+            };
         }
-        if (!mNeat) {
-            mOut << std::endl;
-        }
+        table.createTextTable(mNeat, emitDebugInfo).dump(out.buf());
+        out << std::endl;
     });
-
 }
 
-void ListCommand::dump() {
-    if (mVintf) {
-        dumpVintf();
-        if (!!mFileOutput) {
-            mFileOutput.buf().close();
-            delete &mFileOutput.buf();
-            mFileOutput = nullptr;
-        }
-        mOut = std::cout;
-    } else {
-        dumpTable();
+Status ListCommand::dump() {
+    auto dump = mVintf ? &ListCommand::dumpVintf : &ListCommand::dumpTable;
+
+    if (mFileOutputPath.empty()) {
+        (*this.*dump)(out());
+        return OK;
     }
+
+    std::ofstream fileOutput(mFileOutputPath);
+    if (!fileOutput.is_open()) {
+        err() << "Could not open file '" << mFileOutputPath << "'." << std::endl;
+        return IO_ERROR;
+    }
+    chown(mFileOutputPath.c_str(), AID_SHELL, AID_SHELL);
+
+    (*this.*dump)(NullableOStream<std::ostream>(fileOutput));
+
+    fileOutput.flush();
+    fileOutput.close();
+    return OK;
 }
 
 void ListCommand::putEntry(TableEntrySource source, TableEntry &&entry) {
@@ -471,10 +491,10 @@
         case LIST_DLLIB :
             table = &mImplementationsTable; break;
         default:
-            mErr << "Error: Unknown source of entry " << source << std::endl;
+            err() << "Error: Unknown source of entry " << source << std::endl;
     }
     if (table) {
-        table->entries.push_back(std::forward<TableEntry>(entry));
+        table->add(std::forward<TableEntry>(entry));
     }
 }
 
@@ -483,7 +503,7 @@
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
     using std::literals::chrono_literals::operator""s;
-    auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+    auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         std::map<std::string, TableEntry> entries;
         for (const auto &info : infos) {
             std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
@@ -491,10 +511,7 @@
             entries.emplace(interfaceName, TableEntry{
                 .interfaceName = interfaceName,
                 .transport = "passthrough",
-                .serverPid = NO_PID,
-                .serverObjectAddress = NO_PTR,
                 .clientPids = info.clientPids,
-                .arch = ARCH_UNKNOWN
             }).first->second.arch |= fromBaseArchitecture(info.arch);
         }
         for (auto &&pair : entries) {
@@ -502,7 +519,7 @@
         }
     });
     if (!ret.isOk()) {
-        mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+        err() << "Error: Failed to call list on getPassthroughServiceManager(): "
              << ret.description() << std::endl;
         return DUMP_ALL_LIBS_ERROR;
     }
@@ -525,14 +542,13 @@
                         std::string{info.instanceName.c_str()},
                 .transport = "passthrough",
                 .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
-                .serverObjectAddress = NO_PTR,
                 .clientPids = info.clientPids,
                 .arch = fromBaseArchitecture(info.arch)
             });
         }
     });
     if (!ret.isOk()) {
-        mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+        err() << "Error: Failed to call debugDump on defaultServiceManager(): "
              << ret.description() << std::endl;
         return DUMP_PASSTHROUGH_ERROR;
     }
@@ -540,10 +556,6 @@
 }
 
 Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
-    using namespace ::std;
-    using namespace ::android::hardware;
-    using namespace ::android::hidl::manager::V1_0;
-    using namespace ::android::hidl::base::V1_0;
     const std::string mode = "hwbinder";
 
     hidl_vec<hidl_string> fqInstanceNames;
@@ -552,86 +564,123 @@
         fqInstanceNames = names;
     });
     if (!listRet.isOk()) {
-        mErr << "Error: Failed to list services for " << mode << ": "
+        err() << "Error: Failed to list services for " << mode << ": "
              << listRet.description() << std::endl;
         return DUMP_BINDERIZED_ERROR;
     }
 
     Status status = OK;
-    // server pid, .ptr value of binder object, child pids
-    std::map<std::string, DebugInfo> allDebugInfos;
-    std::map<pid_t, PidInfo> allPids;
+    std::map<std::string, TableEntry> allTableEntries;
     for (const auto &fqInstanceName : fqInstanceNames) {
-        const auto pair = splitFirst(fqInstanceName, '/');
-        const auto &serviceName = pair.first;
-        const auto &instanceName = pair.second;
-        auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
-        if (!getRet.isOk()) {
-            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                 << "cannot be fetched from service manager:"
-                 << getRet.description() << std::endl;
-            status |= DUMP_BINDERIZED_ERROR;
-            continue;
-        }
-        sp<IBase> service = getRet;
-        if (service == nullptr) {
-            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                 << "cannot be fetched from service manager (null)"
-                 << std::endl;
-            status |= DUMP_BINDERIZED_ERROR;
-            continue;
-        }
-        auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
-            allDebugInfos[fqInstanceName] = debugInfo;
-            if (debugInfo.pid >= 0) {
-                allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
-            }
+        // create entry and default assign all fields.
+        TableEntry& entry = allTableEntries[fqInstanceName];
+        entry.interfaceName = fqInstanceName;
+        entry.transport = mode;
+
+        status |= fetchBinderizedEntry(manager, &entry);
+    }
+
+    for (auto& pair : allTableEntries) {
+        putEntry(HWSERVICEMANAGER_LIST, std::move(pair.second));
+    }
+    return status;
+}
+
+Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager,
+                                         TableEntry *entry) {
+    Status status = OK;
+    const auto handleError = [&](Status additionalError, const std::string& msg) {
+        err() << "Warning: Skipping \"" << entry->interfaceName << "\": " << msg << std::endl;
+        status |= DUMP_BINDERIZED_ERROR | additionalError;
+    };
+
+    const auto pair = splitFirst(entry->interfaceName, '/');
+    const auto &serviceName = pair.first;
+    const auto &instanceName = pair.second;
+    auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+    if (!getRet.isOk()) {
+        handleError(TRANSACTION_ERROR,
+                    "cannot be fetched from service manager:" + getRet.description());
+        return status;
+    }
+    sp<IBase> service = getRet;
+    if (service == nullptr) {
+        handleError(NO_INTERFACE, "cannot be fetched from service manager (null)");
+        return status;
+    }
+
+    // getDebugInfo
+    do {
+        DebugInfo debugInfo;
+        auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) {
+            debugInfo = received;
         });
         if (!debugRet.isOk()) {
-            mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                 << "debugging information cannot be retrieved:"
-                 << debugRet.description() << std::endl;
-            status |= DUMP_BINDERIZED_ERROR;
+            handleError(TRANSACTION_ERROR,
+                        "debugging information cannot be retrieved: " + debugRet.description());
+            break; // skip getPidInfo
         }
-    }
 
-    for (auto &pair : allPids) {
-        pid_t serverPid = pair.first;
-        if (!getPidInfo(serverPid, &allPids[serverPid])) {
-            mErr << "Warning: no information for PID " << serverPid
-                      << ", are you root?" << std::endl;
-            status |= DUMP_BINDERIZED_ERROR;
-        }
-    }
-    for (const auto &fqInstanceName : fqInstanceNames) {
-        auto it = allDebugInfos.find(fqInstanceName);
-        if (it == allDebugInfos.end()) {
-            putEntry(HWSERVICEMANAGER_LIST, {
-                .interfaceName = fqInstanceName,
-                .transport = mode,
-                .serverPid = NO_PID,
-                .serverObjectAddress = NO_PTR,
-                .clientPids = {},
-                .threadUsage = 0,
-                .threadCount = 0,
-                .arch = ARCH_UNKNOWN
-            });
-            continue;
-        }
-        const DebugInfo &info = it->second;
-        bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+        entry->serverPid = debugInfo.pid;
+        entry->serverObjectAddress = debugInfo.ptr;
+        entry->arch = fromBaseArchitecture(debugInfo.arch);
 
-        putEntry(HWSERVICEMANAGER_LIST, {
-            .interfaceName = fqInstanceName,
-            .transport = mode,
-            .serverPid = info.pid,
-            .serverObjectAddress = info.ptr,
-            .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
-            .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
-            .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
-            .arch = fromBaseArchitecture(info.arch),
+        if (debugInfo.pid != NO_PID) {
+            const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+            if (pidInfo == nullptr) {
+                handleError(IO_ERROR,
+                            "no information for PID " + std::to_string(debugInfo.pid) +
+                            ", are you root?");
+                break;
+            }
+            if (debugInfo.ptr != NO_PTR) {
+                auto it = pidInfo->refPids.find(debugInfo.ptr);
+                if (it != pidInfo->refPids.end()) {
+                    entry->clientPids = it->second;
+                }
+            }
+            entry->threadUsage = pidInfo->threadUsage;
+            entry->threadCount = pidInfo->threadCount;
+        }
+    } while (0);
+
+    // hash
+    do {
+        ssize_t hashIndex = -1;
+        auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) {
+            for (size_t i = 0; i < c.size(); ++i) {
+                if (serviceName == c[i]) {
+                    hashIndex = static_cast<ssize_t>(i);
+                    break;
+                }
+            }
         });
-    }
+        if (!ifaceChainRet.isOk()) {
+            handleError(TRANSACTION_ERROR,
+                        "interfaceChain fails: " + ifaceChainRet.description());
+            break; // skip getHashChain
+        }
+        if (hashIndex < 0) {
+            handleError(BAD_IMPL, "Interface name does not exist in interfaceChain.");
+            break; // skip getHashChain
+        }
+        auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) {
+            if (static_cast<size_t>(hashIndex) >= hashChain.size()) {
+                handleError(BAD_IMPL,
+                            "interfaceChain indicates position " + std::to_string(hashIndex) +
+                            " but getHashChain returns " + std::to_string(hashChain.size()) +
+                            " hashes");
+                return;
+            }
+
+            auto&& hashArray = hashChain[hashIndex];
+            std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
+            entry->hash = Hash::hexString(hashVec);
+        });
+        if (!hashRet.isOk()) {
+            handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
+        }
+    } while (0);
     return status;
 }
 
@@ -639,7 +688,7 @@
     Status status = OK;
     auto bManager = mLshal.serviceManager();
     if (bManager == nullptr) {
-        mErr << "Failed to get defaultServiceManager()!" << std::endl;
+        err() << "Failed to get defaultServiceManager()!" << std::endl;
         status |= NO_BINDERIZED_MANAGER;
     } else {
         status |= fetchBinderized(bManager);
@@ -649,7 +698,7 @@
 
     auto pManager = mLshal.passthroughManager();
     if (pManager == nullptr) {
-        mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+        err() << "Failed to get getPassthroughServiceManager()!" << std::endl;
         status |= NO_PASSTHROUGH_MANAGER;
     } else {
         status |= fetchAllLibraries(pManager);
@@ -657,139 +706,279 @@
     return status;
 }
 
-Status ListCommand::parseArgs(const std::string &command, const Arg &arg) {
-    static struct option longOptions[] = {
-        // long options with short alternatives
-        {"help",      no_argument,       0, 'h' },
-        {"interface", no_argument,       0, 'i' },
-        {"transport", no_argument,       0, 't' },
-        {"arch",      no_argument,       0, 'r' },
-        {"pid",       no_argument,       0, 'p' },
-        {"address",   no_argument,       0, 'a' },
-        {"clients",   no_argument,       0, 'c' },
-        {"threads",   no_argument,       0, 'e' },
-        {"cmdline",   no_argument,       0, 'm' },
-        {"debug",     optional_argument, 0, 'd' },
+void ListCommand::registerAllOptions() {
+    int v = mOptions.size();
+    // A list of acceptable command line options
+    // key: value returned by getopt_long
+    // long options with short alternatives
+    mOptions.push_back({'h', "help", no_argument, v++, [](ListCommand*, const char*) {
+        return USAGE;
+    }, ""});
+    mOptions.push_back({'i', "interface", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::INTERFACE_NAME);
+        return OK;
+    }, "print the instance name column"});
+    mOptions.push_back({'l', "released", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::RELEASED);
+        return OK;
+    }, "print the 'is released?' column\n(Y=released, empty=unreleased or unknown)"});
+    mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
+        return OK;
+    }, "print the transport mode column"});
+    mOptions.push_back({'r', "arch", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::ARCH);
+        return OK;
+    }, "print the bitness column"});
+    mOptions.push_back({'s', "hash", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::HASH);
+        return OK;
+    }, "print hash of the interface"});
+    mOptions.push_back({'p', "pid", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::SERVER_PID);
+        return OK;
+    }, "print the server PID, or server cmdline if -m is set"});
+    mOptions.push_back({'a', "address", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::SERVER_ADDR);
+        return OK;
+    }, "print the server object address column"});
+    mOptions.push_back({'c', "clients", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::CLIENT_PIDS);
+        return OK;
+    }, "print the client PIDs, or client cmdlines if -m is set"});
+    mOptions.push_back({'e', "threads", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::THREADS);
+        return OK;
+    }, "print currently used/available threads\n(note, available threads created lazily)"});
+    mOptions.push_back({'m', "cmdline", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mEnableCmdlines = true;
+        return OK;
+    }, "print cmdline instead of PIDs"});
+    mOptions.push_back({'d', "debug", optional_argument, v++, [](ListCommand* thiz, const char* arg) {
+        thiz->mEmitDebugInfo = true;
+        if (arg) thiz->mFileOutputPath = arg;
+        return OK;
+    }, "Emit debug info from\nIBase::debug with empty options. Cannot be used with --neat.\n"
+        "Writes to specified file if 'arg' is provided, otherwise stdout."});
 
-        // long options without short alternatives
-        {"sort",      required_argument, 0, 's' },
-        {"init-vintf",optional_argument, 0, 'v' },
-        {"neat",      no_argument,       0, 'n' },
-        { 0,          0,                 0,  0  }
-    };
+    // long options without short alternatives
+    mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
+        thiz->mVintf = true;
+        if (thiz->mVintfPartition == Partition::UNKNOWN)
+            thiz->mVintfPartition = Partition::VENDOR;
+        if (arg) thiz->mFileOutputPath = arg;
+        return OK;
+    }, "form a skeleton HAL manifest to specified file,\nor stdout if no file specified."});
+    mOptions.push_back({'\0', "init-vintf-partition", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+        if (!arg) return USAGE;
+        thiz->mVintfPartition = android::procpartition::parsePartition(arg);
+        if (thiz->mVintfPartition == Partition::UNKNOWN) return USAGE;
+        return OK;
+    }, "Specify the partition of the HAL manifest\ngenerated by --init-vintf.\n"
+       "Valid values are 'system', 'vendor', and 'odm'. Default is 'vendor'."});
+    mOptions.push_back({'\0', "sort", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+        if (strcmp(arg, "interface") == 0 || strcmp(arg, "i") == 0) {
+            thiz->mSortColumn = TableEntry::sortByInterfaceName;
+        } else if (strcmp(arg, "pid") == 0 || strcmp(arg, "p") == 0) {
+            thiz->mSortColumn = TableEntry::sortByServerPid;
+        } else {
+            thiz->err() << "Unrecognized sorting column: " << arg << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }, "sort by a column. 'arg' can be (i|interface) or (p|pid)."});
+    mOptions.push_back({'\0', "neat", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mNeat = true;
+        return OK;
+    }, "output is machine parsable (no explanatory text).\nCannot be used with --debug."});
+}
+
+// Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
+// the lifetime of "options" during the usage of the returned array.
+static std::unique_ptr<struct option[]> getLongOptions(
+        const ListCommand::RegisteredOptions& options,
+        int* longOptFlag) {
+    std::unique_ptr<struct option[]> ret{new struct option[options.size() + 1]};
+    int i = 0;
+    for (const auto& e : options) {
+        ret[i].name = e.longOption.c_str();
+        ret[i].has_arg = e.hasArg;
+        ret[i].flag = longOptFlag;
+        ret[i].val = e.val;
+
+        i++;
+    }
+    // getopt_long last option has all zeros
+    ret[i].name = NULL;
+    ret[i].has_arg = 0;
+    ret[i].flag = NULL;
+    ret[i].val = 0;
+
+    return ret;
+}
+
+// Create 'optstring' argument to getopt_long.
+static std::string getShortOptions(const ListCommand::RegisteredOptions& options) {
+    std::stringstream ss;
+    for (const auto& e : options) {
+        if (e.shortOption != '\0') {
+            ss << e.shortOption;
+        }
+    }
+    return ss.str();
+}
+
+Status ListCommand::parseArgs(const Arg &arg) {
+
+    if (mOptions.empty()) {
+        registerAllOptions();
+    }
+    int longOptFlag;
+    std::unique_ptr<struct option[]> longOptions = getLongOptions(mOptions, &longOptFlag);
+    std::string shortOptions = getShortOptions(mOptions);
+
+    // suppress output to std::err for unknown options
+    opterr = 0;
 
     int optionIndex;
     int c;
     // Lshal::parseArgs has set optind to the next option to parse
     for (;;) {
-        // using getopt_long in case we want to add other options in the future
         c = getopt_long(arg.argc, arg.argv,
-                "hitrpacmde", longOptions, &optionIndex);
+                shortOptions.c_str(), longOptions.get(), &optionIndex);
         if (c == -1) {
             break;
         }
-        switch (c) {
-        case 's': {
-            if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
-                mSortColumn = TableEntry::sortByInterfaceName;
-            } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
-                mSortColumn = TableEntry::sortByServerPid;
-            } else {
-                mErr << "Unrecognized sorting column: " << optarg << std::endl;
-                mLshal.usage(command);
-                return USAGE;
+        const RegisteredOption* found = nullptr;
+        if (c == 0) {
+            // see long option
+            for (const auto& e : mOptions) {
+                if (longOptFlag == e.val) found = &e;
             }
-            break;
-        }
-        case 'v': {
-            if (optarg) {
-                mFileOutput = new std::ofstream{optarg};
-                mOut = mFileOutput;
-                if (!mFileOutput.buf().is_open()) {
-                    mErr << "Could not open file '" << optarg << "'." << std::endl;
-                    return IO_ERROR;
-                }
+        } else {
+            // see short option
+            for (const auto& e : mOptions) {
+                if (c == e.shortOption) found = &e;
             }
-            mVintf = true;
         }
-        case 'i': {
-            mSelectedColumns |= ENABLE_INTERFACE_NAME;
-            break;
-        }
-        case 't': {
-            mSelectedColumns |= ENABLE_TRANSPORT;
-            break;
-        }
-        case 'r': {
-            mSelectedColumns |= ENABLE_ARCH;
-            break;
-        }
-        case 'p': {
-            mSelectedColumns |= ENABLE_SERVER_PID;
-            break;
-        }
-        case 'a': {
-            mSelectedColumns |= ENABLE_SERVER_ADDR;
-            break;
-        }
-        case 'c': {
-            mSelectedColumns |= ENABLE_CLIENT_PIDS;
-            break;
-        }
-        case 'e': {
-            mSelectedColumns |= ENABLE_THREADS;
-            break;
-        }
-        case 'm': {
-            mEnableCmdlines = true;
-            break;
-        }
-        case 'd': {
-            mEmitDebugInfo = true;
 
-            if (optarg) {
-                mFileOutput = new std::ofstream{optarg};
-                mOut = mFileOutput;
-                if (!mFileOutput.buf().is_open()) {
-                    mErr << "Could not open file '" << optarg << "'." << std::endl;
-                    return IO_ERROR;
-                }
-                chown(optarg, AID_SHELL, AID_SHELL);
-            }
-            break;
-        }
-        case 'n': {
-            mNeat = true;
-            break;
-        }
-        case 'h': // falls through
-        default: // see unrecognized options
-            mLshal.usage(command);
+        if (found == nullptr) {
+            // see unrecognized options
+            err() << "unrecognized option `" << arg.argv[optind - 1] << "'" << std::endl;
             return USAGE;
         }
+
+        Status status = found->op(this, optarg);
+        if (status != OK) {
+            return status;
+        }
     }
     if (optind < arg.argc) {
         // see non option
-        mErr << "Unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+        err() << "unrecognized option `" << arg.argv[optind] << "'" << std::endl;
+        return USAGE;
     }
 
-    if (mSelectedColumns == 0) {
-        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS | ENABLE_THREADS;
+    if (mNeat && mEmitDebugInfo) {
+        err() << "Error: --neat should not be used with --debug." << std::endl;
+        return USAGE;
     }
+
+    if (mSelectedColumns.empty()) {
+        mSelectedColumns = {TableColumnType::RELEASED,
+                            TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
+                            TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
+    }
+
+    if (mEnableCmdlines) {
+        for (size_t i = 0; i < mSelectedColumns.size(); ++i) {
+            if (mSelectedColumns[i] == TableColumnType::SERVER_PID) {
+                mSelectedColumns[i] = TableColumnType::SERVER_CMD;
+            }
+            if (mSelectedColumns[i] == TableColumnType::CLIENT_PIDS) {
+                mSelectedColumns[i] = TableColumnType::CLIENT_CMDS;
+            }
+        }
+    }
+
+    forEachTable([this] (Table& table) {
+        table.setSelectedColumns(this->mSelectedColumns);
+    });
+
     return OK;
 }
 
-Status ListCommand::main(const std::string &command, const Arg &arg) {
-    Status status = parseArgs(command, arg);
+Status ListCommand::main(const Arg &arg) {
+    Status status = parseArgs(arg);
     if (status != OK) {
         return status;
     }
     status = fetch();
     postprocess();
-    dump();
+    status |= dump();
     return status;
 }
 
+static std::vector<std::string> splitString(const std::string &s, char c) {
+    std::vector<std::string> components;
+
+    size_t startPos = 0;
+    size_t matchPos;
+    while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+        components.push_back(s.substr(startPos, matchPos - startPos));
+        startPos = matchPos + 1;
+    }
+
+    if (startPos <= s.length()) {
+        components.push_back(s.substr(startPos));
+    }
+    return components;
+}
+
+const std::string& ListCommand::RegisteredOption::getHelpMessageForArgument() const {
+    static const std::string empty{};
+    static const std::string optional{"[=<arg>]"};
+    static const std::string required{"=<arg>"};
+
+    if (hasArg == optional_argument) {
+        return optional;
+    }
+    if (hasArg == required_argument) {
+        return required;
+    }
+    return empty;
+}
+
+void ListCommand::usage() const {
+
+    err() << "list:" << std::endl
+          << "    lshal" << std::endl
+          << "    lshal list" << std::endl
+          << "        List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
+          << "    lshal list [-h|--help]" << std::endl
+          << "        -h, --help: Print help message for list (`lshal help list`)" << std::endl
+          << "    lshal [list] [OPTIONS...]" << std::endl;
+    for (const auto& e : mOptions) {
+        if (e.help.empty()) {
+            continue;
+        }
+        err() << "        ";
+        if (e.shortOption != '\0')
+            err() << "-" << e.shortOption << e.getHelpMessageForArgument();
+        if (e.shortOption != '\0' && !e.longOption.empty())
+            err() << ", ";
+        if (!e.longOption.empty())
+            err() << "--" << e.longOption << e.getHelpMessageForArgument();
+        err() << ": ";
+        std::vector<std::string> lines = splitString(e.help, '\n');
+        for (const auto& line : lines) {
+            if (&line != &lines.front())
+                err() << "            ";
+            err() << line << std::endl;
+        }
+    }
+}
+
 }  // namespace lshal
 }  // namespace android
 
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index a75db04..1e85ea0 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -17,6 +17,7 @@
 #ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
 #define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
 
+#include <getopt.h>
 #include <stdint.h>
 
 #include <fstream>
@@ -25,9 +26,12 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
 
+#include "Command.h"
 #include "NullableOStream.h"
 #include "TableEntry.h"
+#include "TextTable.h"
 #include "utils.h"
 
 namespace android {
@@ -35,66 +39,102 @@
 
 class Lshal;
 
-class ListCommand {
+struct PidInfo {
+    std::map<uint64_t, Pids> refPids; // pids that are referenced
+    uint32_t threadUsage; // number of threads in use
+    uint32_t threadCount; // number of threads total
+};
+
+class ListCommand : public Command {
 public:
-    ListCommand(Lshal &lshal);
-    Status main(const std::string &command, const Arg &arg);
-private:
-    Status parseArgs(const std::string &command, const Arg &arg);
+    ListCommand(Lshal &lshal) : Command(lshal) {}
+    virtual ~ListCommand() = default;
+    Status main(const Arg &arg) override;
+    void usage() const override;
+    std::string getSimpleDescription() const override;
+    std::string getName() const override { return GetName(); }
+
+    static std::string GetName();
+
+    struct RegisteredOption {
+        // short alternative, e.g. 'v'. If '\0', no short options is available.
+        char shortOption;
+        // long alternative, e.g. 'init-vintf'
+        std::string longOption;
+        // no_argument, required_argument or optional_argument
+        int hasArg;
+        // value written to 'flag' by getopt_long
+        int val;
+        // operation when the argument is present
+        std::function<Status(ListCommand* thiz, const char* arg)> op;
+        // help message
+        std::string help;
+
+        const std::string& getHelpMessageForArgument() const;
+    };
+    // A list of acceptable command line options
+    // key: value returned by getopt_long
+    using RegisteredOptions = std::vector<RegisteredOption>;
+
+    static std::string INIT_VINTF_NOTES;
+
+protected:
+    Status parseArgs(const Arg &arg);
     Status fetch();
-    void postprocess();
-    void dump();
+    virtual void postprocess();
+    Status dump();
     void putEntry(TableEntrySource source, TableEntry &&entry);
     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
 
-    struct PidInfo {
-        std::map<uint64_t, Pids> refPids; // pids that are referenced
-        uint32_t threadUsage; // number of threads in use
-        uint32_t threadCount; // number of threads total
-    };
-    bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+    Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
+                                TableEntry *entry);
 
-    void dumpTable();
-    void dumpVintf() const;
-    void printLine(
-            const std::string &interfaceName,
-            const std::string &transport,
-            const std::string &arch,
-            const std::string &threadUsage,
-            const std::string &server,
-            const std::string &serverCmdline,
-            const std::string &address,
-            const std::string &clients,
-            const std::string &clientCmdlines) const;
+    // Get relevant information for a PID by parsing files under /d/binder.
+    // It is a virtual member function so that it can be mocked.
+    virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+    // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
+    const PidInfo* getPidInfoCached(pid_t serverPid);
+
+    void dumpTable(const NullableOStream<std::ostream>& out) const;
+    void dumpVintf(const NullableOStream<std::ostream>& out) const;
+    void addLine(TextTable *table, const std::string &interfaceName, const std::string &transport,
+                 const std::string &arch, const std::string &threadUsage, const std::string &server,
+                 const std::string &serverCmdline, const std::string &address,
+                 const std::string &clients, const std::string &clientCmdlines) const;
+    void addLine(TextTable *table, const TableEntry &entry);
+    // Read and return /proc/{pid}/cmdline.
+    virtual std::string parseCmdline(pid_t pid) const;
     // Return /proc/{pid}/cmdline if it exists, else empty string.
-    const std::string &getCmdline(pid_t pid);
+    const std::string& getCmdline(pid_t pid);
     // Call getCmdline on all pid in pids. If it returns empty string, the process might
     // have died, and the pid is removed from pids.
     void removeDeadProcesses(Pids *pids);
+
+    virtual Partition getPartition(pid_t pid);
+    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
+
     void forEachTable(const std::function<void(Table &)> &f);
     void forEachTable(const std::function<void(const Table &)> &f) const;
 
-    Lshal &mLshal;
+    NullableOStream<std::ostream> err() const;
+    NullableOStream<std::ostream> out() const;
+
+    void registerAllOptions();
 
     Table mServicesTable{};
     Table mPassthroughRefTable{};
     Table mImplementationsTable{};
 
-    NullableOStream<std::ostream> mErr;
-    NullableOStream<std::ostream> mOut;
-    NullableOStream<std::ofstream> mFileOutput = nullptr;
+    std::string mFileOutputPath;
     TableEntryCompare mSortColumn = nullptr;
-    TableEntrySelect mSelectedColumns = 0;
-    // If true, cmdlines will be printed instead of pid.
-    bool mEnableCmdlines = false;
 
-    // If true, calls IBase::debug(...) on each service.
     bool mEmitDebugInfo = false;
 
-    // If true, output in VINTF format.
+    // If true, output in VINTF format. Output only entries from the specified partition.
     bool mVintf = false;
+    Partition mVintfPartition = Partition::UNKNOWN;
 
     // If true, explanatory text are not emitted.
     bool mNeat = false;
@@ -104,6 +144,19 @@
     // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
     std::map<pid_t, std::string> mCmdlines;
 
+    // Cache for getPidInfo.
+    std::map<pid_t, PidInfo> mCachedPidInfos;
+
+    // Cache for getPartition.
+    std::map<pid_t, Partition> mPartitions;
+
+    RegisteredOptions mOptions;
+    // All selected columns
+    std::vector<TableColumnType> mSelectedColumns;
+    // If true, emit cmdlines instead of PIDs
+    bool mEnableCmdlines = false;
+
+private:
     DISALLOW_COPY_AND_ASSIGN(ListCommand);
 };
 
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e2d5f6d..8c83457 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -23,6 +23,7 @@
 #include <string>
 
 #include <hidl/ServiceManagement.h>
+#include <hidl/HidlTransportUtils.h>
 
 #include "DebugCommand.h"
 #include "ListCommand.h"
@@ -34,9 +35,8 @@
 using ::android::hidl::manager::V1_0::IServiceManager;
 
 Lshal::Lshal()
-    : mOut(std::cout), mErr(std::cerr),
-      mServiceManager(::android::hardware::defaultServiceManager()),
-      mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+    : Lshal(std::cout, std::cerr, ::android::hardware::defaultServiceManager(),
+            ::android::hardware::getPassthroughServiceManager()) {
 }
 
 Lshal::Lshal(std::ostream &out, std::ostream &err,
@@ -46,76 +46,39 @@
       mServiceManager(serviceManager),
       mPassthroughManager(passthroughManager) {
 
+    mRegisteredCommands.push_back({std::make_unique<ListCommand>(*this)});
+    mRegisteredCommands.push_back({std::make_unique<DebugCommand>(*this)});
+    mRegisteredCommands.push_back({std::make_unique<HelpCommand>(*this)});
 }
 
-void Lshal::usage(const std::string &command) const {
-    static const std::string helpSummary =
-            "lshal: List and debug HALs.\n"
-            "\n"
-            "commands:\n"
-            "    help            Print help message\n"
-            "    list            list HALs\n"
-            "    debug           debug a specified HAL\n"
-            "\n"
-            "If no command is specified, `list` is the default.\n";
+void Lshal::forEachCommand(const std::function<void(const Command* c)>& f) const {
+    for (const auto& e : mRegisteredCommands) f(e.get());
+}
 
-    static const std::string list =
-            "list:\n"
-            "    lshal\n"
-            "    lshal list\n"
-            "        List all hals with default ordering and columns (`lshal list -ipc`)\n"
-            "    lshal list [-h|--help]\n"
-            "        -h, --help: Print help message for list (`lshal help list`)\n"
-            "    lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n"
-            "            [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
-            "            [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
-            "            [--debug|-d[=<output file>]]\n"
-            "        -i, --interface: print the interface name column\n"
-            "        -n, --instance: print the instance name column\n"
-            "        -t, --transport: print the transport mode column\n"
-            "        -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
-            "        -e, --threads: print currently used/available threads\n"
-            "                       (note, available threads created lazily)\n"
-            "        -p, --pid: print the server PID, or server cmdline if -m is set\n"
-            "        -a, --address: print the server object address column\n"
-            "        -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
-            "        -m, --cmdline: print cmdline instead of PIDs\n"
-            "        -d[=<output file>], --debug[=<output file>]: emit debug info from \n"
-            "                IBase::debug with empty options\n"
-            "        --sort=i, --sort=interface: sort by interface name\n"
-            "        --sort=p, --sort=pid: sort by server pid\n"
-            "        --init-vintf=<output file>: form a skeleton HAL manifest to specified\n"
-            "                      file, or stdout if no file specified.\n";
+void Lshal::usage() {
+    err() << "lshal: List and debug HALs." << std::endl << std::endl
+          << "commands:" << std::endl;
 
-    static const std::string debug =
-            "debug:\n"
-            "    lshal debug <interface> [options [options [...]]] \n"
-            "        Print debug information of a specified interface.\n"
-            "        <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
-            "            If instance name is missing `default` is used.\n"
-            "        options: space separated options to IBase::debug.\n";
+    size_t nameMaxLength = 0;
+    forEachCommand([&](const Command* e) {
+        nameMaxLength = std::max(nameMaxLength, e->getName().length());
+    });
+    bool first = true;
+    forEachCommand([&](const Command* e) {
+        if (!first) err() << std::endl;
+        first = false;
+        err() << "    " << std::left << std::setw(nameMaxLength + 8) << e->getName()
+              << e->getSimpleDescription();
+    });
+    err() << std::endl << "If no command is specified, `" << ListCommand::GetName()
+          << "` is the default." << std::endl << std::endl;
 
-    static const std::string help =
-            "help:\n"
-            "    lshal -h\n"
-            "    lshal --help\n"
-            "    lshal help\n"
-            "        Print this help message\n"
-            "    lshal help list\n"
-            "        Print help message for list\n"
-            "    lshal help debug\n"
-            "        Print help message for debug\n";
-
-    if (command == "list") {
-        mErr << list;
-        return;
-    }
-    if (command == "debug") {
-        mErr << debug;
-        return;
-    }
-
-    mErr << helpSummary << "\n" << list << "\n" << debug << "\n" << help;
+    first = true;
+    forEachCommand([&](const Command* e) {
+        if (!first) err() << std::endl;
+        first = false;
+        e->usage();
+    });
 }
 
 // A unique_ptr type using a custom deleter function.
@@ -135,9 +98,11 @@
         const std::string &interfaceName,
         const std::string &instanceName,
         const std::vector<std::string> &options,
+        bool excludesParentInstances,
         std::ostream &out,
         NullableOStream<std::ostream> err) const {
     using android::hidl::base::V1_0::IBase;
+    using android::hardware::details::getDescriptor;
 
     hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
 
@@ -158,6 +123,18 @@
         return NO_INTERFACE;
     }
 
+    if (excludesParentInstances) {
+        const std::string descriptor = getDescriptor(base.get());
+        if (descriptor.empty()) {
+            std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed";
+            err << msg << std::endl;
+            LOG(ERROR) << msg;
+        }
+        if (descriptor != interfaceName) {
+            return OK;
+        }
+    }
+
     PipeRelay relay(out);
 
     if (relay.initCheck() != OK) {
@@ -186,26 +163,24 @@
 }
 
 Status Lshal::parseArgs(const Arg &arg) {
-    static std::set<std::string> sAllCommands{"list", "debug", "help"};
     optind = 1;
     if (optind >= arg.argc) {
         // no options at all.
         return OK;
     }
     mCommand = arg.argv[optind];
-    if (sAllCommands.find(mCommand) != sAllCommands.end()) {
+    if (selectCommand(mCommand) != nullptr) {
         ++optind;
         return OK; // mCommand is set correctly
     }
 
     if (mCommand.size() > 0 && mCommand[0] == '-') {
         // first argument is an option, set command to "" (which is recognized as "list")
-        mCommand = "";
+        mCommand.clear();
         return OK;
     }
 
-    mErr << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "`" << std::endl;
-    usage();
+    err() << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "'" << std::endl;
     return USAGE;
 }
 
@@ -216,27 +191,43 @@
     }
 }
 
+Command* Lshal::selectCommand(const std::string& command) const {
+    if (command.empty()) {
+        return selectCommand(ListCommand::GetName());
+    }
+    for (const auto& e : mRegisteredCommands) {
+        if (e->getName() == command) {
+            return e.get();
+        }
+    }
+    return nullptr;
+}
+
 Status Lshal::main(const Arg &arg) {
     // Allow SIGINT to terminate all threads.
     signal(SIGINT, signalHandler);
 
     Status status = parseArgs(arg);
     if (status != OK) {
+        usage();
         return status;
     }
-    if (mCommand == "help") {
-        usage(optind < arg.argc ? arg.argv[optind] : "");
+    auto c = selectCommand(mCommand);
+    if (c == nullptr) {
+        // unknown command, print global usage
+        usage();
         return USAGE;
     }
-    // Default command is list
-    if (mCommand == "list" || mCommand == "") {
-        return ListCommand{*this}.main(mCommand, arg);
+    status = c->main(arg);
+    if (status == USAGE) {
+        // bad options. Run `lshal help ${mCommand}` instead.
+        // For example, `lshal --unknown-option` becomes `lshal help` (prints global help)
+        // and `lshal list --unknown-option` becomes `lshal help list`
+        auto&& help = selectCommand(HelpCommand::GetName());
+        return static_cast<HelpCommand*>(help)->usageOfCommand(mCommand);
     }
-    if (mCommand == "debug") {
-        return DebugCommand{*this}.main(mCommand, arg);
-    }
-    usage();
-    return USAGE;
+
+    return status;
 }
 
 NullableOStream<std::ostream> Lshal::err() const {
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 00db5d0..9457f1e 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -24,6 +24,8 @@
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <utils/StrongPointer.h>
 
+#include "Command.h"
+#include "HelpCommand.h"
 #include "NullableOStream.h"
 #include "utils.h"
 
@@ -33,13 +35,15 @@
 class Lshal {
 public:
     Lshal();
+    virtual ~Lshal() {}
     Lshal(std::ostream &out, std::ostream &err,
             sp<hidl::manager::V1_0::IServiceManager> serviceManager,
             sp<hidl::manager::V1_0::IServiceManager> passthroughManager);
     Status main(const Arg &arg);
-    void usage(const std::string &command = "") const;
-    NullableOStream<std::ostream> err() const;
-    NullableOStream<std::ostream> out() const;
+    // global usage
+    void usage();
+    virtual NullableOStream<std::ostream> err() const;
+    virtual NullableOStream<std::ostream> out() const;
     const sp<hidl::manager::V1_0::IServiceManager> &serviceManager() const;
     const sp<hidl::manager::V1_0::IServiceManager> &passthroughManager() const;
 
@@ -47,18 +51,26 @@
             const std::string &interfaceName,
             const std::string &instanceName,
             const std::vector<std::string> &options,
+            bool excludesParentInstances,
             std::ostream &out,
             NullableOStream<std::ostream> err) const;
+
+    Command* selectCommand(const std::string& command) const;
+
+    void forEachCommand(const std::function<void(const Command* c)>& f) const;
+
 private:
     Status parseArgs(const Arg &arg);
+
     std::string mCommand;
-    Arg mCmdArgs;
     NullableOStream<std::ostream> mOut;
     NullableOStream<std::ostream> mErr;
 
     sp<hidl::manager::V1_0::IServiceManager> mServiceManager;
     sp<hidl::manager::V1_0::IServiceManager> mPassthroughManager;
 
+    std::vector<std::unique_ptr<Command>> mRegisteredCommands;
+
     DISALLOW_COPY_AND_ASSIGN(Lshal);
 };
 
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 54d19f6..fc40749 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -57,8 +57,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 PipeRelay::PipeRelay(std::ostream &os)
-    : mOutStream(os),
-      mInitCheck(NO_INIT) {
+    : mInitCheck(NO_INIT) {
     int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
 
     if (res < 0) {
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index 76b2b23..8dc3093 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -42,7 +42,6 @@
 private:
     struct RelayThread;
 
-    std::ostream &mOutStream;
     status_t mInitCheck;
     int mFds[2];
     sp<RelayThread> mThread;
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
new file mode 100644
index 0000000..e8792a4
--- /dev/null
+++ b/cmds/lshal/TableEntry.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "lshal"
+#include <android-base/logging.h>
+
+#include <hidl-hash/Hash.h>
+
+#include "TableEntry.h"
+
+#include "TextTable.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+static const std::string &getArchString(Architecture arch) {
+    static const std::string sStr64 = "64";
+    static const std::string sStr32 = "32";
+    static const std::string sStrBoth = "32+64";
+    static const std::string sStrUnknown = "";
+    switch (arch) {
+        case ARCH64:
+            return sStr64;
+        case ARCH32:
+            return sStr32;
+        case ARCH_BOTH:
+            return sStrBoth;
+        case ARCH_UNKNOWN: // fall through
+        default:
+            return sStrUnknown;
+    }
+}
+
+static std::string getTitle(TableColumnType type) {
+    switch (type) {
+        case TableColumnType::INTERFACE_NAME:   return "Interface";
+        case TableColumnType::TRANSPORT:        return "Transport";
+        case TableColumnType::SERVER_PID:       return "Server";
+        case TableColumnType::SERVER_CMD:       return "Server CMD";
+        case TableColumnType::SERVER_ADDR:      return "PTR";
+        case TableColumnType::CLIENT_PIDS:      return "Clients";
+        case TableColumnType::CLIENT_CMDS:      return "Clients CMD";
+        case TableColumnType::ARCH:             return "Arch";
+        case TableColumnType::THREADS:          return "Thread Use";
+        case TableColumnType::RELEASED:         return "R";
+        case TableColumnType::HASH:             return "Hash";
+        default:
+            LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
+            return "";
+    }
+}
+
+std::string TableEntry::getField(TableColumnType type) const {
+    switch (type) {
+        case TableColumnType::INTERFACE_NAME:
+            return interfaceName;
+        case TableColumnType::TRANSPORT:
+            return transport;
+        case TableColumnType::SERVER_PID:
+            return serverPid == NO_PID ? "N/A" : std::to_string(serverPid);
+        case TableColumnType::SERVER_CMD:
+            return serverCmdline;
+        case TableColumnType::SERVER_ADDR:
+            return serverObjectAddress == NO_PTR ? "N/A" : toHexString(serverObjectAddress);
+        case TableColumnType::CLIENT_PIDS:
+            return join(clientPids, " ");
+        case TableColumnType::CLIENT_CMDS:
+            return join(clientCmdlines, ";");
+        case TableColumnType::ARCH:
+            return getArchString(arch);
+        case TableColumnType::THREADS:
+            return getThreadUsage();
+        case TableColumnType::RELEASED:
+            return isReleased();
+        case TableColumnType::HASH:
+            return hash;
+        default:
+            LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
+            return "";
+    }
+}
+
+std::string TableEntry::isReleased() const {
+    static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+
+    if (hash.empty() || hash == unreleased) {
+        return " "; // unknown or unreleased
+    }
+    return "Y"; // released
+}
+
+TextTable Table::createTextTable(bool neat,
+    const std::function<std::string(const std::string&)>& emitDebugInfo) const {
+
+    TextTable textTable;
+    std::vector<std::string> row;
+    if (!neat) {
+        textTable.add(mDescription);
+
+        row.clear();
+        for (TableColumnType type : mSelectedColumns) {
+            row.push_back(getTitle(type));
+        }
+        textTable.add(std::move(row));
+    }
+
+    for (const auto& entry : mEntries) {
+        row.clear();
+        for (TableColumnType type : mSelectedColumns) {
+            row.push_back(entry.getField(type));
+        }
+        textTable.add(std::move(row));
+
+        if (emitDebugInfo) {
+            std::string debugInfo = emitDebugInfo(entry.interfaceName);
+            if (!debugInfo.empty()) textTable.add(debugInfo);
+        }
+    }
+    return textTable;
+}
+
+TextTable MergedTable::createTextTable() {
+    TextTable textTable;
+    for (const Table* table : mTables) {
+        textTable.addAll(table->createTextTable());
+    }
+    return textTable;
+}
+
+bool TableEntry::operator==(const TableEntry& other) const {
+    if (this == &other) {
+        return true;
+    }
+    return interfaceName == other.interfaceName && transport == other.transport &&
+        serverPid == other.serverPid && threadUsage == other.threadUsage &&
+        threadCount == other.threadCount && serverCmdline == other.serverCmdline &&
+        serverObjectAddress == other.serverObjectAddress && clientPids == other.clientPids &&
+        clientCmdlines == other.clientCmdlines && arch == other.arch;
+}
+
+std::string TableEntry::to_string() const {
+    std::stringstream ss;
+    ss << "name=" << interfaceName << ";transport=" << transport << ";thread=" << getThreadUsage()
+       << ";server=" << serverPid
+       << "(" << serverObjectAddress << ";" << serverCmdline << ");clients=["
+       << join(clientPids, ";") << "](" << join(clientCmdlines, ";") << ");arch="
+       << getArchString(arch);
+    return ss.str();
+
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index e04c3ca..24ea438 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -23,9 +23,14 @@
 #include <vector>
 #include <iostream>
 
+#include <procpartition/procpartition.h>
+
+#include "TextTable.h"
+
 namespace android {
 namespace lshal {
 
+using android::procpartition::Partition;
 using Pids = std::vector<int32_t>;
 
 enum : unsigned int {
@@ -43,17 +48,39 @@
 };
 using Architecture = unsigned int;
 
+enum class TableColumnType : unsigned int {
+    INTERFACE_NAME,
+    TRANSPORT,
+    SERVER_PID,
+    SERVER_CMD,
+    SERVER_ADDR,
+    CLIENT_PIDS,
+    CLIENT_CMDS,
+    ARCH,
+    THREADS,
+    RELEASED,
+    HASH,
+};
+
+enum {
+    NO_PID = -1,
+    NO_PTR = 0
+};
+
 struct TableEntry {
-    std::string interfaceName;
-    std::string transport;
-    int32_t serverPid;
-    uint32_t threadUsage;
-    uint32_t threadCount;
-    std::string serverCmdline;
-    uint64_t serverObjectAddress;
-    Pids clientPids;
-    std::vector<std::string> clientCmdlines;
-    Architecture arch;
+    std::string interfaceName{};
+    std::string transport{};
+    int32_t serverPid{NO_PID};
+    uint32_t threadUsage{0};
+    uint32_t threadCount{0};
+    std::string serverCmdline{};
+    uint64_t serverObjectAddress{NO_PTR};
+    Pids clientPids{};
+    std::vector<std::string> clientCmdlines{};
+    Architecture arch{ARCH_UNKNOWN};
+    // empty: unknown, all zeros: unreleased, otherwise: released
+    std::string hash{};
+    Partition partition{Partition::UNKNOWN};
 
     static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
         return a.interfaceName < b.interfaceName;
@@ -69,36 +96,52 @@
 
         return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
     }
+
+    std::string isReleased() const;
+
+    std::string getField(TableColumnType type) const;
+
+    bool operator==(const TableEntry& other) const;
+    std::string to_string() const;
 };
 
-struct Table {
-    using Entries = std::vector<TableEntry>;
-    std::string description;
-    Entries entries;
+using SelectedColumns = std::vector<TableColumnType>;
 
-    Entries::iterator begin() { return entries.begin(); }
-    Entries::const_iterator begin() const { return entries.begin(); }
-    Entries::iterator end() { return entries.end(); }
-    Entries::const_iterator end() const { return entries.end(); }
+class Table {
+public:
+    using Entries = std::vector<TableEntry>;
+
+    Entries::iterator begin() { return mEntries.begin(); }
+    Entries::const_iterator begin() const { return mEntries.begin(); }
+    Entries::iterator end() { return mEntries.end(); }
+    Entries::const_iterator end() const { return mEntries.end(); }
+    size_t size() const { return mEntries.size(); }
+
+    void add(TableEntry&& entry) { mEntries.push_back(std::move(entry)); }
+
+    void setSelectedColumns(const SelectedColumns& s) { mSelectedColumns = s; }
+    const SelectedColumns& getSelectedColumns() const { return mSelectedColumns; }
+
+    void setDescription(std::string&& d) { mDescription = std::move(d); }
+
+    // Write table content.
+    TextTable createTextTable(bool neat = true,
+        const std::function<std::string(const std::string&)>& emitDebugInfo = nullptr) const;
+
+private:
+    std::string mDescription;
+    Entries mEntries;
+    SelectedColumns mSelectedColumns;
 };
 
 using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
 
-enum : unsigned int {
-    ENABLE_INTERFACE_NAME = 1 << 0,
-    ENABLE_TRANSPORT      = 1 << 1,
-    ENABLE_SERVER_PID     = 1 << 2,
-    ENABLE_SERVER_ADDR    = 1 << 3,
-    ENABLE_CLIENT_PIDS    = 1 << 4,
-    ENABLE_ARCH           = 1 << 5,
-    ENABLE_THREADS        = 1 << 6,
-};
-
-using TableEntrySelect = unsigned int;
-
-enum {
-    NO_PID = -1,
-    NO_PTR = 0
+class MergedTable {
+public:
+    MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
+    TextTable createTextTable();
+private:
+    std::vector<const Table*> mTables;
 };
 
 }  // namespace lshal
diff --git a/cmds/lshal/TextTable.cpp b/cmds/lshal/TextTable.cpp
new file mode 100644
index 0000000..eca9061
--- /dev/null
+++ b/cmds/lshal/TextTable.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <iomanip>
+
+#include "TextTable.h"
+
+namespace android {
+namespace lshal {
+
+void TextTable::computeWidth(const std::vector<std::string>& v) {
+    if (mWidths.size() < v.size()) {
+        mWidths.resize(v.size());
+    }
+    for (size_t i = 0; i < v.size(); ++i) {
+        mWidths[i] = std::max(mWidths[i], v[i].length());
+    }
+}
+
+void TextTable::dump(std::ostream& out) const {
+    out << std::left;
+    for (const auto& row : mTable) {
+        if (!row.isRow()) {
+            out << row.line() << std::endl;
+            continue;
+        }
+
+        for (size_t i = 0; i < row.fields().size(); ++i) {
+            if (i != 0) {
+                out << " ";
+            }
+            // last column does not std::setw to avoid printing unnecessary spaces.
+            if (i < row.fields().size() - 1) {
+                out << std::setw(mWidths[i]);
+            }
+            out << row.fields()[i];
+        }
+        out << std::endl;
+    }
+}
+
+void TextTable::addAll(TextTable&& other) {
+    for (auto&& row : other.mTable) {
+        if (row.isRow()) {
+            computeWidth(row.fields());
+        }
+
+        mTable.emplace_back(std::move(row));
+    }
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
new file mode 100644
index 0000000..91d522a
--- /dev/null
+++ b/cmds/lshal/TextTable.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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 FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace lshal {
+
+// An element in TextTable. This is either an actual row (an array of cells
+// in this row), or a string of explanatory text.
+// To see if this is an actual row, test fields().empty().
+class TextTableRow {
+public:
+    // An empty line.
+    TextTableRow() {}
+
+    // A row of cells.
+    TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
+
+    // A single comment string.
+    TextTableRow(std::string&& s) : mLine(std::move(s)) {}
+    TextTableRow(const std::string& s) : mLine(s) {}
+
+    // Whether this row is an actual row of cells.
+    bool isRow() const { return !fields().empty(); }
+
+    // Get all cells.
+    const std::vector<std::string>& fields() const { return mFields; }
+
+    // Get the single comment string.
+    const std::string& line() const { return mLine; }
+
+private:
+    std::vector<std::string> mFields;
+    std::string mLine;
+};
+
+// A TextTable is a 2D array of strings.
+class TextTable {
+public:
+
+    // Add a TextTableRow.
+    void add() { mTable.emplace_back(); }
+    void add(std::vector<std::string>&& v) {
+        computeWidth(v);
+        mTable.emplace_back(std::move(v));
+    }
+    void add(const std::string& s) { mTable.emplace_back(s); }
+    void add(std::string&& s) { mTable.emplace_back(std::move(s)); }
+
+    void addAll(TextTable&& other);
+
+    // Prints the table to out, with column widths adjusted appropriately according
+    // to the content.
+    void dump(std::ostream& out) const;
+
+private:
+    void computeWidth(const std::vector<std::string>& v);
+    std::vector<size_t> mWidths;
+    std::vector<TextTableRow> mTable;
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TEXT_TABLE_H_
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
new file mode 100644
index 0000000..9592111
--- /dev/null
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+cc_library_static {
+    name: "libprocpartition",
+    shared_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "procpartition.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
new file mode 100644
index 0000000..7e86432
--- /dev/null
+++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
@@ -0,0 +1,48 @@
+/*
+ * 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 FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+
+#include <sys/types.h>
+
+#include <string>
+#include <iostream>
+
+namespace android {
+namespace procpartition {
+
+enum class Partition {
+    UNKNOWN = 0,
+    SYSTEM,
+    VENDOR,
+    ODM
+};
+
+std::ostream& operator<<(std::ostream& os, Partition p);
+Partition parsePartition(const std::string& s);
+
+// Return the path that /proc/<pid>/exe points to.
+std::string getExe(pid_t pid);
+// Return the content of /proc/<pid>/cmdline.
+std::string getCmdline(pid_t pid);
+// Infer the partition of a process from /proc/<pid>/exe and /proc/<pid>/cmdline.
+Partition getPartition(pid_t pid);
+
+}  // namespace procpartition
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
diff --git a/cmds/lshal/libprocpartition/procpartition.cpp b/cmds/lshal/libprocpartition/procpartition.cpp
new file mode 100644
index 0000000..8ca458a
--- /dev/null
+++ b/cmds/lshal/libprocpartition/procpartition.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <procpartition/procpartition.h>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace procpartition {
+
+std::ostream& operator<<(std::ostream& os, Partition p) {
+    switch (p) {
+        case Partition::SYSTEM: return os << "system";
+        case Partition::VENDOR: return os << "vendor";
+        case Partition::ODM: return os << "odm";
+        case Partition::UNKNOWN: // fallthrough
+        default:
+            return os << "(unknown)";
+    }
+}
+
+std::string getExe(pid_t pid) {
+    std::string exe;
+    std::string real;
+    if (!android::base::Readlink("/proc/" + std::to_string(pid) + "/exe", &exe)) {
+        return "";
+    }
+    if (!android::base::Realpath(exe, &real)) {
+        return "";
+    }
+    return real;
+}
+
+std::string getCmdline(pid_t pid) {
+    std::string content;
+    if (!android::base::ReadFileToString("/proc/" + std::to_string(pid) + "/cmdline", &content,
+                                         false /* follow symlinks */)) {
+        return "";
+    }
+    return content;
+}
+
+Partition parsePartition(const std::string& s) {
+    if (s == "system") {
+        return Partition::SYSTEM;
+    }
+    if (s == "vendor") {
+        return Partition::VENDOR;
+    }
+    if (s == "odm") {
+        return Partition::ODM;
+    }
+    return Partition::UNKNOWN;
+}
+
+Partition getPartitionFromRealpath(const std::string& path) {
+    if (path == "/system/bin/app_process64" ||
+        path == "/system/bin/app_process32") {
+
+        return Partition::UNKNOWN; // cannot determine
+    }
+    size_t backslash = path.find_first_of('/', 1);
+    std::string partition = (backslash != std::string::npos) ? path.substr(1, backslash - 1) : path;
+
+    return parsePartition(partition);
+}
+
+Partition getPartitionFromCmdline(pid_t pid) {
+    const auto& cmdline = getCmdline(pid);
+    if (cmdline == "system_server") {
+        return Partition::SYSTEM;
+    }
+    if (cmdline.empty() || cmdline.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(cmdline);
+}
+
+Partition getPartitionFromExe(pid_t pid) {
+    const auto& real = getExe(pid);
+    if (real.empty() || real.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(real);
+}
+
+
+Partition getPartition(pid_t pid) {
+    Partition partition = getPartitionFromExe(pid);
+    if (partition == Partition::UNKNOWN) {
+        partition = getPartitionFromCmdline(pid);
+    }
+    return partition;
+}
+
+}  // namespace procpartition
+}  // namespace android
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 972d508..4fa941e 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -26,21 +26,29 @@
 #include <gmock/gmock.h>
 #include <android/hardware/tests/baz/1.0/IQuux.h>
 #include <hidl/HidlTransportSupport.h>
+#include <vintf/parse_xml.h>
 
+#include "ListCommand.h"
 #include "Lshal.h"
 
 #define NELEMS(array)   static_cast<int>(sizeof(array) / sizeof(array[0]))
 
 using namespace testing;
 
+using ::android::hidl::base::V1_0::DebugInfo;
 using ::android::hidl::base::V1_0::IBase;
 using ::android::hidl::manager::V1_0::IServiceManager;
 using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_death_recipient;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 
+using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+
+using hidl_hash = hidl_array<uint8_t, 32>;
+
 namespace android {
 namespace hardware {
 namespace tests {
@@ -76,7 +84,6 @@
 
 namespace lshal {
 
-
 class MockServiceManager : public IServiceManager {
 public:
     template<typename T>
@@ -107,7 +114,7 @@
 
 };
 
-class LshalTest : public ::testing::Test {
+class DebugTest : public ::testing::Test {
 public:
     void SetUp() override {
         using ::android::hardware::tests::baz::V1_0::IQuux;
@@ -122,43 +129,534 @@
                     return new Quux();
                 return nullptr;
             }));
+
+        lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
     }
     void TearDown() override {}
 
     std::stringstream err;
     std::stringstream out;
     sp<MockServiceManager> serviceManager;
+
+    std::unique_ptr<Lshal> lshal;
 };
 
-TEST_F(LshalTest, Debug) {
-    const char *args[] = {
+static Arg createArg(const std::vector<const char*>& args) {
+    return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
+}
+
+template<typename T>
+static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
+    return lshal->main(createArg(args));
+}
+
+TEST_F(DebugTest, Debug) {
+    EXPECT_EQ(0u, callMain(lshal, {
         "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
-    };
-    EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
-            .main({NELEMS(args), const_cast<char **>(args)}));
+    }));
     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
     EXPECT_THAT(err.str(), IsEmpty());
 }
 
-TEST_F(LshalTest, Debug2) {
-    const char *args[] = {
+TEST_F(DebugTest, Debug2) {
+    EXPECT_EQ(0u, callMain(lshal, {
         "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
-    };
-    EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
-            .main({NELEMS(args), const_cast<char **>(args)}));
+    }));
     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
     EXPECT_THAT(err.str(), IsEmpty());
 }
 
-TEST_F(LshalTest, Debug3) {
-    const char *args[] = {
+TEST_F(DebugTest, Debug3) {
+    EXPECT_NE(0u, callMain(lshal, {
         "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
-    };
-    EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
-            .main({NELEMS(args), const_cast<char **>(args)}));
+    }));
     EXPECT_THAT(err.str(), HasSubstr("does not exist"));
 }
 
+class MockLshal : public Lshal {
+public:
+    MockLshal() {}
+    ~MockLshal() = default;
+    MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
+    MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
+};
+
+// expose protected fields and methods for ListCommand
+class MockListCommand : public ListCommand {
+public:
+    MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
+
+    Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
+    Status main(const Arg& arg) { return ListCommand::main(arg); }
+    void forEachTable(const std::function<void(Table &)> &f) {
+        return ListCommand::forEachTable(f);
+    }
+    void forEachTable(const std::function<void(const Table &)> &f) const {
+        return ListCommand::forEachTable(f);
+    }
+    Status fetch() { return ListCommand::fetch(); }
+    void dumpVintf(const NullableOStream<std::ostream>& out) {
+        return ListCommand::dumpVintf(out);
+    }
+    void internalPostprocess() { ListCommand::postprocess(); }
+    const PidInfo* getPidInfoCached(pid_t serverPid) {
+        return ListCommand::getPidInfoCached(serverPid);
+    }
+
+    MOCK_METHOD0(postprocess, void());
+    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
+    MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
+    MOCK_METHOD1(getPartition, Partition(pid_t));
+};
+
+class ListParseArgsTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        mockLshal = std::make_unique<NiceMock<MockLshal>>();
+        mockList = std::make_unique<MockListCommand>(mockLshal.get());
+        // ListCommand::parseArgs should parse arguments from the second element
+        optind = 1;
+    }
+    std::unique_ptr<MockLshal> mockLshal;
+    std::unique_ptr<MockListCommand> mockList;
+    std::stringstream output;
+};
+
+TEST_F(ListParseArgsTest, Args) {
+    EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
+    mockList->forEachTable([](const Table& table) {
+        EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
+                                   TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
+                  table.getSelectedColumns());
+    });
+}
+
+TEST_F(ListParseArgsTest, Cmds) {
+    EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
+    mockList->forEachTable([](const Table& table) {
+        EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
+                << "should not print server PID with -m";
+        EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
+                << "should not print client PIDs with -m";
+        EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
+                << "should print server cmd with -m";
+        EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
+                << "should print client cmds with -m";
+    });
+}
+
+TEST_F(ListParseArgsTest, DebugAndNeat) {
+    ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
+    EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
+    EXPECT_THAT(output.str(), StrNe(""));
+}
+
+/// Fetch Test
+
+// A set of deterministic functions to generate fake debug infos.
+static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
+static std::vector<pid_t> getClients(pid_t serverId) {
+    return {serverId + 1, serverId + 3};
+}
+static PidInfo getPidInfoFromId(pid_t serverId) {
+    PidInfo info;
+    info.refPids[getPtr(serverId)] = getClients(serverId);
+    info.threadUsage = 10 + serverId;
+    info.threadCount = 20 + serverId;
+    return info;
+}
+static std::string getInterfaceName(pid_t serverId) {
+    return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
+}
+static std::string getInstanceName(pid_t serverId) {
+    return std::to_string(serverId);
+}
+static pid_t getIdFromInstanceName(const hidl_string& instance) {
+    return atoi(instance.c_str());
+}
+static std::string getFqInstanceName(pid_t serverId) {
+    return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
+}
+static std::string getCmdlineFromId(pid_t serverId) {
+    if (serverId == NO_PID) return "";
+    return "command_line_" + std::to_string(serverId);
+}
+static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
+static hidl_hash getHashFromId(pid_t serverId) {
+    hidl_hash hash;
+    bool isReleased = getIsReleasedFromId(serverId);
+    for (size_t i = 0; i < hash.size(); ++i) {
+        hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
+    }
+    return hash;
+}
+
+// Fake service returned by mocked IServiceManager::get.
+class TestService : public IBase {
+public:
+    TestService(pid_t id) : mId(id) {}
+    hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
+        cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
+        return hardware::Void();
+    }
+    hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+        cb({getInterfaceName(mId), IBase::descriptor});
+        return hardware::Void();
+    }
+    hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+        cb({getHashFromId(mId), getHashFromId(0xff)});
+        return hardware::Void();
+    }
+private:
+    pid_t mId;
+};
+
+class ListTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        initMockServiceManager();
+        lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
+        initMockList();
+    }
+
+    void initMockList() {
+        mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
+        ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
+            [](pid_t serverPid, PidInfo* info) {
+                *info = getPidInfoFromId(serverPid);
+                return true;
+            }));
+        ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
+        ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
+            mockList->internalPostprocess();
+            size_t i = 0;
+            mockList->forEachTable([&](Table& table) {
+                table.setDescription("[fake description " + std::to_string(i++) + "]");
+            });
+        }));
+        ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
+    }
+
+    void initMockServiceManager() {
+        serviceManager = new testing::NiceMock<MockServiceManager>();
+        passthruManager = new testing::NiceMock<MockServiceManager>();
+        using A = DebugInfo::Architecture;
+        ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
+            [] (IServiceManager::list_cb cb) {
+                cb({ getFqInstanceName(1), getFqInstanceName(2) });
+                return hardware::Void();
+            }));
+
+        ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+            [&](const hidl_string&, const hidl_string& instance) {
+                int id = getIdFromInstanceName(instance);
+                return sp<IBase>(new TestService(id));
+            }));
+
+        ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
+            [] (IServiceManager::debugDump_cb cb) {
+                cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
+                                      getClients(3), A::IS_32BIT},
+                    InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
+                                      getClients(4), A::IS_32BIT}});
+                return hardware::Void();
+            }));
+
+        ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
+            [] (IServiceManager::debugDump_cb cb) {
+                cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
+                                      getClients(5), A::IS_32BIT},
+                    InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
+                                      getClients(6), A::IS_32BIT}});
+                return hardware::Void();
+            }));
+    }
+
+    std::stringstream err;
+    std::stringstream out;
+    std::unique_ptr<Lshal> lshal;
+    std::unique_ptr<MockListCommand> mockList;
+    sp<MockServiceManager> serviceManager;
+    sp<MockServiceManager> passthruManager;
+};
+
+TEST_F(ListTest, GetPidInfoCached) {
+    EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
+
+    EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+    EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+}
+
+TEST_F(ListTest, Fetch) {
+    EXPECT_EQ(0u, mockList->fetch());
+    std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
+                                          "passthrough", "passthrough", "passthrough"}};
+    std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
+    int id = 1;
+    mockList->forEachTable([&](const Table& table) {
+        ASSERT_EQ(2u, table.size());
+        for (const auto& entry : table) {
+            const auto& transport = transports[id - 1];
+            TableEntry expected{
+                .interfaceName = getFqInstanceName(id),
+                .transport = transport,
+                .serverPid = transport == "hwbinder" ? id : NO_PID,
+                .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
+                .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
+                .serverCmdline = {},
+                .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
+                .clientPids = getClients(id),
+                .clientCmdlines = {},
+                .arch = archs[id - 1],
+            };
+            EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
+
+            ++id;
+        }
+    });
+
+}
+
+TEST_F(ListTest, DumpVintf) {
+    const std::string expected =
+        "<!-- \n"
+        "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
+        "-->\n"
+        "<manifest version=\"1.0\" type=\"device\">\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo1</name>\n"
+        "        <transport>hwbinder</transport>\n"
+        "        <version>1.0</version>\n"
+        "        <interface>\n"
+        "            <name>IFoo</name>\n"
+        "            <instance>1</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo2</name>\n"
+        "        <transport>hwbinder</transport>\n"
+        "        <version>2.0</version>\n"
+        "        <interface>\n"
+        "            <name>IFoo</name>\n"
+        "            <instance>2</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo3</name>\n"
+        "        <transport arch=\"32\">passthrough</transport>\n"
+        "        <version>3.0</version>\n"
+        "        <interface>\n"
+        "            <name>IFoo</name>\n"
+        "            <instance>3</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo4</name>\n"
+        "        <transport arch=\"32\">passthrough</transport>\n"
+        "        <version>4.0</version>\n"
+        "        <interface>\n"
+        "            <name>IFoo</name>\n"
+        "            <instance>4</instance>\n"
+        "        </interface>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo5</name>\n"
+        "        <transport arch=\"32\">passthrough</transport>\n"
+        "        <version>5.0</version>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>a.h.foo6</name>\n"
+        "        <transport arch=\"32\">passthrough</transport>\n"
+        "        <version>6.0</version>\n"
+        "    </hal>\n"
+        "</manifest>\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+
+    vintf::HalManifest m;
+    EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
+        << "--init-vintf does not emit valid HAL manifest: "
+        << vintf::gHalManifestConverter.lastError();
+}
+
+// test default columns
+TEST_F(ListTest, DumpDefault) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "R Interface            Thread Use Server Clients\n"
+        "  a.h.foo1@1.0::IFoo/1 11/21      1      2 4\n"
+        "Y a.h.foo2@2.0::IFoo/2 12/22      2      3 5\n"
+        "\n"
+        "[fake description 1]\n"
+        "R Interface            Thread Use Server Clients\n"
+        "  a.h.foo3@3.0::IFoo/3 N/A        N/A    4 6\n"
+        "  a.h.foo4@4.0::IFoo/4 N/A        N/A    5 7\n"
+        "\n"
+        "[fake description 2]\n"
+        "R Interface            Thread Use Server Clients\n"
+        "  a.h.foo5@5.0::IFoo/5 N/A        N/A    6 8\n"
+        "  a.h.foo6@6.0::IFoo/6 N/A        N/A    7 9\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpHash) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            R Hash\n"
+        "a.h.foo1@1.0::IFoo/1   0000000000000000000000000000000000000000000000000000000000000000\n"
+        "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            R Hash\n"
+        "a.h.foo3@3.0::IFoo/3   \n"
+        "a.h.foo4@4.0::IFoo/4   \n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            R Hash\n"
+        "a.h.foo5@5.0::IFoo/5   \n"
+        "a.h.foo6@6.0::IFoo/6   \n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, Dump) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport Arch Thread Use Server PTR              Clients\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpCmdline) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport Arch Thread Use Server CMD     PTR              Clients CMD\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      command_line_1 0000000000002711 command_line_2;command_line_4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      command_line_2 0000000000002712 command_line_3;command_line_5\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A                   N/A command_line_4;command_line_6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A                   N/A command_line_5;command_line_7\n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A                   N/A command_line_6;command_line_8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A                   N/A command_line_7;command_line_9\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpNeat) {
+    const std::string expected =
+        "a.h.foo1@1.0::IFoo/1 11/21 1   2 4\n"
+        "a.h.foo2@2.0::IFoo/2 12/22 2   3 5\n"
+        "a.h.foo3@3.0::IFoo/3 N/A   N/A 4 6\n"
+        "a.h.foo4@4.0::IFoo/4 N/A   N/A 5 7\n"
+        "a.h.foo5@5.0::IFoo/5 N/A   N/A 6 8\n"
+        "a.h.foo6@6.0::IFoo/6 N/A   N/A 7 9\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+class HelpTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
+                                        new MockServiceManager() /* passthruManager */);
+    }
+
+    std::stringstream err;
+    std::stringstream out;
+    std::unique_ptr<Lshal> lshal;
+};
+
+TEST_F(HelpTest, GlobalUsage) {
+    (void)callMain(lshal, {"lshal", "--help"}); // ignore return
+    std::string errStr = err.str();
+    EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
+        << "`lshal --help` does not contain global usage";
+    EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
+        << "`lshal --help` does not contain usage for 'list' command";
+    EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
+        << "`lshal --help` does not contain usage for 'debug' command";
+    EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
+        << "`lshal --help` does not contain usage for 'help' command";
+
+    err.str("");
+    (void)callMain(lshal, {"lshal", "help"}); // ignore return
+    EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
+
+    err.str("");
+    EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
+    EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
+    EXPECT_THAT(err.str(), EndsWith(errStr))
+            << "`lshal --unknown-option` should have the same output as `lshal --help`";
+    EXPECT_EQ("", out.str());
+}
+
+TEST_F(HelpTest, UnknownOptionList1) {
+    (void)callMain(lshal, {"lshal", "help", "list"});
+    EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
+        << "`lshal help list` does not contain usage for 'list' command";
+}
+
+TEST_F(HelpTest, UnknownOptionList2) {
+    EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
+    EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
+    EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
+        << "`lshal list --unknown-option` does not contain usage for 'list' command";
+    EXPECT_EQ("", out.str());
+}
+
+TEST_F(HelpTest, UnknownOptionHelp1) {
+    (void)callMain(lshal, {"lshal", "help", "help"});
+    EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
+        << "`lshal help help` does not contain usage for 'help' command";
+}
+
+TEST_F(HelpTest, UnknownOptionHelp2) {
+    (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
+    EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
+        << "`lshal help --unknown-option` does not contain usage for 'help' command";
+    EXPECT_EQ("", out.str());
+}
+
 } // namespace lshal
 } // namespace android
 
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index 45b922c..c09e8b1 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -29,15 +29,23 @@
 
 enum : unsigned int {
     OK                                      = 0,
+    // Return to Lshal::main to print help info.
     USAGE                                   = 1 << 0,
+    // no service managers
     NO_BINDERIZED_MANAGER                   = 1 << 1,
     NO_PASSTHROUGH_MANAGER                  = 1 << 2,
+    // general error in getting information from the three sources
     DUMP_BINDERIZED_ERROR                   = 1 << 3,
     DUMP_PASSTHROUGH_ERROR                  = 1 << 4,
     DUMP_ALL_LIBS_ERROR                     = 1 << 5,
+    // I/O error in reading files
     IO_ERROR                                = 1 << 6,
+    // Interface does not exist (IServiceManager::get fails)
     NO_INTERFACE                            = 1 << 7,
+    // Transaction error from hwbinder transactions
     TRANSACTION_ERROR                       = 1 << 8,
+    // No transaction error, but return value is unexpected.
+    BAD_IMPL                                = 1 << 9,
 };
 using Status = unsigned int;
 
diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk
index b580390..9322151 100644
--- a/cmds/rawbu/Android.mk
+++ b/cmds/rawbu/Android.mk
@@ -5,6 +5,8 @@
 
 LOCAL_SRC_FILES:= backup.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := libcutils libc
 
 LOCAL_MODULE:= rawbu
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index ff6719f..0072281 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -129,7 +129,6 @@
         }
 
         if(S_ISDIR(statBuffer.st_mode)) {
-            int i;
             char *newpath;
 
             newpath = strdup(nameBuffer);
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index b703ed4..9513ec1 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -8,7 +8,11 @@
         "libbinder",
     ],
 
-    cflags: ["-DXP_UNIX"],
+    cflags: [
+        "-DXP_UNIX",
+        "-Wall",
+        "-Werror",
+    ],
 }
 
 cc_binary {
@@ -22,5 +26,10 @@
         "libbinder",
     ],
 
-    cflags: ["-DXP_UNIX", "-DVENDORSERVICES"],
+    cflags: [
+        "-DXP_UNIX",
+        "-DVENDORSERVICES",
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index d3d396f..428561b 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -46,6 +46,6 @@
     cflags: [
         "-DVENDORSERVICEMANAGER=1",
     ],
-    shared_libs: ["libcutils", "libselinux_vendor"],
+    shared_libs: ["libcutils", "libselinux"],
     init_rc: ["vndservicemanager.rc"],
 }
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 93a18fc..fade8cf 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -514,7 +514,7 @@
         return;
 
     obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
-    obj->type = BINDER_TYPE_BINDER;
+    obj->hdr.type = BINDER_TYPE_BINDER;
     obj->binder = (uintptr_t)ptr;
     obj->cookie = 0;
 }
@@ -532,7 +532,7 @@
         return;
 
     obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
-    obj->type = BINDER_TYPE_HANDLE;
+    obj->hdr.type = BINDER_TYPE_HANDLE;
     obj->handle = handle;
     obj->cookie = 0;
 }
@@ -649,7 +649,7 @@
     if (!obj)
         return 0;
 
-    if (obj->type == BINDER_TYPE_HANDLE)
+    if (obj->hdr.type == BINDER_TYPE_HANDLE)
         return obj->handle;
 
     return 0;
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 31cd0cb..6b340a8 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -138,6 +138,7 @@
     uint32_t handle;
     struct binder_death death;
     int allow_isolated;
+    uint32_t dumpsys_priority;
     size_t len;
     uint16_t name[0];
 };
@@ -198,11 +199,8 @@
     return si->handle;
 }
 
-int do_add_service(struct binder_state *bs,
-                   const uint16_t *s, size_t len,
-                   uint32_t handle, uid_t uid, int allow_isolated,
-                   pid_t spid)
-{
+int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
+                   uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
     struct svcinfo *si;
 
     //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -239,6 +237,7 @@
         si->death.func = (void*) svcinfo_death;
         si->death.ptr = si;
         si->allow_isolated = allow_isolated;
+        si->dumpsys_priority = dumpsys_priority;
         si->next = svclist;
         svclist = si;
     }
@@ -259,6 +258,7 @@
     uint32_t handle;
     uint32_t strict_policy;
     int allow_isolated;
+    uint32_t dumpsys_priority;
 
     //ALOGI("target=%p code=%d pid=%d uid=%d\n",
     //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -317,13 +317,15 @@
         }
         handle = bio_get_ref(msg);
         allow_isolated = bio_get_uint32(msg) ? 1 : 0;
-        if (do_add_service(bs, s, len, handle, txn->sender_euid,
-            allow_isolated, txn->sender_pid))
+        dumpsys_priority = bio_get_uint32(msg);
+        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
+                           txn->sender_pid))
             return -1;
         break;
 
     case SVC_MGR_LIST_SERVICES: {
         uint32_t n = bio_get_uint32(msg);
+        uint32_t req_dumpsys_priority = bio_get_uint32(msg);
 
         if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
             ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
@@ -331,8 +333,15 @@
             return -1;
         }
         si = svclist;
-        while ((n-- > 0) && si)
+        // walk through the list of services n times skipping services that
+        // do not support the requested priority
+        while (si) {
+            if (si->dumpsys_priority & req_dumpsys_priority) {
+                if (n == 0) break;
+                n--;
+            }
             si = si->next;
+        }
         if (si) {
             bio_put_string16(reply, si->name);
             return 0;
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index d336a43..4d93cb4 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -11,5 +11,7 @@
     onrestart restart inputflinger
     onrestart restart drm
     onrestart restart cameraserver
+    onrestart restart keystore
+    onrestart restart gatekeeperd
     writepid /dev/cpuset/system-background/tasks
     shutdown critical
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index dda80bb..71a5e23 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -3,6 +3,10 @@
     srcs: [
         "src/trace.proto",
     ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     proto: {
         type: "lite",
         export_proto_headers: true,
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 35b63ec..4140f40 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -24,9 +24,9 @@
 
 #include <gui/BufferQueue.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 #include <ui/DisplayInfo.h>
 #include <utils/Log.h>
@@ -338,27 +338,29 @@
 status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) {
     ALOGV("Started Transaction");
 
-    SurfaceComposerClient::openGlobalTransaction();
+    SurfaceComposerClient::Transaction liveTransaction;
 
     status_t status = NO_ERROR;
 
-    status = doSurfaceTransaction(t.surface_change());
-    doDisplayTransaction(t.display_change());
+    status = doSurfaceTransaction(liveTransaction, t.surface_change());
+    doDisplayTransaction(liveTransaction, t.display_change());
 
     if (t.animation()) {
-        SurfaceComposerClient::setAnimationTransaction();
+        liveTransaction.setAnimationTransaction();
     }
 
     event->readyToExecute();
 
-    SurfaceComposerClient::closeGlobalTransaction(t.synchronous());
+    liveTransaction.apply(t.synchronous());
 
     ALOGV("Ended Transaction");
 
     return status;
 }
 
-status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) {
+status_t Replayer::doSurfaceTransaction(
+        SurfaceComposerClient::Transaction& transaction,
+        const SurfaceChanges& surfaceChanges) {
     status_t status = NO_ERROR;
 
     for (const SurfaceChange& change : surfaceChanges) {
@@ -369,62 +371,66 @@
 
         switch (change.SurfaceChange_case()) {
             case SurfaceChange::SurfaceChangeCase::kPosition:
-                status = setPosition(change.id(), change.position());
+                setPosition(transaction, change.id(), change.position());
                 break;
             case SurfaceChange::SurfaceChangeCase::kSize:
-                status = setSize(change.id(), change.size());
+                setSize(transaction, change.id(), change.size());
                 break;
             case SurfaceChange::SurfaceChangeCase::kAlpha:
-                status = setAlpha(change.id(), change.alpha());
+                setAlpha(transaction, change.id(), change.alpha());
                 break;
             case SurfaceChange::SurfaceChangeCase::kLayer:
-                status = setLayer(change.id(), change.layer());
+                setLayer(transaction, change.id(), change.layer());
                 break;
             case SurfaceChange::SurfaceChangeCase::kCrop:
-                status = setCrop(change.id(), change.crop());
+                setCrop(transaction, change.id(), change.crop());
                 break;
             case SurfaceChange::SurfaceChangeCase::kMatrix:
-                status = setMatrix(change.id(), change.matrix());
+                setMatrix(transaction, change.id(), change.matrix());
                 break;
             case SurfaceChange::SurfaceChangeCase::kFinalCrop:
-                status = setFinalCrop(change.id(), change.final_crop());
+                setFinalCrop(transaction, change.id(), change.final_crop());
                 break;
             case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
-                status = setOverrideScalingMode(change.id(), change.override_scaling_mode());
+                setOverrideScalingMode(transaction, change.id(),
+                        change.override_scaling_mode());
                 break;
             case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
-                status = setTransparentRegionHint(change.id(), change.transparent_region_hint());
+                setTransparentRegionHint(transaction, change.id(),
+                        change.transparent_region_hint());
                 break;
             case SurfaceChange::SurfaceChangeCase::kLayerStack:
-                status = setLayerStack(change.id(), change.layer_stack());
+                setLayerStack(transaction, change.id(), change.layer_stack());
                 break;
             case SurfaceChange::SurfaceChangeCase::kHiddenFlag:
-                status = setHiddenFlag(change.id(), change.hidden_flag());
+                setHiddenFlag(transaction, change.id(), change.hidden_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kOpaqueFlag:
-                status = setOpaqueFlag(change.id(), change.opaque_flag());
+                setOpaqueFlag(transaction, change.id(), change.opaque_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kSecureFlag:
-                status = setSecureFlag(change.id(), change.secure_flag());
+                setSecureFlag(transaction, change.id(), change.secure_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
                 waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
-                status = setDeferredTransaction(change.id(), change.deferred_transaction());
+                setDeferredTransaction(transaction, change.id(),
+                        change.deferred_transaction());
                 break;
             default:
-                status = NO_ERROR;
+                status = 1;
                 break;
         }
 
         if (status != NO_ERROR) {
-            ALOGE("SET TRANSACTION FAILED");
+            ALOGE("Unknown Transaction Code");
             return status;
         }
     }
     return status;
 }
 
-void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) {
+void Replayer::doDisplayTransaction(SurfaceComposerClient::Transaction& t,
+        const DisplayChanges& displayChanges) {
     for (const DisplayChange& change : displayChanges) {
         ALOGV("Doing display transaction");
         std::unique_lock<std::mutex> lock(mDisplayLock);
@@ -434,16 +440,16 @@
 
         switch (change.DisplayChange_case()) {
             case DisplayChange::DisplayChangeCase::kSurface:
-                setDisplaySurface(change.id(), change.surface());
+                setDisplaySurface(t, change.id(), change.surface());
                 break;
             case DisplayChange::DisplayChangeCase::kLayerStack:
-                setDisplayLayerStack(change.id(), change.layer_stack());
+                setDisplayLayerStack(t, change.id(), change.layer_stack());
                 break;
             case DisplayChange::DisplayChangeCase::kSize:
-                setDisplaySize(change.id(), change.size());
+                setDisplaySize(t, change.id(), change.size());
                 break;
             case DisplayChange::DisplayChangeCase::kProjection:
-                setDisplayProjection(change.id(), change.projection());
+                setDisplayProjection(t, change.id(), change.projection());
                 break;
             default:
                 break;
@@ -451,130 +457,148 @@
     }
 }
 
-status_t Replayer::setPosition(layer_id id, const PositionChange& pc) {
+void Replayer::setPosition(SurfaceComposerClient::Transaction& t,
+        layer_id id, const PositionChange& pc) {
     ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y());
-    return mLayers[id]->setPosition(pc.x(), pc.y());
+    t.setPosition(mLayers[id], pc.x(), pc.y());
 }
 
-status_t Replayer::setSize(layer_id id, const SizeChange& sc) {
+void Replayer::setSize(SurfaceComposerClient::Transaction& t,
+        layer_id id, const SizeChange& sc) {
     ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h());
-    return mLayers[id]->setSize(sc.w(), sc.h());
+    t.setSize(mLayers[id], sc.w(), sc.h());
 }
 
-status_t Replayer::setLayer(layer_id id, const LayerChange& lc) {
+void Replayer::setLayer(SurfaceComposerClient::Transaction& t,
+        layer_id id, const LayerChange& lc) {
     ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer());
-    return mLayers[id]->setLayer(lc.layer());
+    t.setLayer(mLayers[id], lc.layer());
 }
 
-status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) {
+void Replayer::setAlpha(SurfaceComposerClient::Transaction& t,
+        layer_id id, const AlphaChange& ac) {
     ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha());
-    return mLayers[id]->setAlpha(ac.alpha());
+    t.setAlpha(mLayers[id], ac.alpha());
 }
 
-status_t Replayer::setCrop(layer_id id, const CropChange& cc) {
+void Replayer::setCrop(SurfaceComposerClient::Transaction& t,
+        layer_id id, const CropChange& cc) {
     ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
             cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
 
     Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
-    return mLayers[id]->setCrop(r);
+    t.setCrop(mLayers[id], r);
 }
 
-status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) {
+void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
+        layer_id id, const FinalCropChange& fcc) {
     ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
             fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
             fcc.rectangle().bottom());
     Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
             fcc.rectangle().bottom());
-    return mLayers[id]->setFinalCrop(r);
+    t.setFinalCrop(mLayers[id], r);
 }
 
-status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) {
+void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
+        layer_id id, const MatrixChange& mc) {
     ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
             mc.dtdx(), mc.dsdy(), mc.dtdy());
-    return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
+    t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
 }
 
-status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) {
+void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+        layer_id id, const OverrideScalingModeChange& osmc) {
     ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
-    return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode());
+    t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode());
 }
 
-status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) {
+void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+        layer_id id, const TransparentRegionHintChange& trhc) {
     ALOGV("Setting Transparent Region Hint");
     Region re = Region();
 
-    for (auto r : trhc.region()) {
+    for (const auto& r : trhc.region()) {
         Rect rect = Rect(r.left(), r.top(), r.right(), r.bottom());
         re.merge(rect);
     }
 
-    return mLayers[id]->setTransparentRegionHint(re);
+    t.setTransparentRegionHint(mLayers[id], re);
 }
 
-status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) {
+void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t,
+        layer_id id, const LayerStackChange& lsc) {
     ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
-    return mLayers[id]->setLayerStack(lsc.layer_stack());
+    t.setLayerStack(mLayers[id], lsc.layer_stack());
 }
 
-status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) {
+void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const HiddenFlagChange& hfc) {
     ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag());
     layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerHidden);
 }
 
-status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) {
+void Replayer::setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const OpaqueFlagChange& ofc) {
     ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag());
     layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerOpaque);
 }
 
-status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) {
+void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const SecureFlagChange& sfc) {
     ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag());
     layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure);
 }
 
-status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) {
+void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+        layer_id id, const DeferredTransactionChange& dtc) {
     ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
           "frame_number=%llu",
             id, dtc.layer_id(), dtc.frame_number());
     if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
         ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
-        return BAD_VALUE;
+        return;
     }
 
     auto handle = mLayers[dtc.layer_id()]->getHandle();
 
-    return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number());
+    t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
 }
 
-void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) {
+void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
+        display_id id, const DispSurfaceChange& /*dsc*/) {
     sp<IGraphicBufferProducer> outProducer;
     sp<IGraphicBufferConsumer> outConsumer;
     BufferQueue::createBufferQueue(&outProducer, &outConsumer);
 
-    SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer);
+    t.setDisplaySurface(mDisplays[id], outProducer);
 }
 
-void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) {
-    SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+        display_id id, const LayerStackChange& lsc) {
+    t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
 }
 
-void Replayer::setDisplaySize(display_id id, const SizeChange& sc) {
-    SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h());
+void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t,
+        display_id id, const SizeChange& sc) {
+    t.setDisplaySize(mDisplays[id], sc.w(), sc.h());
 }
 
-void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) {
+void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t,
+        display_id id, const ProjectionChange& pc) {
     Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(),
             pc.viewport().bottom());
     Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
 
-    SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+    t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
 }
 
 status_t Replayer::createSurfaceControl(
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index f36c9fd..295403e 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -77,28 +77,48 @@
     void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
     void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event);
 
-    status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange);
-    void doDisplayTransaction(const DisplayChanges& displayChange);
+    status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction,
+            const SurfaceChanges& surfaceChange);
+    void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction,
+            const DisplayChanges& displayChange);
 
-    status_t setPosition(layer_id id, const PositionChange& pc);
-    status_t setSize(layer_id id, const SizeChange& sc);
-    status_t setAlpha(layer_id id, const AlphaChange& ac);
-    status_t setLayer(layer_id id, const LayerChange& lc);
-    status_t setCrop(layer_id id, const CropChange& cc);
-    status_t setFinalCrop(layer_id id, const FinalCropChange& fcc);
-    status_t setMatrix(layer_id id, const MatrixChange& mc);
-    status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc);
-    status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc);
-    status_t setLayerStack(layer_id id, const LayerStackChange& lsc);
-    status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc);
-    status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc);
-    status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc);
-    status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc);
+    void setPosition(SurfaceComposerClient::Transaction& t,
+            layer_id id, const PositionChange& pc);
+    void setSize(SurfaceComposerClient::Transaction& t,
+            layer_id id, const SizeChange& sc);
+    void setAlpha(SurfaceComposerClient::Transaction& t,
+            layer_id id, const AlphaChange& ac);
+    void setLayer(SurfaceComposerClient::Transaction& t,
+            layer_id id, const LayerChange& lc);
+    void setCrop(SurfaceComposerClient::Transaction& t,
+            layer_id id, const CropChange& cc);
+    void setFinalCrop(SurfaceComposerClient::Transaction& t,
+            layer_id id, const FinalCropChange& fcc);
+    void setMatrix(SurfaceComposerClient::Transaction& t,
+            layer_id id, const MatrixChange& mc);
+    void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+            layer_id id, const OverrideScalingModeChange& osmc);
+    void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+            layer_id id, const TransparentRegionHintChange& trgc);
+    void setLayerStack(SurfaceComposerClient::Transaction& t,
+            layer_id id, const LayerStackChange& lsc);
+    void setHiddenFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const HiddenFlagChange& hfc);
+    void setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const OpaqueFlagChange& ofc);
+    void setSecureFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const SecureFlagChange& sfc);
+    void setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+            layer_id id, const DeferredTransactionChange& dtc);
 
-    void setDisplaySurface(display_id id, const DispSurfaceChange& dsc);
-    void setDisplayLayerStack(display_id id, const LayerStackChange& lsc);
-    void setDisplaySize(display_id id, const SizeChange& sc);
-    void setDisplayProjection(display_id id, const ProjectionChange& pc);
+    void setDisplaySurface(SurfaceComposerClient::Transaction& t,
+            display_id id, const DispSurfaceChange& dsc);
+    void setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+            display_id id, const LayerStackChange& lsc);
+    void setDisplaySize(SurfaceComposerClient::Transaction& t,
+            display_id id, const SizeChange& sc);
+    void setDisplayProjection(SurfaceComposerClient::Transaction& t,
+            display_id id, const ProjectionChange& pc);
 
     void doDeleteSurfaceControls();
     void waitUntilTimestamp(int64_t timestamp);
diff --git a/data/etc/android.hardware.camera.ar.xml b/data/etc/android.hardware.camera.ar.xml
new file mode 100644
index 0000000..2fc3280
--- /dev/null
+++ b/data/etc/android.hardware.camera.ar.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the set of features required for a camera2 device that supports the motion tracking
+     feature -->
+<permissions>
+    <feature name="android.hardware.camera.any" />
+    <feature name="android.hardware.camera.ar" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.assist.xml b/data/etc/android.hardware.sensor.assist.xml
new file mode 100644
index 0000000..c7f9d56
--- /dev/null
+++ b/data/etc/android.hardware.sensor.assist.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices with an assist gesture sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.assist" />
+</permissions>
diff --git a/data/etc/android.hardware.strongbox_keystore.xml b/data/etc/android.hardware.strongbox_keystore.xml
new file mode 100644
index 0000000..2a0ec37
--- /dev/null
+++ b/data/etc/android.hardware.strongbox_keystore.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices with Keymaster in StrongBox. -->
+<permissions>
+    <feature name="android.hardware.strongbox_keystore" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.mbms.xml b/data/etc/android.hardware.telephony.mbms.xml
new file mode 100644
index 0000000..271ea58
--- /dev/null
+++ b/data/etc/android.hardware.telephony.mbms.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- Feature for devices that support MBMS. -->
+<permissions>
+    <feature name="android.hardware.telephony.mbms" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.version-1_1.xml b/data/etc/android.hardware.vulkan.version-1_1.xml
new file mode 100644
index 0000000..9704e0f
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.version-1_1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device has a Vulkan
+     driver that supports API version 1.1 (0x00401000) -->
+<permissions>
+    <feature name="android.hardware.vulkan.version" version="4198400" />
+</permissions>
diff --git a/data/etc/android.hardware.wifi.rtt.xml b/data/etc/android.hardware.wifi.rtt.xml
new file mode 100644
index 0000000..60529ea
--- /dev/null
+++ b/data/etc/android.hardware.wifi.rtt.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports WiFi RTT (IEEE 802.11mc). -->
+<permissions>
+    <feature name="android.hardware.wifi.rtt" />
+</permissions>
diff --git a/data/etc/android.software.device_id_attestation.xml b/data/etc/android.software.device_id_attestation.xml
new file mode 100644
index 0000000..4e637ca
--- /dev/null
+++ b/data/etc/android.software.device_id_attestation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices with Keymaster that support Device ID attestation. -->
+<permissions>
+    <feature name="android.software.device_id_attestation" />
+</permissions>
diff --git a/data/etc/aosp_excluded_hardware.xml b/data/etc/aosp_excluded_hardware.xml
new file mode 100644
index 0000000..c12f435
--- /dev/null
+++ b/data/etc/aosp_excluded_hardware.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <!-- This should be used to exclude this feature from aosp targets. As aosp configurations
+    may or may not have a valid location provider -->
+    <unavailable-feature name="android.hardware.location.network" />
+    <unavailable-feature name="android.software.device_id_attestation" />
+</permissions>
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
new file mode 100644
index 0000000..8b5a461
--- /dev/null
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- These are the hardware components that all Android Go handheld devices
+     must include. Devices with optional hardware must also include extra
+     hardware files, per the comments below.
+-->
+<permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
+    <feature name="android.hardware.audio.output" />
+    <feature name="android.hardware.camera" />
+    <feature name="android.hardware.location" />
+    <feature name="android.hardware.location.network" />
+    <feature name="android.hardware.sensor.compass" />
+    <feature name="android.hardware.sensor.accelerometer" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.touchscreen" />
+    <feature name="android.hardware.microphone" />
+    <feature name="android.hardware.screen.portrait" />
+    <feature name="android.hardware.screen.landscape" />
+
+    <!-- basic system services -->
+    <feature name="android.software.connectionservice" />
+    <feature name="android.software.backup" />
+    <feature name="android.software.home_screen" />
+    <feature name="android.software.input_methods" />
+    <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
+
+    <!-- Feature to specify if the device supports adding device admins. -->
+    <feature name="android.software.device_admin" />
+
+    <!-- Devices with all optimizations required to support VR Mode and
+         pass all CDD requirements for this feature may include
+         android.hardware.vr.high_performance -->
+    <!-- Devices that support VR headtracking features and pass all CDD
+         requirements may include
+         android.hardware.vr.headtracking -->
+
+    <!-- devices with GPS must include android.hardware.location.gps.xml -->
+    <!-- devices with an autofocus camera and/or flash must include either
+         android.hardware.camera.autofocus.xml or
+         android.hardware.camera.autofocus-flash.xml -->
+    <!-- devices with a front facing camera must include
+         android.hardware.camera.front.xml -->
+    <!-- devices with WiFi must also include android.hardware.wifi.xml -->
+    <!-- devices that support multitouch must include the most appropriate one
+         of these files:
+
+         If only partial (non-independent) pointers are supported:
+         android.hardware.touchscreen.multitouch.xml
+
+         If up to 4 independently tracked pointers are supported:
+         include android.hardware.touchscreen.multitouch.distinct.xml
+
+         If 5 or more independently tracked pointers are supported:
+         include android.hardware.touchscreen.multitouch.jazzhand.xml
+
+         ONLY ONE of the above should be included. -->
+    <!-- devices with an ambient light sensor must also include
+         android.hardware.sensor.light.xml -->
+    <!-- devices with a proximity sensor must also include
+         android.hardware.sensor.proximity.xml -->
+    <!-- GSM phones must also include android.hardware.telephony.gsm.xml -->
+    <!-- CDMA phones must also include android.hardware.telephony.cdma.xml -->
+    <!-- Devices that have low-latency audio stacks suitable for apps like
+         VoIP may include android.hardware.audio.low_latency.xml. ONLY apps
+         that meet the requirements specified in the CDD may include this. -->
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index ec7be53..060a334 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -14,9 +14,9 @@
      limitations under the License.
 -->
 
-<!-- These are the hardware components that all handheld devices
-     must include. Devices with optional hardware must also include extra
-     hardware files, per the comments below.
+<!-- These are the hardware components that all handheld devices except Android Go
+     must include, for Android Go devices include go_handheld_core_hardware.xml.
+     Devices with optional hardware must also include extra hardware files, per the comments below.
 
      Handheld devices include phones, mobile Internet devices (MIDs),
      Personal Media Players (PMPs), small tablets (7" or less), and similar
@@ -46,21 +46,20 @@
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" notLowRam="true" />
-    <feature name="android.software.activities_on_secondary_displays" />
+    <feature name="android.software.activities_on_secondary_displays" notLowRam="true" />
     <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
 
     <!-- Feature to specify if the device support managed users. -->
-    <feature name="android.software.managed_users" />
+    <feature name="android.software.managed_users" notLowRam="true"/>
 
-    <!-- Feature to specify if the device supports a VR mode.
-         feature name="android.software.vr.mode" -->
-    <!-- Devices with all optimizations required to be a "VR Ready" device that
-         pass all CTS tests for this feature must include feature
+    <!-- Devices with all optimizations required to support VR Mode and
+         pass all CDD requirements for this feature may include
          android.hardware.vr.high_performance -->
     <!-- Devices that support VR headtracking features and pass all CDD
          requirements may include
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 9b88648..6db2627 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -50,6 +50,7 @@
     <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index d7c3730..e2ab71a 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -36,9 +36,6 @@
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
 
-    <!-- device administration -->
-    <feature name="android.software.device_admin" />
-
     <!-- input management and third-party input method editors -->
     <feature name="android.software.input_methods" />
 
diff --git a/docs/Doxyfile b/docs/Doxyfile
index bb0ca32..efa639d 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -677,7 +677,7 @@
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = ../include/android ../../av/include/ndk ../../av/include/camera/ndk
+INPUT                  = ../include/android ../../av/media/ndk/include ../../av/camera/ndk/include
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -1580,20 +1580,20 @@
 # evaluate all C-preprocessor directives found in the sources and include
 # files.
 
-ENABLE_PREPROCESSING   = NO
+ENABLE_PREPROCESSING   = YES
 
 # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
 # names in the source code. If set to NO (the default) only conditional
 # compilation will be performed. Macro expansion can be done in a controlled
 # way by setting EXPAND_ONLY_PREDEF to YES.
 
-MACRO_EXPANSION        = NO
+MACRO_EXPANSION        = YES
 
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
 # then the macro expansion is limited to the macros specified with the
 # PREDEFINED and EXPAND_AS_DEFINED tags.
 
-EXPAND_ONLY_PREDEF     = NO
+EXPAND_ONLY_PREDEF     = YES
 
 # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
 # pointed to by INCLUDE_PATH will be searched when a #include is found.
@@ -1621,7 +1621,7 @@
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             =
+PREDEFINED             = __attribute__(x)=
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
index a02fd89..f739fa2 100644
--- a/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
index c309ac5..4b45e3a 100644
--- a/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
index 414fad4..748d1a2 100644
--- a/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
index c147a87..6e436ba 100644
--- a/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
index 4ce2125..9776874 100644
--- a/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
new file mode 100644
index 0000000..b32c92e
--- /dev/null
+++ b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 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 ANDROID_IARC_VIDEO_BRIDGE_H
+#define ANDROID_IARC_VIDEO_BRIDGE_H
+
+#include <arc/IArcBridgeService.h>
+#include <binder/IInterface.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class IArcVideoBridge : public IInterface {
+public:
+    DECLARE_META_INTERFACE(ArcVideoBridge);
+
+    // Returns MojoBootstrapResult for creating mojo ipc channel of
+    // VideoAcceleratorFactory.
+    virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0;
+
+    // Get the version of the remote VideoHost on Chromium side.
+    virtual int32_t hostVersion() = 0;
+};
+
+class BnArcVideoBridge : public BnInterface<IArcVideoBridge> {
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+};  // namespace android
+
+#endif // ANDROID_IARC_VIDEO_BRIDGE_H
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index 67f4511..4de314d 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -63,7 +63,7 @@
     // Construct a new instance of a CasPlugin given a CA_system_id
     virtual status_t createPlugin(
             int32_t CA_system_id,
-            uint64_t appData,
+            void *appData,
             CasPluginCallback callback,
             CasPlugin **plugin) = 0;
 
diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
index 0a51952..033c8ce 100644
--- a/headers/media_plugin/media/cas/DescramblerAPI.h
+++ b/headers/media_plugin/media/cas/DescramblerAPI.h
@@ -48,6 +48,10 @@
         kScrambling_Reserved    = 1,
         kScrambling_EvenKey     = 2,
         kScrambling_OddKey      = 3,
+        kScrambling_Mask_Key    = 0x3,
+
+        // Hint that the descrambling request is for a PES header only
+        kScrambling_Flag_PesHeader = (1 << 31),
     };
 
     struct SubSample {
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index 985d919..c44a1f6 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -102,7 +102,9 @@
             kKeyRequestType_Unknown,
             kKeyRequestType_Initial,
             kKeyRequestType_Renewal,
-            kKeyRequestType_Release
+            kKeyRequestType_Release,
+            kKeyRequestType_None,
+            kKeyRequestType_Update,
         };
 
         // Enumerate KeyStatusTypes which indicate the state of a key
@@ -123,6 +125,48 @@
             KeyStatusType mType;
         };
 
+        // Enumerate HDCP output protection levels
+        enum HdcpLevel {
+            // Failure to access HDCP level, an error occurred
+            kHdcpLevelUnknown,
+            // HDCP is not supported on this device, content is unprotected
+            kHdcpNone,
+            // HDCP version 1.0
+            kHdcpV1,
+            // HDCP version 2.0 Type 1.
+            kHdcpV2,
+            // HDCP version 2.1 Type 1.
+            kHdcpV2_1,
+            // HDCP version 2.2 Type 1.
+            kHdcpV2_2,
+            // No digital output, implicitly secure
+            kHdcpNoOutput = 0x7fff
+        };
+
+        // SecurityLevel indicates the level of robustness of the DRM
+        // implementation on the device
+        enum SecurityLevel {
+            // Failure to access security level, an error occurred
+            kSecurityLevelUnknown,
+            // The maximum security level of the device. This is the default when
+            // a session is opened if no security level is specified
+            kSecurityLevelMax,
+            // Software-based whitebox crypto
+            kSecurityLevelSwSecureCrypto,
+            // Software-based whitebox crypto and an obfuscated decoder
+            kSecurityLevelSwSecureDecode,
+            // DRM key management and crypto operations are performed within a
+            // hardware backed trusted execution environment
+            kSecurityLevelHwSecureCrypto,
+            // DRM key management, crypto operations and decoding of content
+            // are performed within a hardware backed trusted execution environment
+            kSecurityLevelHwSecureDecode,
+            // DRM key management, crypto operations, decoding of content  and all
+            // handling of the media (compressed and uncompressed) is handled within
+            // a hardware backed trusted execution environment.
+            kSecurityLevelHwSecureAll
+        };
+
         DrmPlugin() {}
         virtual ~DrmPlugin() {}
 
diff --git a/headers/media_plugin/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h
index 9c0296b..f8a36bd 100644
--- a/headers/media_plugin/media/openmax/OMX_Audio.h
+++ b/headers/media_plugin/media/openmax/OMX_Audio.h
@@ -263,6 +263,7 @@
   OMX_AUDIO_AACObjectLD = 23,       /**< AAC Low Delay object (Error Resilient) */
   OMX_AUDIO_AACObjectHE_PS = 29,    /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */
   OMX_AUDIO_AACObjectELD = 39,      /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/
+  OMX_AUDIO_AACObjectXHE = 42,      /** extended High Efficiency AAC. NOTE: Pending Khronos standardization */
   OMX_AUDIO_AACObjectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
   OMX_AUDIO_AACObjectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
   OMX_AUDIO_AACObjectMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
index 05c2232..8409553 100644
--- a/headers/media_plugin/media/openmax/OMX_AudioExt.h
+++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h
@@ -82,6 +82,7 @@
                                    limit the audio signal. Use 0 to let encoder decide */
 } OMX_AUDIO_PARAM_ANDROID_OPUSTYPE;
 
+/** deprecated. use OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
 typedef struct OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE {
     OMX_U32 nSize;            /**< size of the structure in bytes */
     OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
@@ -94,6 +95,19 @@
     OMX_S32 nPCMLimiterEnable;     /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */
 } OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE;
 
+typedef struct OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_S32 nMaxOutputChannels;    /**< Maximum channel count to be output, -1 if unspecified, 0 if downmixing disabled */
+    OMX_S32 nDrcCut;               /**< The DRC attenuation factor, between 0 and 127, -1 if unspecified */
+    OMX_S32 nDrcBoost;             /**< The DRC amplification factor, between 0 and 127, -1 if unspecified */
+    OMX_S32 nHeavyCompression;     /**< 0 for light compression, 1 for heavy compression, -1 if unspecified */
+    OMX_S32 nTargetReferenceLevel; /**< Target reference level, between 0 and 127, -1 if unspecified */
+    OMX_S32 nEncodedTargetLevel;   /**< Target reference level assumed at the encoder, between 0 and 127, -1 if unspecified */
+    OMX_S32 nPCMLimiterEnable;     /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */
+    OMX_S32 nDrcEffectType;        /**< MPEG-D DRC effect type, between -1 and 6, -2 if unspecified */
+} OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE;
+
 typedef struct OMX_AUDIO_PARAM_ANDROID_PROFILETYPE {
    OMX_U32 nSize;
    OMX_VERSIONTYPE nVersion;
diff --git a/headers/media_plugin/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h
index f9b6f4b..f83114b 100644
--- a/headers/media_plugin/media/openmax/OMX_IVCommon.h
+++ b/headers/media_plugin/media/openmax/OMX_IVCommon.h
@@ -165,6 +165,14 @@
      *  format for it. */
     OMX_COLOR_FormatYUV420Flexible = 0x7F420888,
 
+    // 10-bit or 12-bit YUV format, LSB-justified (0's on higher bits)
+    OMX_COLOR_FormatYUV420Planar16 = 0x7F42016B,
+
+    // Packed 10-bit YUV444 representation that includes 2 bits of alpha. Each pixel is
+    // 32-bit. Bits 0-9 contain the U sample, bits 10-19 contain the Y sample,
+    // bits 20-29 contain the V sample, and bits 30-31 contain the alpha value.
+    OMX_COLOR_FormatYUV444Y410 = 0x7F444AAA,
+
     OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,
     OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00,
     OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03,
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 5a029d0..716d959 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -63,6 +63,7 @@
     OMX_IndexParamAudioAndroidAacPresentation,      /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */
     OMX_IndexParamAudioAndroidEac3,                 /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
     OMX_IndexParamAudioProfileQuerySupported,       /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
+    OMX_IndexParamAudioAndroidAacDrcPresentation,   /**< reference: OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
     OMX_IndexExtAudioEndUnused,
 
     /* Image parameters and configurations */
@@ -85,6 +86,7 @@
     OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexParamVideoVp9,                         /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
     OMX_IndexParamVideoAndroidVp9Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
+    OMX_IndexParamVideoAndroidImageGrid,            /**< reference: OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE */
     OMX_IndexExtVideoEndUnused,
 
     /* Image & Video common configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index 76efac9..9fd2fd2 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -89,6 +89,7 @@
     OMX_VIDEO_CodingVP9,        /**< Google VP9 */
     OMX_VIDEO_CodingHEVC,       /**< ITU H.265/HEVC */
     OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */
+    OMX_VIDEO_CodingImageHEIC,  /**< HEIF image encoded with HEVC */
     OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_CodingMax = 0x7FFFFFFF
@@ -240,6 +241,7 @@
     OMX_Video_ControlRateConstant,
     OMX_Video_ControlRateVariableSkipFrames,
     OMX_Video_ControlRateConstantSkipFrames,
+    OMX_Video_ControlRateConstantQuality,
     OMX_Video_ControlRateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_Video_ControlRateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_Video_ControlRateMax = 0x7FFFFFFF
@@ -254,14 +256,20 @@
  *  nVersion       : OMX spec version info
  *  nPortIndex     : Port that this struct applies to
  *  eControlRate   : Control rate type enum
- *  nTargetBitrate : Target bitrate to encode with
+ *  nTargetBitrate : Target bitrate to encode with (used when eControlRate is
+ *                   not OMX_Video_ControlRateConstantQuality)
+ *  nQualityFactor : Quality to encode with (used when eControlRate is
+ *                   OMX_Video_ControlRateConstantQuality only)
  */
 typedef struct OMX_VIDEO_PARAM_BITRATETYPE {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
     OMX_U32 nPortIndex;
     OMX_VIDEO_CONTROLRATETYPE eControlRate;
-    OMX_U32 nTargetBitrate;
+    union {
+        OMX_U32 nTargetBitrate;
+        OMX_U32 nQualityFactor;
+    };
 } OMX_VIDEO_PARAM_BITRATETYPE;
 
 
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index c102564..bbf157b 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -213,6 +213,7 @@
     OMX_VIDEO_HEVCProfileUnknown      = 0x0,
     OMX_VIDEO_HEVCProfileMain         = 0x1,
     OMX_VIDEO_HEVCProfileMain10       = 0x2,
+    OMX_VIDEO_HEVCProfileMainStill    = 0x4,
     // Main10 profile with HDR SEI support.
     OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
     OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
@@ -421,6 +422,49 @@
     OMX_U32 nBitrateRatios[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
 } OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE;
 
+/**
+ * Android specific param for specifying image grid layout information for image encoding
+ * use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid.
+ *
+ * OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set
+ * on the component with bEnabled set to true, nTileWidth, nTileHeight, nGridRows,
+ * nGridCols indicates the desired grid config by the client. The component can use this
+ * as a heuristic, and is free to choose any suitable grid configs. The client shall
+ * always get the actual from the component after the param is set. Encoder will receive
+ * each input image in full, and shall encode it into tiles in row-major, top-row first,
+ * left-to-right order, and send each encoded tile in a separate output buffer. All output
+ * buffers for the same input buffer shall carry the same timestamp as the input buffer.
+ * If the input buffer is marked EOS, the EOS should only appear on the last output buffer
+ * for that input buffer.
+ *
+ * OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image
+ * encoding, although in this case the param only serves as a hint. The encoder will
+ * receive the input image tiles in row-major, top-row first, left-to-right order.
+ * The grid config can be used for quality control, or optimizations.
+ *
+ * If this param is not set, the component shall assume that grid option is disabled.
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to (output port for encoders)
+ *  bEnabled                   : Whether grid is enabled. If true, the other parameters
+ *                               specifies the grid config; otherwise they shall be ignored.
+ *  nTileWidth                 : Width of each tile.
+ *  nTileHeight                : Height of each tile.
+ *  nGridRows                  : Number of rows in the grid.
+ *  nGridCols                  : Number of cols in the grid.
+ */
+typedef struct OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+    OMX_U32 nTileWidth;
+    OMX_U32 nTileHeight;
+    OMX_U32 nGridRows;
+    OMX_U32 nGridCols;
+} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
index 6020870..7c4be24 100644
--- a/include/android/hardware_buffer_jni.h
+++ b/include/android/hardware_buffer_jni.h
@@ -31,9 +31,11 @@
 
 /**
  * Return the AHardwareBuffer associated with a Java HardwareBuffer object,
- * for interacting with it through native code.  This acquires a reference
- * on the AHardwareBuffer that is returned; be sure to use
- * AHardwareBuffer_release() when done with it so that it doesn't leak.
+ * for interacting with it through native code. This method does not acquire any
+ * additional reference to the AHardwareBuffer that is returned. To keep the
+ * AHardwareBuffer live after the Java HardwareBuffer object got garbage
+ * collected, be sure to use AHardwareBuffer_acquire() to acquire an additional
+ * reference.
  */
 AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
         jobject hardwareBufferObj);
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 2164d61..59d67f3 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -767,7 +767,9 @@
     /** fingerprint navigation key, right. */
     AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
     /** all apps */
-    AKEYCODE_ALL_APPS = 284
+    AKEYCODE_ALL_APPS = 284,
+    /** refresh key */
+    AKEYCODE_REFRESH = 285
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 7f46087..191777c 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -65,9 +65,14 @@
 #define ASENSOR_FIFO_COUNT_INVALID     (-1)
 #define ASENSOR_DELAY_INVALID          INT32_MIN
 
+/* (Keep in sync with hardware/sensors-base.h and Sensor.java.) */
+
 /**
  * Sensor types.
- * (keep in sync with hardware/sensors.h)
+ *
+ * See
+ * [android.hardware.SensorEvent#values](https://developer.android.com/reference/android/hardware/SensorEvent.html#values)
+ * for detailed explanations of the data returned for each of these types.
  */
 enum {
     /**
@@ -106,6 +111,12 @@
      */
     ASENSOR_TYPE_LIGHT               = 5,
     /**
+     * {@link ASENSOR_TYPE_PRESSURE}
+     *
+     * The pressure sensor value is returned in hPa (millibar).
+     */
+    ASENSOR_TYPE_PRESSURE            = 6,
+    /**
      * {@link ASENSOR_TYPE_PROXIMITY}
      * reporting-mode: on-change
      *
@@ -117,13 +128,93 @@
      */
     ASENSOR_TYPE_PROXIMITY           = 8,
     /**
+     * {@link ASENSOR_TYPE_GRAVITY}
+     *
+     * All values are in SI units (m/s^2) and measure the direction and
+     * magnitude of gravity. When the device is at rest, the output of
+     * the gravity sensor should be identical to that of the accelerometer.
+     */
+    ASENSOR_TYPE_GRAVITY             = 9,
+    /**
      * {@link ASENSOR_TYPE_LINEAR_ACCELERATION}
      * reporting-mode: continuous
      *
      *  All values are in SI units (m/s^2) and measure the acceleration of the
      *  device not including the force of gravity.
      */
-    ASENSOR_TYPE_LINEAR_ACCELERATION = 10
+    ASENSOR_TYPE_LINEAR_ACCELERATION = 10,
+    /**
+     * {@link ASENSOR_TYPE_ROTATION_VECTOR}
+     */
+    ASENSOR_TYPE_ROTATION_VECTOR     = 11,
+    /**
+     * {@link ASENSOR_TYPE_RELATIVE_HUMIDITY}
+     *
+     * The relative humidity sensor value is returned in percent.
+     */
+    ASENSOR_TYPE_RELATIVE_HUMIDITY   = 12,
+    /**
+     * {@link ASENSOR_TYPE_AMBIENT_TEMPERATURE}
+     *
+     * The ambient temperature sensor value is returned in Celcius.
+     */
+    ASENSOR_TYPE_AMBIENT_TEMPERATURE = 13,
+    /**
+     * {@link ASENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED}
+     */
+    ASENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14,
+    /**
+     * {@link ASENSOR_TYPE_GAME_ROTATION_VECTOR}
+     */
+    ASENSOR_TYPE_GAME_ROTATION_VECTOR = 15,
+    /**
+     * {@link ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED}
+     */
+    ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED = 16,
+    /**
+     * {@link ASENSOR_TYPE_SIGNIFICANT_MOTION}
+     */
+    ASENSOR_TYPE_SIGNIFICANT_MOTION = 17,
+    /**
+     * {@link ASENSOR_TYPE_STEP_DETECTOR}
+     */
+    ASENSOR_TYPE_STEP_DETECTOR = 18,
+    /**
+     * {@link ASENSOR_TYPE_STEP_COUNTER}
+     */
+    ASENSOR_TYPE_STEP_COUNTER = 19,
+    /**
+     * {@link ASENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR}
+     */
+    ASENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20,
+    /**
+     * {@link ASENSOR_TYPE_HEART_RATE}
+     */
+    ASENSOR_TYPE_HEART_RATE = 21,
+    /**
+     * {@link ASENSOR_TYPE_POSE_6DOF}
+     */
+    ASENSOR_TYPE_POSE_6DOF = 28,
+    /**
+     * {@link ASENSOR_TYPE_STATIONARY_DETECT}
+     */
+    ASENSOR_TYPE_STATIONARY_DETECT = 29,
+    /**
+     * {@link ASENSOR_TYPE_MOTION_DETECT}
+     */
+    ASENSOR_TYPE_MOTION_DETECT = 30,
+    /**
+     * {@link ASENSOR_TYPE_HEART_BEAT}
+     */
+    ASENSOR_TYPE_HEART_BEAT = 31,
+    /**
+     * {@link ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT}
+     */
+    ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
+    /**
+     * {@link ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED}
+     */
+    ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED = 35,
 };
 
 /**
@@ -197,7 +288,7 @@
  * A sensor event.
  */
 
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to these structs have to be backward compatible */
 typedef struct ASensorVector {
     union {
         float v[3];
@@ -259,7 +350,7 @@
     };
 } AAdditionalInfoEvent;
 
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to this struct has to be backward compatible */
 typedef struct ASensorEvent {
     int32_t version; /* sizeof(struct ASensorEvent) */
     int32_t sensor;
@@ -388,13 +479,13 @@
 #endif
 
 #if __ANDROID_API__ >= __ANDROID_API_O__
-/*
+/**
  * Get a reference to the sensor manager. ASensorManager is a singleton
  * per package as different packages may have access to different sensors.
  *
  * Example:
  *
- *    ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
+ *     ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
  *
  */
 ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
@@ -503,14 +594,12 @@
  * {@link ASensor_isDirectChannelTypeSupported}, respectively.
  *
  * Example:
- * \code{.cpp}
- *      ASensorManager *manager = ...;
- *      ASensor *sensor = ...;
- *      int channelId = ...;
  *
- *      ASensorManager_configureDirectReport(
- *              manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
- * \endcode
+ *     ASensorManager *manager = ...;
+ *     ASensor *sensor = ...;
+ *     int channelId = ...;
+ *
+ *     ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST);
  *
  * \param manager   the {@link ASensorManager} instance obtained from
  *                  {@link ASensorManager_getInstanceForPackage}.
@@ -530,50 +619,86 @@
 /*****************************************************************************/
 
 /**
- * Enable the selected sensor with a specified sampling period and max batch report latency.
- * Returns a negative error code on failure.
- * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before.
+ * Enable the selected sensor with sampling and report parameters
+ *
+ * Enable the selected sensor at a specified sampling period and max batch report latency.
+ * To disable  sensor, use {@link ASensorEventQueue_disableSensor}.
+ *
+ * \param queue {@link ASensorEventQueue} for sensor event to be report to.
+ * \param sensor {@link ASensor} to be enabled.
+ * \param samplingPeriodUs sampling period of sensor in microseconds.
+ * \param maxBatchReportLatencyus maximum time interval between two batch of sensor events are
+ *                                delievered in microseconds. For sensor streaming, set to 0.
+ * \return 0 on success or a negative error code on failure.
  */
 int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
         int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs);
 
 /**
- * Enable the selected sensor. Returns a negative error code on failure.
+ * Enable the selected sensor at default sampling rate.
+ *
+ * Start event reports of a sensor to specified sensor event queue at a default rate.
+ *
+ * \param queue {@link ASensorEventQueue} for sensor event to be report to.
+ * \param sensor {@link ASensor} to be enabled.
+ *
+ * \return 0 on success or a negative error code on failure.
  */
 int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /**
- * Disable the selected sensor. Returns a negative error code on failure.
+ * Disable the selected sensor.
+ *
+ * Stop event reports from the sensor to specified sensor event queue.
+ *
+ * \param queue {@link ASensorEventQueue} to be changed
+ * \param sensor {@link ASensor} to be disabled
+ * \return 0 on success or a negative error code on failure.
  */
 int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /**
  * Sets the delivery rate of events in microseconds for the given sensor.
+ *
+ * This function has to be called after {@link ASensorEventQueue_enableSensor}.
  * Note that this is a hint only, generally event will arrive at a higher
  * rate. It is an error to set a rate inferior to the value returned by
  * ASensor_getMinDelay().
- * Returns a negative error code on failure.
+ *
+ * \param queue {@link ASensorEventQueue} to which sensor event is delivered.
+ * \param sensor {@link ASensor} of which sampling rate to be updated.
+ * \param usec sensor sampling period (1/sampling rate) in microseconds
+ * \return 0 on sucess or a negative error code on failure.
  */
 int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
 
 /**
- * Returns true if there are one or more events available in the
- * sensor queue.  Returns 1 if the queue has events; 0 if
- * it does not have events; and a negative value if there is an error.
+ * Determine if a sensor event queue has pending event to be processed.
+ *
+ * \param queue {@link ASensorEventQueue} to be queried
+ * \return 1 if the queue has events; 0 if it does not have events;
+ *         or a negative value if there is an error.
  */
 int ASensorEventQueue_hasEvents(ASensorEventQueue* queue);
 
 /**
- * Returns the next available events from the queue.  Returns a negative
- * value if no events are available or an error has occurred, otherwise
- * the number of events returned.
+ * Retrieve pending events in sensor event queue
+ *
+ * Retrieve next available events from the queue to a specified event array.
+ *
+ * \param queue {@link ASensorEventQueue} to get events from
+ * \param events pointer to an array of {@link ASensorEvents}.
+ * \param count max number of event that can be filled into array event.
+ * \return number of events returned on success; negative error code when
+ *         no events are pending or an error has occurred.
  *
  * Examples:
- *   ASensorEvent event;
- *   ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1);
  *
- *   ASensorEvent eventBuffer[8];
- *   ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
+ *     ASensorEvent event;
+ *     ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1);
+ *
+ *     ASensorEvent eventBuffer[8];
+ *     ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8);
  *
  */
 ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
new file mode 100644
index 0000000..56b3342
--- /dev/null
+++ b/include/android/surface_texture.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+#include <stdint.h>
+
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceTexture;
+
+/**
+ * {@link ASurfaceTexture} is an opaque type to manage SurfaceTexture from native code
+ *
+ * {@link ASurfaceTexture} can be obtained from an android.graphics.SurfaceTexture object using
+ * ASurfaceTexture_fromSurfaceTexture().
+ */
+typedef struct ASurfaceTexture ASurfaceTexture;
+
+/**
+ * Release the reference to the native ASurfaceTexture acquired with
+ * ASurfaceTexture_fromSurfaceTexture().
+ * Failing to do so will result in leaked memory and graphic resources.
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+void ASurfaceTexture_release(ASurfaceTexture* st);
+
+/**
+ * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
+ * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture);
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
+ * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
+ * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture
+ */
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st);
+
+/**
+ * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.  A
+ * new OpenGL ES texture object is created and populated with the SurfaceTexture image frame
+ * that was current at the time of the last call to {@link #detachFromGLContext}.  This new
+ * texture is bound to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param texName The name of the OpenGL ES texture that will be created.  This texture name
+ * must be unusued in the OpenGL ES context that is current on the calling thread.
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName);
+
+/**
+ * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
+ * This call must be made with the OpenGL ES context current on the calling thread.  The OpenGL
+ * ES texture object will be deleted as a result of this call.  After calling this method all
+ * calls to {@link #updateTexImage} will fail until a successful call to {@link #attachToGLContext}
+ * is made.
+ *
+ * This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
+ * contexts.  Note, however, that the image contents are only accessible from one OpenGL ES
+ * context at a time.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st);
+
+/**
+ * Update the texture image to the most recent frame from the image stream.  This may only be
+ * called while the OpenGL ES context that owns the texture is current on the calling thread.
+ * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \return 0 on success, negative posix error code otherwise (see <errno.h>)
+ */
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st);
+
+/**
+ * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
+ * the most recent call to updateTexImage.
+ *
+ * This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s
+ * and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample
+ * that location from the texture.  Sampling the texture outside of the range of this transform
+ * is undefined.
+ *
+ * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via
+ * the glLoadMatrixf or glUniformMatrix4fv functions.
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
+ *     16 elements.
+ */
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+
+/**
+ * Retrieve the timestamp associated with the texture image set by the most recent call to
+ * updateTexImage.
+ *
+ * This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp
+ * should be unaffected by time-of-day adjustments, and for a camera should be strictly
+ * monotonic but for a MediaPlayer may be reset when the position is set.  The
+ * specific meaning and zero point of the timestamp depends on the source providing images to
+ * the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
+ * generally be compared across SurfaceTexture instances, or across multiple program
+ * invocations. It is mostly useful for determining time offsets between subsequent frames.
+ *
+ * For EGL/Vulkan producers, this timestamp is the desired present time set with the
+ * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions
+ *
+ * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
+ */
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
new file mode 100644
index 0000000..b0e1edd
--- /dev/null
+++ b/include/android/surface_texture_jni.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup SurfaceTexture
+ * @{
+ */
+
+/**
+ * @file surface_texture_jni.h
+ */
+
+#ifndef ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+#define ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H
+
+#include <android/surface_texture.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/**
+ * Get a reference to the native ASurfaceTexture from the corresponding java object.
+ *
+ * The caller must keep a reference to the Java SurfaceTexture during the lifetime of the returned
+ * ASurfaceTexture. Failing to do so could result in the ASurfaceTexture to stop functioning
+ * properly once the Java object gets finalized.
+ * However, this will not result in program termination.
+ *
+ * \param env JNI environment
+ * \param surfacetexture Instance of Java SurfaceTexture object
+ * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture.
+ *         The returned reference MUST BE released when it's no longer needed using
+ *         ASurfaceTexture_release().
+ */
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+
+__END_DECLS
+
+#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index ce7804b..d279bbd 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -32,85 +32,10 @@
     // These transaction IDs must be kept in sync with the method order from
     // IAudioService.aidl.
     enum {
-        // transaction IDs for the unsupported methods are commented out
-        /*
-        ADJUSTSUGGESTEDSTREAMVOLUME           = IBinder::FIRST_CALL_TRANSACTION,
-        ADJUSTSTREAMVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 1,
-        SETSTREAMVOLUME                       = IBinder::FIRST_CALL_TRANSACTION + 2,
-        ISSTREAMMUTE                          = IBinder::FIRST_CALL_TRANSACTION + 3,
-        FORCEREMOTESUBMIXFULLVOLUME           = IBinder::FIRST_CALL_TRANSACTION + 4,
-        ISMASTERMUTE                          = IBinder::FIRST_CALL_TRANSACTION + 5,
-        SETMASTERMUTE                         = IBinder::FIRST_CALL_TRANSACTION + 6,
-        GETSTREAMVOLUME                       = IBinder::FIRST_CALL_TRANSACTION + 7,
-        GETSTREAMMINVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 8,
-        GETSTREAMMAXVOLUME                    = IBinder::FIRST_CALL_TRANSACTION + 9,
-        GETLASTAUDIBLESTREAMVOLUME            = IBinder::FIRST_CALL_TRANSACTION + 10,
-        SETMICROPHONEMUTE                     = IBinder::FIRST_CALL_TRANSACTION + 11,
-        SETRINGERMODEEXTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 12,
-        SETRINGERMODEINTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 13,
-        GETRINGERMODEEXTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 14,
-        GETRINGERMODEINTERNAL                 = IBinder::FIRST_CALL_TRANSACTION + 15,
-        ISVALIDRINGERMODE                     = IBinder::FIRST_CALL_TRANSACTION + 16,
-        SETVIBRATESETTING                     = IBinder::FIRST_CALL_TRANSACTION + 17,
-        GETVIBRATESETTING                     = IBinder::FIRST_CALL_TRANSACTION + 18,
-        SHOULDVIBRATE                         = IBinder::FIRST_CALL_TRANSACTION + 19,
-        SETMODE                               = IBinder::FIRST_CALL_TRANSACTION + 20,
-        GETMODE                               = IBinder::FIRST_CALL_TRANSACTION + 21,
-        PLAYSOUNDEFFECT                       = IBinder::FIRST_CALL_TRANSACTION + 22,
-        PLAYSOUNDEFFECTVOLUME                 = IBinder::FIRST_CALL_TRANSACTION + 23,
-        LOADSOUNDEFFECTS                      = IBinder::FIRST_CALL_TRANSACTION + 24,
-        UNLOADSOUNDEFFECTS                    = IBinder::FIRST_CALL_TRANSACTION + 25,
-        RELOADAUDIOSETTINGS                   = IBinder::FIRST_CALL_TRANSACTION + 26,
-        AVRCPSUPPORTSABSOLUTEVOLUME           = IBinder::FIRST_CALL_TRANSACTION + 27,
-        SETSPEAKERPHONEON                     = IBinder::FIRST_CALL_TRANSACTION + 28,
-        ISSPEAKERPHONEON                      = IBinder::FIRST_CALL_TRANSACTION + 29,
-        SETBLUETOOTHSCOON                     = IBinder::FIRST_CALL_TRANSACTION + 30,
-        ISBLUETOOTHSCOON                      = IBinder::FIRST_CALL_TRANSACTION + 31,
-        SETBLUETOOTHA2DPON                    = IBinder::FIRST_CALL_TRANSACTION + 32,
-        ISBLUETOOTHA2DPON                     = IBinder::FIRST_CALL_TRANSACTION + 33,
-        REQUESTAUDIOFOCUS                     = IBinder::FIRST_CALL_TRANSACTION + 34,
-        ABANDONAUDIOFOCUS                     = IBinder::FIRST_CALL_TRANSACTION + 35,
-        UNREGISTERAUDIOFOCUSCLIENT            = IBinder::FIRST_CALL_TRANSACTION + 36,
-        GETCURRENTAUDIOFOCUS                  = IBinder::FIRST_CALL_TRANSACTION + 37,
-        STARTBLUETOOTHSCO                     = IBinder::FIRST_CALL_TRANSACTION + 38,
-        STARTBLUETOOTHSCOVIRTUALCALL          = IBinder::FIRST_CALL_TRANSACTION + 39,
-        STOPBLUETOOTHSCO                      = IBinder::FIRST_CALL_TRANSACTION + 40,
-        FORCEVOLUMECONTROLSTREAM              = IBinder::FIRST_CALL_TRANSACTION + 41,
-        SETRINGTONEPLAYER                     = IBinder::FIRST_CALL_TRANSACTION + 42,
-        GETRINGTONEPLAYER                     = IBinder::FIRST_CALL_TRANSACTION + 43,
-        GETUISOUNDSSTREAMTYPE                 = IBinder::FIRST_CALL_TRANSACTION + 44,
-        SETWIREDDEVICECONNECTIONSTATE         = IBinder::FIRST_CALL_TRANSACTION + 45,
-        SETBLUETOOTHA2DPDEVICECONNECTIONSTATE = IBinder::FIRST_CALL_TRANSACTION + 46,
-        HANDLEBLUETOOTHA2DPDEVICECONFIGCHANGE = IBinder::FIRST_CALL_TRANSACTION + 47,
-        STARTWATCHINGROUTES                   = IBinder::FIRST_CALL_TRANSACTION + 48,
-        ISCAMERASOUNDFORCED                   = IBinder::FIRST_CALL_TRANSACTION + 49,
-        SETVOLUMECONTROLLER                   = IBinder::FIRST_CALL_TRANSACTION + 50,
-        NOTIFYVOLUMECONTROLLERVISIBLE         = IBinder::FIRST_CALL_TRANSACTION + 51,
-        ISSTREAMAFFECTEDBYRINGERMODE          = IBinder::FIRST_CALL_TRANSACTION + 52,
-        ISSTREAMAFFECTEDBYMUTE                = IBinder::FIRST_CALL_TRANSACTION + 53,
-        DISABLESAFEMEDIAVOLUME                = IBinder::FIRST_CALL_TRANSACTION + 54,
-        SETHDMISYSTEMAUDIOSUPPORTED           = IBinder::FIRST_CALL_TRANSACTION + 55,
-        ISHDMISYSTEMAUDIOSUPPORTED            = IBinder::FIRST_CALL_TRANSACTION + 56,
-        REGISTERAUDIOPOLICY                   = IBinder::FIRST_CALL_TRANSACTION + 57,
-        UNREGISTERAUDIOPOLICYASYNC            = IBinder::FIRST_CALL_TRANSACTION + 58,
-        SETFOCUSPROPERTIESFORPOLICY           = IBinder::FIRST_CALL_TRANSACTION + 59,
-        SETVOLUMEPOLICY                       = IBinder::FIRST_CALL_TRANSACTION + 60,
-        REGISTERRECORDINGCALLBACK             = IBinder::FIRST_CALL_TRANSACTION + 61,
-        UNREGISTERRECORDINGCALLBACK           = IBinder::FIRST_CALL_TRANSACTION + 62,
-        GETACTIVERECORDINGCONFIGURATIONS      = IBinder::FIRST_CALL_TRANSACTION + 63,
-        REGISTERPLAYBACKCALLBACK              = IBinder::FIRST_CALL_TRANSACTION + 64,
-        UNREGISTERPLAYBACKCALLBACK            = IBinder::FIRST_CALL_TRANSACTION + 65,
-        GETACTIVEPLAYBACKCONFIGURATIONS       = IBinder::FIRST_CALL_TRANSACTION + 66,
-        */
-
-        TRACK_PLAYER                          = IBinder::FIRST_CALL_TRANSACTION + 67,
-        PLAYER_ATTRIBUTES                     = IBinder::FIRST_CALL_TRANSACTION + 68,
-        PLAYER_EVENT                          = IBinder::FIRST_CALL_TRANSACTION + 69,
-        RELEASE_PLAYER                        = IBinder::FIRST_CALL_TRANSACTION + 70,
-
-        /*
-        DISABLE_RINGTONE_SYNC                 = IBinder::FIRST_CALL_TRANSACTION + 71,
-        */
+        TRACK_PLAYER                          = IBinder::FIRST_CALL_TRANSACTION,
+        PLAYER_ATTRIBUTES                     = IBinder::FIRST_CALL_TRANSACTION + 1,
+        PLAYER_EVENT                          = IBinder::FIRST_CALL_TRANSACTION + 2,
+        RELEASE_PLAYER                        = IBinder::FIRST_CALL_TRANSACTION + 3,
     };
 
     DECLARE_META_INTERFACE(AudioManager)
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
deleted file mode 100644
index de5c1c7..0000000
--- a/include/audiomanager/IPlayer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 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 ANDROID_IPLAYER_H
-#define ANDROID_IPLAYER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/VolumeShaper.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IPlayer : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(Player);
-
-    virtual void start() = 0;
-
-    virtual void pause() = 0;
-
-    virtual void stop() = 0;
-
-    virtual void setVolume(float vol) = 0;
-
-    virtual void setPan(float pan) = 0;
-
-    virtual void setStartDelayMs(int delayMs) = 0;
-
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnPlayer : public BnInterface<IPlayer>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPLAYER_H
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index c282cf0..4b33a96 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -324,6 +324,7 @@
     DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT),
     DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT),
     DEFINE_KEYCODE(ALL_APPS),
+    DEFINE_KEYCODE(REFRESH),
 
     { NULL, 0 }
 };
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 9f3d45a..ecdc075 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -31,7 +31,6 @@
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/BitSet.h>
 
@@ -155,16 +154,16 @@
     virtual ~InputChannel();
 
 public:
-    InputChannel(const String8& name, int fd);
+    InputChannel(const std::string& name, int fd);
 
     /* Creates a pair of input channels.
      *
      * Returns OK on success.
      */
-    static status_t openInputChannelPair(const String8& name,
+    static status_t openInputChannelPair(const std::string& name,
             sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
 
-    inline String8 getName() const { return mName; }
+    inline std::string getName() const { return mName; }
     inline int getFd() const { return mFd; }
 
     /* Sends a message to the other endpoint.
@@ -196,7 +195,7 @@
     sp<InputChannel> dup() const;
 
 private:
-    String8 mName;
+    std::string mName;
     int mFd;
 };
 
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 7935927..33d2757 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -51,6 +51,9 @@
         KEYBOARD_TYPE_PREDICTIVE = 2,
         KEYBOARD_TYPE_ALPHA = 3,
         KEYBOARD_TYPE_FULL = 4,
+        /**
+         * Deprecated. Set 'keyboard.specialFunction' to '1' in the device's IDC file instead.
+         */
         KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
         KEYBOARD_TYPE_OVERLAY = 6,
     };
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 795f575..ffa1614 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -264,6 +264,40 @@
     Movement mMovements[HISTORY_SIZE];
 };
 
+class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
+public:
+    ImpulseVelocityTrackerStrategy();
+    virtual ~ImpulseVelocityTrackerStrategy();
+
+    virtual void clear();
+    virtual void clearPointers(BitSet32 idBits);
+    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+            const VelocityTracker::Position* positions);
+    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+
+private:
+    // Sample horizon.
+    // We don't use too much history by default since we want to react to quick
+    // changes in direction.
+    static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms
+
+    // Number of samples to keep.
+    static constexpr size_t HISTORY_SIZE = 20;
+
+    struct Movement {
+        nsecs_t eventTime;
+        BitSet32 idBits;
+        VelocityTracker::Position positions[MAX_POINTERS];
+
+        inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+            return positions[idBits.getIndexOfBit(id)];
+        }
+    };
+
+    size_t mIndex;
+    Movement mMovements[HISTORY_SIZE];
+};
+
 } // namespace android
 
 #endif // _LIBINPUT_VELOCITY_TRACKER_H
diff --git a/include/layerproto b/include/layerproto
new file mode 120000
index 0000000..ef21a4e
--- /dev/null
+++ b/include/layerproto
@@ -0,0 +1 @@
+../services/surfaceflinger/layerproto/include/layerproto/
\ No newline at end of file
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 380e745..0ec3e94 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -81,7 +81,6 @@
             int inside = spanner.next(current.top, current.bottom);
             spannerInner.prepare(inside);
             do {
-                TYPE left, right;
                 int inner_inside = spannerInner.next(current.left, current.right);
                 if ((op_mask >> inner_inside) & 1) {
                     if (current.left < current.right && 
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index 80741c0..b36728e 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -33,23 +33,26 @@
 #endif
 
 /**
- * {@link ARect} is a struct that represents a rectangular window area.
+ * Rectangular window area.
  *
- * It is used with {@link
- * ANativeActivityCallbacks::onContentRectChanged} event callback and
- * ANativeWindow_lock() function.
+ * This is the NDK equivalent of the android.graphics.Rect class in Java. It is
+ * used with {@link ANativeActivityCallbacks::onContentRectChanged} event
+ * callback and the ANativeWindow_lock() function.
+ *
+ * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10,
+ * right=1, bottom=11 contains only one pixel at x=0, y=10.
  */
 typedef struct ARect {
 #ifdef __cplusplus
     typedef int32_t value_type;
 #endif
-    /** left position */
+    /// Minimum X coordinate of the rectangle.
     int32_t left;
-    /** top position */
+    /// Minimum Y coordinate of the rectangle.
     int32_t top;
-    /** left position */
+    /// Maximum X coordinate of the rectangle.
     int32_t right;
-    /** bottom position */
+    /// Maximum Y coordinate of the rectangle.
     int32_t bottom;
 } ARect;
 
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
new file mode 100644
index 0000000..2728f35
--- /dev/null
+++ b/libs/binder/ActivityManager.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <unistd.h>
+
+#include <binder/ActivityManager.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+ActivityManager::ActivityManager()
+{
+}
+
+sp<IActivityManager> ActivityManager::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<IActivityManager> service = mService;
+    while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity"));
+        if (binder == NULL) {
+            // Wait for the activity service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for activity service");
+            } else if ((uptimeMillis() - startTime) > 1000000) {
+                ALOGW("Waiting too long for activity service, giving up");
+                service = NULL;
+                break;
+            }
+            usleep(25000);
+        } else {
+            service = interface_cast<IActivityManager>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+int ActivityManager::openContentUri(const String16& stringUri)
+{
+    sp<IActivityManager> service = getService();
+    return service != NULL ? service->openContentUri(stringUri) : -1;
+}
+
+void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+                                          const int32_t event,
+                                          const int32_t cutpoint,
+                                          const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->registerUidObserver(observer, event, cutpoint, callingPackage);
+    }
+}
+
+void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->unregisterUidObserver(observer);
+    }
+}
+
+bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return service->isUidActive(uid, callingPackage);
+    }
+    return false;
+}
+
+status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+}; // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 83b8021..7c1eaaf 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -38,6 +38,7 @@
     },
 
     srcs: [
+        "ActivityManager.cpp",
         "AppOpsManager.cpp",
         "Binder.cpp",
         "BpBinder.cpp",
@@ -56,11 +57,13 @@
         "IResultReceiver.cpp",
         "IServiceManager.cpp",
         "IShellCallback.cpp",
+        "IUidObserver.cpp",
         "MemoryBase.cpp",
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
         "Parcel.cpp",
         "PermissionCache.cpp",
+        "PermissionController.cpp",
         "PersistableBundle.cpp",
         "ProcessInfoService.cpp",
         "ProcessState.cpp",
@@ -69,9 +72,31 @@
         "TextOutput.cpp",
         "IpPrefix.cpp",
         "Value.cpp",
-        "aidl/android/content/pm/IPackageManagerNative.aidl",
+        ":libbinder_aidl",
     ],
 
+    target: {
+        vendor: {
+            exclude_srcs: [
+                "ActivityManager.cpp",
+                "AppOpsManager.cpp",
+                "IActivityManager.cpp",
+                "IAppOpsCallback.cpp",
+                "IAppOpsService.cpp",
+                "IBatteryStats.cpp",
+                "IMediaResourceMonitor.cpp",
+                "IPermissionController.cpp",
+                "IProcessInfoService.cpp",
+                "IUidObserver.cpp",
+                "PermissionCache.cpp",
+                "PermissionController.cpp",
+                "ProcessInfoService.cpp",
+                "IpPrefix.cpp",
+                ":libbinder_aidl",
+            ],
+        },
+    },
+
     aidl: {
         export_aidl_headers: true,
     },
@@ -92,6 +117,7 @@
         "liblog",
         "libcutils",
         "libutils",
+        "libutilscallstack",
     ],
 
     header_libs: [
@@ -108,4 +134,12 @@
     },
 }
 
+// AIDL interface between libbinder and framework.jar
+filegroup {
+    name: "libbinder_aidl",
+    srcs: [
+        "aidl/android/content/pm/IPackageManagerNative.aidl",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index f3b86ae..62c8987 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -100,11 +100,12 @@
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
-int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+        bool startIfModeDefault) {
     sp<IAppOpsService> service = getService();
     return service != NULL
-            ? service->startOperation(getToken(service), op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            ? service->startOperation(getToken(service), op, uid, callingPackage,
+                    startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 890ef30..a81f44e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -249,6 +249,8 @@
             if (resultReceiver != NULL) {
                 resultReceiver->send(INVALID_OPERATION);
             }
+
+            return NO_ERROR;
         }
 
         case SYSPROPS_TRANSACTION: {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index c0e0296..449a9e9 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IResultReceiver.h>
+#include <cutils/compiler.h>
 #include <utils/Log.h>
 
 #include <stdio.h>
@@ -32,6 +33,23 @@
 
 // ---------------------------------------------------------------------------
 
+Mutex BpBinder::sTrackingLock;
+std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap;
+int BpBinder::sNumTrackedUids = 0;
+std::atomic_bool BpBinder::sCountByUidEnabled(false);
+binder_proxy_limit_callback BpBinder::sLimitCallback;
+bool BpBinder::sBinderProxyThrottleCreate = false;
+
+// Arbitrarily high value that probably distinguishes a bad behaving app
+uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500;
+// Another arbitrary value a binder count needs to drop below before another callback will be called
+uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+
+enum {
+    LIMIT_REACHED_MASK = 0x80000000,        // A flag denoting that the limit has been reached
+    COUNTING_VALUE_MASK = 0x7FFFFFFF,       // A mask of the remaining bits for the count value
+};
+
 BpBinder::ObjectManager::ObjectManager()
 {
 }
@@ -87,16 +105,47 @@
 
 // ---------------------------------------------------------------------------
 
-BpBinder::BpBinder(int32_t handle)
+
+BpBinder* BpBinder::create(int32_t handle) {
+    int32_t trackedUid = -1;
+    if (sCountByUidEnabled) {
+        trackedUid = IPCThreadState::self()->getCallingUid();
+        AutoMutex _l(sTrackingLock);
+        uint32_t trackedValue = sTrackingMap[trackedUid];
+        if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
+            if (sBinderProxyThrottleCreate) {
+                return nullptr;
+            }
+        } else {
+            if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
+                ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
+                      getuid(), trackedUid, trackedValue);
+                sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
+                if (sLimitCallback) sLimitCallback(trackedUid);
+                if (sBinderProxyThrottleCreate) {
+                    ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
+                          " count drops below %d",
+                          trackedUid, getuid(), sBinderProxyCountLowWatermark);
+                    return nullptr;
+                }
+            }
+        }
+        sTrackingMap[trackedUid]++;
+    }
+    return new BpBinder(handle, trackedUid);
+}
+
+BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
     : mHandle(handle)
     , mAlive(1)
     , mObitsSent(0)
     , mObituaries(NULL)
+    , mTrackedUid(trackedUid)
 {
     ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
 
     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
-    IPCThreadState::self()->incWeakHandle(handle);
+    IPCThreadState::self()->incWeakHandle(handle, this);
 }
 
 bool BpBinder::isDescriptorCached() const {
@@ -315,6 +364,26 @@
 
     IPCThreadState* ipc = IPCThreadState::self();
 
+    if (mTrackedUid >= 0) {
+        AutoMutex _l(sTrackingLock);
+        uint32_t trackedValue = sTrackingMap[mTrackedUid];
+        if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) {
+            ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle);
+        } else {
+            if (CC_UNLIKELY(
+                (trackedValue & LIMIT_REACHED_MASK) &&
+                ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark)
+                )) {
+                ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)",
+                                   getuid(), mTrackedUid, sBinderProxyCountLowWatermark);
+                sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK;
+            }
+            if (--sTrackingMap[mTrackedUid] == 0) {
+                sTrackingMap.erase(mTrackedUid);
+            }
+        }
+    }
+
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
     if(obits != NULL) {
@@ -340,7 +409,7 @@
 {
     ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
     IPCThreadState* ipc = IPCThreadState::self();
-    if (ipc) ipc->incStrongHandle(mHandle);
+    if (ipc) ipc->incStrongHandle(mHandle, this);
 }
 
 void BpBinder::onLastStrongRef(const void* /*id*/)
@@ -360,6 +429,42 @@
     return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
 }
 
+uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
+{
+    AutoMutex _l(sTrackingLock);
+    auto it = sTrackingMap.find(uid);
+    if (it != sTrackingMap.end()) {
+        return it->second & COUNTING_VALUE_MASK;
+    }
+    return 0;
+}
+
+void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts)
+{
+    AutoMutex _l(sTrackingLock);
+    uids.setCapacity(sTrackingMap.size());
+    counts.setCapacity(sTrackingMap.size());
+    for (const auto& it : sTrackingMap) {
+        uids.push_back(it.first);
+        counts.push_back(it.second & COUNTING_VALUE_MASK);
+    }
+}
+
+void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); }
+void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); }
+void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); }
+
+void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) {
+    AutoMutex _l(sTrackingLock);
+    sLimitCallback = cb;
+}
+
+void BpBinder::setBinderProxyCountWatermarks(int high, int low) {
+    AutoMutex _l(sTrackingLock);
+    sBinderProxyCountHighWatermark = high;
+    sBinderProxyCountLowWatermark = low;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index a2443c0..30e70b0 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -17,11 +17,11 @@
 #include <binder/BufferedTextOutput.h>
 #include <binder/Debug.h>
 
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
+#include <cutils/threads.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
-#include <cutils/threads.h>
 
 #include <private/binder/Static.h>
 
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 50a8b28..428db4d 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -56,6 +56,40 @@
         }
         return fd;
     }
+
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         data.writeInt32(event);
+         data.writeInt32(cutpoint);
+         data.writeString16(callingPackage);
+         remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
+
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
+
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeInt32(uid);
+         data.writeString16(callingPackage);
+         remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
+         // fail on exception
+         if (reply.readExceptionCode() != 0) return false;
+         return reply.readInt32() == 1;
+    }
 };
 
 // ------------------------------------------------------------------------------------
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 638ae5c..9c76350 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -61,13 +61,14 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName) {
+                const String16& packageName, bool startIfModeDefault) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
+        data.writeInt32(startIfModeDefault ? 1 : 0);
         remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -159,7 +160,8 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            int32_t res = startOperation(token, code, uid, packageName);
+            bool startIfModeDefault = data.readInt32() == 1;
+            int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index e832961..fd552b4 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -409,6 +409,15 @@
     if (mProcess->mDriverFD <= 0)
         return;
     talkWithDriver(false);
+    // The flush could have caused post-write refcount decrements to have
+    // been executed, which in turn could result in BC_RELEASE/BC_DECREFS
+    // being queued in mOut. So flush again, if we need to.
+    if (mOut.dataSize() > 0) {
+        talkWithDriver(false);
+    }
+    if (mOut.dataSize() > 0) {
+        ALOGW("mOut.dataSize() > 0 after flushCommands()");
+    }
 }
 
 void IPCThreadState::blockUntilThreadAvailable()
@@ -470,26 +479,52 @@
 void IPCThreadState::processPendingDerefs()
 {
     if (mIn.dataPosition() >= mIn.dataSize()) {
-        size_t numPending = mPendingWeakDerefs.size();
-        if (numPending > 0) {
-            for (size_t i = 0; i < numPending; i++) {
-                RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+        /*
+         * The decWeak()/decStrong() calls may cause a destructor to run,
+         * which in turn could have initiated an outgoing transaction,
+         * which in turn could cause us to add to the pending refs
+         * vectors; so instead of simply iterating, loop until they're empty.
+         *
+         * We do this in an outer loop, because calling decStrong()
+         * may result in something being added to mPendingWeakDerefs,
+         * which could be delayed until the next incoming command
+         * from the driver if we don't process it now.
+         */
+        while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) {
+            while (mPendingWeakDerefs.size() > 0) {
+                RefBase::weakref_type* refs = mPendingWeakDerefs[0];
+                mPendingWeakDerefs.removeAt(0);
                 refs->decWeak(mProcess.get());
             }
-            mPendingWeakDerefs.clear();
-        }
 
-        numPending = mPendingStrongDerefs.size();
-        if (numPending > 0) {
-            for (size_t i = 0; i < numPending; i++) {
-                BBinder* obj = mPendingStrongDerefs[i];
+            if (mPendingStrongDerefs.size() > 0) {
+                // We don't use while() here because we don't want to re-order
+                // strong and weak decs at all; if this decStrong() causes both a
+                // decWeak() and a decStrong() to be queued, we want to process
+                // the decWeak() first.
+                BBinder* obj = mPendingStrongDerefs[0];
+                mPendingStrongDerefs.removeAt(0);
                 obj->decStrong(mProcess.get());
             }
-            mPendingStrongDerefs.clear();
         }
     }
 }
 
+void IPCThreadState::processPostWriteDerefs()
+{
+    for (size_t i = 0; i < mPostWriteWeakDerefs.size(); i++) {
+        RefBase::weakref_type* refs = mPostWriteWeakDerefs[i];
+        refs->decWeak(mProcess.get());
+    }
+    mPostWriteWeakDerefs.clear();
+
+    for (size_t i = 0; i < mPostWriteStrongDerefs.size(); i++) {
+        RefBase* obj = mPostWriteStrongDerefs[i];
+        obj->decStrong(mProcess.get());
+    }
+    mPostWriteStrongDerefs.clear();
+}
+
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
@@ -560,7 +595,7 @@
                                   uint32_t code, const Parcel& data,
                                   Parcel* reply, uint32_t flags)
 {
-    status_t err = data.errorCheck();
+    status_t err;
 
     flags |= TF_ACCEPT_FDS;
 
@@ -571,11 +606,9 @@
             << indent << data << dedent << endl;
     }
 
-    if (err == NO_ERROR) {
-        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
-            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
-        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
-    }
+    LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+        (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
 
     if (err != NO_ERROR) {
         if (reply) reply->setError(err);
@@ -618,11 +651,14 @@
     return err;
 }
 
-void IPCThreadState::incStrongHandle(int32_t handle)
+void IPCThreadState::incStrongHandle(int32_t handle, BpBinder *proxy)
 {
     LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
     mOut.writeInt32(BC_ACQUIRE);
     mOut.writeInt32(handle);
+    // Create a temp reference until the driver has handled this command.
+    proxy->incStrong(mProcess.get());
+    mPostWriteStrongDerefs.push(proxy);
 }
 
 void IPCThreadState::decStrongHandle(int32_t handle)
@@ -632,11 +668,14 @@
     mOut.writeInt32(handle);
 }
 
-void IPCThreadState::incWeakHandle(int32_t handle)
+void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy)
 {
     LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
     mOut.writeInt32(BC_INCREFS);
     mOut.writeInt32(handle);
+    // Create a temp reference until the driver has handled this command.
+    proxy->getWeakRefs()->incWeak(mProcess.get());
+    mPostWriteWeakDerefs.push(proxy->getWeakRefs());
 }
 
 void IPCThreadState::decWeakHandle(int32_t handle)
@@ -675,7 +714,7 @@
 #if LOG_REFCOUNTS
     ALOGV("IPCThreadState::expungeHandle(%ld)\n", handle);
 #endif
-    self()->mProcess->expungeHandle(handle, binder);
+    self()->mProcess->expungeHandle(handle, binder); // NOLINT
 }
 
 status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
@@ -888,8 +927,10 @@
         if (bwr.write_consumed > 0) {
             if (bwr.write_consumed < mOut.dataSize())
                 mOut.remove(0, bwr.write_consumed);
-            else
+            else {
                 mOut.setDataSize(0);
+                processPostWriteDerefs();
+            }
         }
         if (bwr.read_consumed > 0) {
             mIn.setDataSize(bwr.read_consumed);
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 674bddf..89ebc6c 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -49,6 +49,19 @@
         return reply.readInt32() != 0;
     }
 
+    virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(op);
+        data.writeInt32(uid);
+        data.writeString16(packageName);
+        remote()->transact(NOTE_OP_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return 2; // MODE_ERRORED
+        return reply.readInt32();
+    }
+
     virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages)
     {
         Parcel data, reply;
@@ -78,6 +91,18 @@
         if (reply.readExceptionCode() != 0) return false;
         return reply.readInt32() != 0;
     }
+
+    virtual int getPackageUid(const String16& package, int flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(package);
+        data.writeInt32(flags);
+        remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return false;
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -99,6 +124,17 @@
             return NO_ERROR;
         } break;
 
+        case NOTE_OP_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 op = data.readString16();
+            int32_t uid = data.readInt32();
+            String16 packageName = data.readString16();
+            int32_t res = noteOp(op, uid, packageName);
+            reply->writeNoException();
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
+
         case GET_PACKAGES_FOR_UID_TRANSACTION: {
             CHECK_INTERFACE(IPermissionController, data, reply);
             int32_t uid = data.readInt32();
@@ -122,6 +158,16 @@
             return NO_ERROR;
         } break;
 
+        case GET_PACKAGE_UID_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 package = data.readString16();
+            int flags = data.readInt32();
+            const int uid = getPackageUid(package, flags);
+            reply->writeNoException();
+            reply->writeInt32(uid);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c7a0f43..4896f68 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -20,7 +20,11 @@
 
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
+#ifndef __ANDROID_VNDK__
+#include <binder/IPermissionController.h>
+#endif
 #include <binder/Parcel.h>
+#include <cutils/properties.h>
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
 #include <utils/CallStack.h>
@@ -48,6 +52,9 @@
     return gDefaultServiceManager;
 }
 
+#ifndef __ANDROID_VNDK__
+// IPermissionController is not accessible to vendors
+
 bool checkCallingPermission(const String16& permission)
 {
     return checkCallingPermission(permission, NULL, NULL);
@@ -122,6 +129,8 @@
     }
 }
 
+#endif //__ANDROID_VNDK__
+
 // ----------------------------------------------------------------------
 
 class BpServiceManager : public BpInterface<IServiceManager>
@@ -134,20 +143,36 @@
 
     virtual sp<IBinder> getService(const String16& name) const
     {
-        unsigned n;
-        for (n = 0; n < 5; n++){
-            if (n > 0) {
-                if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) {
-                    ALOGI("Waiting for vendor service %s...", String8(name).string());
-                    CallStack stack(LOG_TAG);
-                } else {
-                    ALOGI("Waiting for service %s...", String8(name).string());
-                }
-                sleep(1);
+        sp<IBinder> svc = checkService(name);
+        if (svc != NULL) return svc;
+
+        const bool isVendorService =
+            strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+        const long timeout = uptimeMillis() + 5000;
+        if (!gSystemBootCompleted && !isVendorService) {
+            // Vendor code can't access system properties
+            char bootCompleted[PROPERTY_VALUE_MAX];
+            property_get("sys.boot_completed", bootCompleted, "0");
+            gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+        }
+        // retry interval in millisecond; note that vendor services stay at 100ms
+        const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+        int n = 0;
+        while (uptimeMillis() < timeout) {
+            n++;
+            if (isVendorService) {
+                ALOGI("Waiting for vendor service %s...", String8(name).string());
+                CallStack stack(LOG_TAG);
+            } else if (n%10 == 0) {
+                ALOGI("Waiting for service %s...", String8(name).string());
             }
+            usleep(1000*sleepTime);
+
             sp<IBinder> svc = checkService(name);
             if (svc != NULL) return svc;
         }
+        ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
         return NULL;
     }
 
@@ -161,19 +186,18 @@
     }
 
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
-            bool allowIsolated)
-    {
+                                bool allowIsolated, int dumpsysPriority) {
         Parcel data, reply;
         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeStrongBinder(service);
         data.writeInt32(allowIsolated ? 1 : 0);
+        data.writeInt32(dumpsysPriority);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
         return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
-    virtual Vector<String16> listServices()
-    {
+    virtual Vector<String16> listServices(int dumpsysPriority) {
         Vector<String16> res;
         int n = 0;
 
@@ -181,6 +205,7 @@
             Parcel data, reply;
             data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
             data.writeInt32(n++);
+            data.writeInt32(dumpsysPriority);
             status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
             if (err != NO_ERROR)
                 break;
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index c793df3..23b83a6 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -39,11 +39,13 @@
     {
     }
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         Parcel data, reply;
         data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
         data.writeString16(path);
         data.writeString16(seLinuxContext);
+        data.writeString16(mode);
         remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
         reply.readExceptionCode();
         int fd = reply.readParcelFileDescriptor();
@@ -64,7 +66,8 @@
             CHECK_INTERFACE(IShellCallback, data, reply);
             String16 path(data.readString16());
             String16 seLinuxContext(data.readString16());
-            int fd = openOutputFile(path, seLinuxContext);
+            String16 mode(data.readString16());
+            int fd = openFile(path, seLinuxContext, mode);
             if (reply != NULL) {
                 reply->writeNoException();
                 if (fd >= 0) {
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
new file mode 100644
index 0000000..697e948
--- /dev/null
+++ b/libs/binder/IUidObserver.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IUidObserver.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class BpUidObserver : public BpInterface<IUidObserver>
+{
+public:
+    explicit BpUidObserver(const sp<IBinder>& impl)
+        : BpInterface<IUidObserver>(impl)
+    {
+    }
+
+    virtual void onUidGone(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidActive(uid_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidIdle(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+// ----------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+
+// ----------------------------------------------------------------------
+
+status_t BnUidObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ON_UID_GONE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidGone(uid, disabled);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_ACTIVE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            onUidActive(uid);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_IDLE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidIdle(uid, disabled);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 2a15773..1cfe02a 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -289,7 +289,15 @@
 SimpleBestFitAllocator::~SimpleBestFitAllocator()
 {
     while(!mList.isEmpty()) {
-        delete mList.remove(mList.head());
+        chunk_t* removed = mList.remove(mList.head());
+#ifdef __clang_analyzer__
+        // Clang static analyzer gets confused in this loop
+        // and generates a false positive warning about accessing
+        // memory that is already freed.
+        // Add an "assert" to avoid the confusion.
+        LOG_ALWAYS_FATAL_IF(mList.head() == removed);
+#endif
+        delete removed;
     }
 }
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 460bbe2..2e7edd7 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -104,7 +104,7 @@
 void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
 {
-    switch (obj.type) {
+    switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
                 LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
@@ -140,7 +140,7 @@
         }
     }
 
-    ALOGD("Invalid object type 0x%08x", obj.type);
+    ALOGD("Invalid object type 0x%08x", obj.hdr.type);
 }
 
 void acquire_object(const sp<ProcessState>& proc,
@@ -152,7 +152,7 @@
 static void release_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
 {
-    switch (obj.type) {
+    switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
                 LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
@@ -191,7 +191,7 @@
         }
     }
 
-    ALOGE("Invalid object type 0x%08x", obj.type);
+    ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
 
 void release_object(const sp<ProcessState>& proc,
@@ -227,17 +227,17 @@
                 ALOGE("null proxy");
             }
             const int32_t handle = proxy ? proxy->handle() : 0;
-            obj.type = BINDER_TYPE_HANDLE;
+            obj.hdr.type = BINDER_TYPE_HANDLE;
             obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
             obj.handle = handle;
             obj.cookie = 0;
         } else {
-            obj.type = BINDER_TYPE_BINDER;
+            obj.hdr.type = BINDER_TYPE_BINDER;
             obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
             obj.cookie = reinterpret_cast<uintptr_t>(local);
         }
     } else {
-        obj.type = BINDER_TYPE_BINDER;
+        obj.hdr.type = BINDER_TYPE_BINDER;
         obj.binder = 0;
         obj.cookie = 0;
     }
@@ -261,12 +261,12 @@
                     ALOGE("null proxy");
                 }
                 const int32_t handle = proxy ? proxy->handle() : 0;
-                obj.type = BINDER_TYPE_WEAK_HANDLE;
+                obj.hdr.type = BINDER_TYPE_WEAK_HANDLE;
                 obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
                 obj.handle = handle;
                 obj.cookie = 0;
             } else {
-                obj.type = BINDER_TYPE_WEAK_BINDER;
+                obj.hdr.type = BINDER_TYPE_WEAK_BINDER;
                 obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs());
                 obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get());
             }
@@ -281,13 +281,13 @@
         // but we can't do that with the different reference counting
         // implementation we are using.
         ALOGE("Unable to unflatten Binder weak reference!");
-        obj.type = BINDER_TYPE_BINDER;
+        obj.hdr.type = BINDER_TYPE_BINDER;
         obj.binder = 0;
         obj.cookie = 0;
         return finish_flatten_binder(NULL, obj, out);
 
     } else {
-        obj.type = BINDER_TYPE_BINDER;
+        obj.hdr.type = BINDER_TYPE_BINDER;
         obj.binder = 0;
         obj.cookie = 0;
         return finish_flatten_binder(NULL, obj, out);
@@ -307,7 +307,7 @@
     const flat_binder_object* flat = in.readObject(false);
 
     if (flat) {
-        switch (flat->type) {
+        switch (flat->hdr.type) {
             case BINDER_TYPE_BINDER:
                 *out = reinterpret_cast<IBinder*>(flat->cookie);
                 return finish_unflatten_binder(NULL, *flat, in);
@@ -326,7 +326,7 @@
     const flat_binder_object* flat = in.readObject(false);
 
     if (flat) {
-        switch (flat->type) {
+        switch (flat->hdr.type) {
             case BINDER_TYPE_BINDER:
                 *out = reinterpret_cast<IBinder*>(flat->cookie);
                 return finish_unflatten_binder(NULL, *flat, in);
@@ -544,7 +544,7 @@
                 = reinterpret_cast<flat_binder_object*>(mData + off);
             acquire_object(proc, *flat, this, &mOpenAshmemSize);
 
-            if (flat->type == BINDER_TYPE_FD) {
+            if (flat->hdr.type == BINDER_TYPE_FD) {
                 // If this is a file descriptor, we need to dup it so the
                 // new Parcel now owns its own fd, and can declare that we
                 // officially know we have fds.
@@ -1153,7 +1153,7 @@
 status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
 {
     flat_binder_object obj;
-    obj.type = BINDER_TYPE_FD;
+    obj.hdr.type = BINDER_TYPE_FD;
     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
     obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
     obj.handle = fd;
@@ -1311,7 +1311,7 @@
         *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
 
         // remember if it's a file descriptor
-        if (val.type == BINDER_TYPE_FD) {
+        if (val.hdr.type == BINDER_TYPE_FD) {
             if (!mAllowFds) {
                 // fail before modifying our object index
                 return FDS_NOT_ALLOWED;
@@ -2214,7 +2214,7 @@
 {
     const flat_binder_object* flat = readObject(true);
 
-    if (flat && flat->type == BINDER_TYPE_FD) {
+    if (flat && flat->hdr.type == BINDER_TYPE_FD) {
         return flat->handle;
     }
 
@@ -2407,7 +2407,7 @@
         i--;
         const flat_binder_object* flat
             = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
-        if (flat->type == BINDER_TYPE_FD) {
+        if (flat->hdr.type == BINDER_TYPE_FD) {
             //ALOGI("Closing fd: %ld", flat->handle);
             close(flat->handle);
         }
@@ -2480,7 +2480,7 @@
             const flat_binder_object* flat
                 = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
             to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
-                << TypeCode(flat->type & 0x7f7f7f00)
+                << TypeCode(flat->hdr.type & 0x7f7f7f00)
                 << " = " << flat->binder;
         }
     } else {
@@ -2703,7 +2703,7 @@
             for (size_t i=objectsSize; i<mObjectsSize; i++) {
                 const flat_binder_object* flat
                     = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
-                if (flat->type == BINDER_TYPE_FD) {
+                if (flat->hdr.type == BINDER_TYPE_FD) {
                     // will need to rescan because we may have lopped off the only FDs
                     mFdsKnown = false;
                 }
@@ -2731,7 +2731,7 @@
                 pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
                 mData = data;
                 mDataCapacity = desired;
-            } else if (desired > mDataCapacity) {
+            } else {
                 mError = NO_MEMORY;
                 return NO_MEMORY;
             }
@@ -2815,7 +2815,7 @@
     for (size_t i=0; i<mObjectsSize; i++) {
         const flat_binder_object* flat
             = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
-        if (flat->type == BINDER_TYPE_FD) {
+        if (flat->hdr.type == BINDER_TYPE_FD) {
             hasFds = true;
             break;
         }
diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp
new file mode 100644
index 0000000..96df33c
--- /dev/null
+++ b/libs/binder/PermissionController.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <mutex>
+#include <binder/PermissionController.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+PermissionController::PermissionController()
+{
+}
+
+sp<IPermissionController> PermissionController::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<IPermissionController> service = mService;
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("permission"));
+        if (binder == nullptr) {
+            // Wait for the activity service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for permission service");
+            } else if ((uptimeMillis() - startTime) > 10000) {
+                ALOGW("Waiting too long for permission service, giving up");
+                service = NULL;
+                break;
+            }
+            sleep(1);
+        } else {
+            service = interface_cast<IPermissionController>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid)
+{
+    sp<IPermissionController> service = getService();
+    return service != NULL ? service->checkPermission(permission, pid, uid) : false;
+}
+
+int32_t PermissionController::noteOp(const String16& op, int32_t uid, const String16& packageName)
+{
+    sp<IPermissionController> service = getService();
+    return service != NULL ? service->noteOp(op, uid, packageName) : MODE_ERRORED;
+}
+
+void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages)
+{
+    sp<IPermissionController> service = getService();
+    if (service != nullptr) {
+        service->getPackagesForUid(uid, packages);
+    }
+}
+
+bool PermissionController::isRuntimePermission(const String16& permission)
+{
+    sp<IPermissionController> service = getService();
+    return service != nullptr ? service->isRuntimePermission(permission) : false;
+}
+
+int PermissionController::getPackageUid(const String16& package, int flags)
+{
+    sp<IPermissionController> service = getService();
+    return service != nullptr ? service->getPackageUid(package, flags) : -1;
+}
+
+}; // namespace android
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index d617b5a..c0aec0a 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -39,8 +39,9 @@
 using namespace ::android::binder;
 
 enum {
-    // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java.
+    // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java.
     BUNDLE_MAGIC = 0x4C444E42,
+    BUNDLE_MAGIC_NATIVE = 0x4C444E44,
 };
 
 namespace {
@@ -99,7 +100,7 @@
 
     size_t length_pos = parcel->dataPosition();
     RETURN_IF_FAILED(parcel->writeInt32(1));  // dummy, will hold length
-    RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC));
+    RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC_NATIVE));
 
     size_t start_pos = parcel->dataPosition();
     RETURN_IF_FAILED(writeToParcelInner(parcel));
@@ -392,7 +393,7 @@
 
     int32_t magic;
     RETURN_IF_FAILED(parcel->readInt32(&magic));
-    if (magic != BUNDLE_MAGIC) {
+    if (magic != BUNDLE_MAGIC && magic != BUNDLE_MAGIC_NATIVE) {
         ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic);
         return BAD_VALUE;
     }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 11dd525..d1c6f84 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,12 +18,12 @@
 
 #include <binder/ProcessState.h>
 
-#include <utils/Atomic.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/atomic.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
-#include <binder/IServiceManager.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
@@ -86,6 +86,12 @@
         }
         LOG_ALWAYS_FATAL("ProcessState was already initialized.");
     }
+
+    if (access(driver, R_OK) == -1) {
+        ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
+        driver = "/dev/binder";
+    }
+
     gProcess = new ProcessState(driver);
     return gProcess;
 }
@@ -276,7 +282,7 @@
                    return NULL;
             }
 
-            b = new BpBinder(handle); 
+            b = BpBinder::create(handle);
             e->binder = b;
             if (b) e->refs = b->getWeakRefs();
             result = b;
@@ -310,7 +316,7 @@
         // arriving from the driver.
         IBinder* b = e->binder;
         if (b == NULL || !e->refs->attemptIncWeak(this)) {
-            b = new BpBinder(handle);
+            b = BpBinder::create(handle);
             result = b;
             e->binder = b;
             if (b) e->refs = b->getWeakRefs();
@@ -420,7 +426,7 @@
         mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
         if (mVMStart == MAP_FAILED) {
             // *sigh*
-            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
             close(mDriverFD);
             mDriverFD = -1;
             mDriverName.clear();
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index f0613d1..d6d0340 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -72,7 +72,7 @@
 
 // ------------ ProcessState.cpp
 
-Mutex gProcessMutex;
+Mutex& gProcessMutex = *new Mutex;
 sp<ProcessState> gProcess;
 
 class LibBinderIPCtStatics
@@ -94,6 +94,9 @@
 
 Mutex gDefaultServiceManagerLock;
 sp<IServiceManager> gDefaultServiceManager;
+#ifndef __ANDROID_VNDK__
 sp<IPermissionController> gPermissionController;
+#endif
+bool gSystemBootCompleted = false;
 
 }   // namespace android
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 006f7f9..a9d5055 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -102,6 +102,15 @@
     }
     mMessage = String8(message);
 
+    // Skip over the remote stack trace data
+    int32_t remote_stack_trace_header_size;
+    status = parcel.readInt32(&remote_stack_trace_header_size);
+    if (status != OK) {
+        setFromStatusT(status);
+        return status;
+    }
+    parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
+
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel.readInt32(&mErrorCode);
     } else if (mException == EX_PARCELABLE) {
@@ -137,6 +146,7 @@
         return status;
     }
     status = parcel->writeString16(String16(mMessage));
+    status = parcel->writeInt32(0); // Empty remote stack trace header
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel->writeInt32(mErrorCode);
     } else if (mException == EX_PARCELABLE) {
diff --git a/libs/binder/Value.cpp b/libs/binder/Value.cpp
index fd1dfd5..85cd739 100644
--- a/libs/binder/Value.cpp
+++ b/libs/binder/Value.cpp
@@ -182,10 +182,12 @@
 
 Value& Value::operator=(const Value& rhs)
 {
-    delete mContent;
-    mContent = rhs.mContent
-        ? rhs.mContent->clone()
-        : NULL;
+    if (this != &rhs) {
+        delete mContent;
+        mContent = rhs.mContent
+            ? rhs.mContent->clone()
+            : NULL;
+    }
     return *this;
 }
 
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 3264666..5b66b92 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -52,6 +52,6 @@
      * Unknown or unknowable versions are returned as 0.
      */
 
-    int getVersionCodeForPackage(in String packageName);
+    long getVersionCodeForPackage(in String packageName);
 
 }
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
new file mode 100644
index 0000000..b8db091
--- /dev/null
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_ACTIVITY_MANAGER_H
+#define ANDROID_ACTIVITY_MANAGER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IActivityManager.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class ActivityManager
+{
+public:
+
+    enum {
+        // Flag for registerUidObserver: report uid gone
+        UID_OBSERVER_GONE = 1<<1,
+        // Flag for registerUidObserver: report uid has become idle
+        UID_OBSERVER_IDLE = 1<<2,
+        // Flag for registerUidObserver: report uid has become active
+        UID_OBSERVER_ACTIVE = 1<<3
+    };
+
+    enum {
+        // Not a real process state
+        PROCESS_STATE_UNKNOWN = -1
+    };
+
+    ActivityManager();
+
+    int openContentUri(const String16& stringUri);
+    void registerUidObserver(const sp<IUidObserver>& observer,
+                             const int32_t event,
+                             const int32_t cutpoint,
+                             const String16& callingPackage);
+    void unregisterUidObserver(const sp<IUidObserver>& observer);
+    bool isUidActive(const uid_t uid, const String16& callingPackage);
+
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
+private:
+    Mutex mLock;
+    sp<IActivityManager> mService;
+    sp<IActivityManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_ACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 4212776..c5b57c7 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_APP_OPS_MANAGER_H
 #define ANDROID_APP_OPS_MANAGER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IAppOpsService.h>
 
 #include <utils/threads.h>
@@ -99,7 +101,8 @@
 
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+            bool startIfModeDefault);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
@@ -116,4 +119,8 @@
 
 }; // namespace android
 // ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index ef703bd..9230e89 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -34,15 +34,17 @@
 class BinderService
 {
 public:
-    static status_t publish(bool allowIsolated = false) {
+    static status_t publish(bool allowIsolated = false,
+                            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
         sp<IServiceManager> sm(defaultServiceManager());
-        return sm->addService(
-                String16(SERVICE::getServiceName()),
-                new SERVICE(), allowIsolated);
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
+                              dumpFlags);
     }
 
-    static void publishAndJoinThreadPool(bool allowIsolated = false) {
-        publish(allowIsolated);
+    static void publishAndJoinThreadPool(
+            bool allowIsolated = false,
+            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
+        publish(allowIsolated, dumpFlags);
         joinThreadPool();
     }
 
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 7ef93aa..8bd297b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -19,15 +19,20 @@
 
 #include <binder/IBinder.h>
 #include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
 #include <utils/threads.h>
 
+#include <unordered_map>
+
 // ---------------------------------------------------------------------------
 namespace android {
 
+using binder_proxy_limit_callback = void(*)(int);
+
 class BpBinder : public IBinder
 {
 public:
-                        BpBinder(int32_t handle);
+    static BpBinder*    create(int32_t handle);
 
     inline  int32_t     handle() const { return mHandle; }
 
@@ -61,6 +66,14 @@
             status_t    setConstantData(const void* data, size_t size);
             void        sendObituary();
 
+    static uint32_t     getBinderProxyCount(uint32_t uid);
+    static void         getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts);
+    static void         enableCountByUid();
+    static void         disableCountByUid();
+    static void         setCountByUidEnabled(bool enable);
+    static void         setLimitCallback(binder_proxy_limit_callback cb);
+    static void         setBinderProxyCountWatermarks(int high, int low);
+
     class ObjectManager
     {
     public:
@@ -91,6 +104,7 @@
     };
 
 protected:
+                        BpBinder(int32_t handle,int32_t trackedUid);
     virtual             ~BpBinder();
     virtual void        onFirstRef();
     virtual void        onLastStrongRef(const void* id);
@@ -115,6 +129,16 @@
             ObjectManager       mObjects;
             Parcel*             mConstantData;
     mutable String16            mDescriptorCache;
+            int32_t             mTrackedUid;
+
+    static Mutex                                sTrackingLock;
+    static std::unordered_map<int32_t,uint32_t> sTrackingMap;
+    static int                                  sNumTrackedUids;
+    static std::atomic_bool                     sCountByUidEnabled;
+    static binder_proxy_limit_callback          sLimitCallback;
+    static uint32_t                             sBinderProxyCountHighWatermark;
+    static uint32_t                             sBinderProxyCountLowWatermark;
+    static bool                                 sBinderProxyThrottleCreate;
 };
 
 }; // namespace android
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index 5ad2180..f34969b 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -17,7 +17,10 @@
 #ifndef ANDROID_IACTIVITY_MANAGER_H
 #define ANDROID_IACTIVITY_MANAGER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
+#include <binder/IUidObserver.h>
 
 namespace android {
 
@@ -28,10 +31,19 @@
 public:
     DECLARE_META_INTERFACE(ActivityManager)
 
-    virtual int openContentUri(const String16& /* stringUri */) = 0;
+    virtual int openContentUri(const String16& stringUri) = 0;
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage) = 0;
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
 
     enum {
-        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        REGISTER_UID_OBSERVER_TRANSACTION,
+        UNREGISTER_UID_OBSERVER_TRANSACTION,
+        IS_UID_ACTIVE_TRANSACTION
     };
 };
 
@@ -39,4 +51,8 @@
 
 }; // namespace android
 
-#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_IACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index b62e9e2..e5b12a9 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IAPP_OPS_CALLBACK_H
 #define ANDROID_IAPP_OPS_CALLBACK_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -51,5 +53,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IAPP_OPS_CALLBACK_H
 
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index dc18045..f0c5e17 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IAPP_OPS_SERVICE_H
 #define ANDROID_IAPP_OPS_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IAppOpsCallback.h>
 #include <binder/IInterface.h>
 
@@ -33,7 +35,7 @@
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
+            const String16& packageName, bool startIfModeDefault) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
             const String16& packageName) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
@@ -75,4 +77,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index e15d6f0..59e806c 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_IBATTERYSTATS_H
 #define ANDROID_IBATTERYSTATS_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -76,4 +78,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IBATTERYSTATS_H
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
index b21047f..213ee63 100644
--- a/libs/binder/include/binder/IMediaResourceMonitor.h
+++ b/libs/binder/include/binder/IMediaResourceMonitor.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H
 #define ANDROID_I_MEDIA_RESOURCE_MONITOR_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -52,4 +54,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 245607e..c1d9a9a 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -64,9 +64,9 @@
                                          uint32_t code, const Parcel& data,
                                          Parcel* reply, uint32_t flags);
 
-            void                incStrongHandle(int32_t handle);
+            void                incStrongHandle(int32_t handle, BpBinder *proxy);
             void                decStrongHandle(int32_t handle);
-            void                incWeakHandle(int32_t handle);
+            void                incWeakHandle(int32_t handle, BpBinder *proxy);
             void                decWeakHandle(int32_t handle);
             status_t            attemptIncStrongHandle(int32_t handle);
     static  void                expungeHandle(int32_t handle, IBinder* binder);
@@ -106,6 +106,7 @@
             status_t            getAndExecuteCommand();
             status_t            executeCommand(int32_t command);
             void                processPendingDerefs();
+            void                processPostWriteDerefs();
 
             void                clearCaller();
 
@@ -118,7 +119,8 @@
     const   sp<ProcessState>    mProcess;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+            Vector<RefBase*>    mPostWriteStrongDerefs;
+            Vector<RefBase::weakref_type*> mPostWriteWeakDerefs;
             Parcel              mIn;
             Parcel              mOut;
             status_t            mLastError;
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 25f3431..3ec459f 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IPERMISSION_CONTROLLER_H
 #define ANDROID_IPERMISSION_CONTROLLER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 #include <stdlib.h>
 
@@ -32,14 +34,20 @@
 
     virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
 
+    virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) = 0;
+
     virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
 
     virtual bool isRuntimePermission(const String16& permission) = 0;
 
+    virtual int getPackageUid(const String16& package, int flags) = 0;
+
     enum {
         CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
-        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
+        NOTE_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
+        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2,
+        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3,
+        GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4
     };
 };
 
@@ -58,5 +66,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IPERMISSION_CONTROLLER_H
 
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h
index 2669f91..033c145 100644
--- a/libs/binder/include/binder/IProcessInfoService.h
+++ b/libs/binder/include/binder/IProcessInfoService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
 #define ANDROID_I_PROCESS_INFO_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -46,4 +48,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3b23f81..197026d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -19,7 +19,6 @@
 #define ANDROID_ISERVICE_MANAGER_H
 
 #include <binder/IInterface.h>
-#include <binder/IPermissionController.h>
 #include <utils/Vector.h>
 #include <utils/String16.h>
 
@@ -31,6 +30,22 @@
 {
 public:
     DECLARE_META_INTERFACE(ServiceManager)
+    /**
+     * Must match values in IServiceManager.java
+     */
+    /* Allows services to dump sections according to priorities. */
+    static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+    static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+    static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
+    /**
+     * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
+     * same priority as NORMAL priority but the services are not called with dump priority
+     * arguments.
+     */
+    static const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
+    static const int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL |
+            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+    static const int DUMP_FLAG_PROTO = 1 << 4;
 
     /**
      * Retrieve an existing service, blocking for a few seconds
@@ -46,14 +61,14 @@
     /**
      * Register a service.
      */
-    virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service,
-                                            bool allowIsolated = false) = 0;
+    virtual status_t addService(const String16& name, const sp<IBinder>& service,
+                                bool allowIsolated = false,
+                                int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
 
     /**
      * Return list of all existing services.
      */
-    virtual Vector<String16>    listServices() = 0;
+    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
 
     enum {
         GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index fda9ee6..b47e995 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -29,7 +29,8 @@
 public:
     DECLARE_META_INTERFACE(ShellCallback);
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) = 0;
 
     enum {
         OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
new file mode 100644
index 0000000..d81789e
--- /dev/null
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_IUID_OBSERVER_H
+#define ANDROID_IUID_OBSERVER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IUidObserver : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(UidObserver)
+
+    virtual void onUidGone(uid_t uid, bool disabled) = 0;
+    virtual void onUidActive(uid_t uid) = 0;
+    virtual void onUidIdle(uid_t uid, bool disabled) = 0;
+
+    enum {
+        ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        ON_UID_ACTIVE_TRANSACTION,
+        ON_UID_IDLE_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnUidObserver : public BnInterface<IUidObserver>
+{
+public:
+    virtual status_t  onTransact(uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_IUID_OBSERVER_H
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
index 96ebaac..dd5bc3a 100644
--- a/libs/binder/include/binder/IpPrefix.h
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_IP_PREFIX_H
 #define ANDROID_IP_PREFIX_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <netinet/in.h>
 
 #include <binder/Parcelable.h>
@@ -85,4 +87,8 @@
 
 }  // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif  // ANDROID_IP_PREFIX_H
diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
index bcdf0c2..95eabff 100644
--- a/libs/binder/include/binder/PermissionCache.h
+++ b/libs/binder/include/binder/PermissionCache.h
@@ -17,6 +17,8 @@
 #ifndef BINDER_PERMISSION_H
 #define BINDER_PERMISSION_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <stdint.h>
 #include <unistd.h>
 
@@ -77,4 +79,8 @@
 // ---------------------------------------------------------------------------
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif /* BINDER_PERMISSION_H */
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
new file mode 100644
index 0000000..d81f514
--- /dev/null
+++ b/libs/binder/include/binder/PermissionController.h
@@ -0,0 +1,69 @@
+/*
+ * 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 ANDROID_PERMISSION_CONTROLLER_H
+#define ANDROID_PERMISSION_CONTROLLER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IPermissionController.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class PermissionController
+{
+public:
+
+    enum {
+        MATCH_SYSTEM_ONLY = 1<<16,
+        MATCH_UNINSTALLED_PACKAGES = 1<<13,
+        MATCH_FACTORY_ONLY = 1<<21,
+        MATCH_INSTANT = 1<<23
+    };
+
+    enum {
+        MODE_ALLOWED = 0,
+        MODE_IGNORED = 1,
+        MODE_ERRORED = 2,
+        MODE_DEFAULT = 3,
+    };
+
+    PermissionController();
+
+    bool checkPermission(const String16& permission, int32_t pid, int32_t uid);
+    int32_t noteOp(const String16& op, int32_t uid, const String16& packageName);
+    void getPackagesForUid(const uid_t uid, Vector<String16>& packages);
+    bool isRuntimePermission(const String16& permission);
+    int getPackageUid(const String16& package, int flags);
+
+private:
+    Mutex mLock;
+    sp<IPermissionController> mService;
+
+    sp<IPermissionController> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_PERMISSION_CONTROLLER_H
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h
index 0da61ee..a03aae9 100644
--- a/libs/binder/include/binder/ProcessInfoService.h
+++ b/libs/binder/include/binder/ProcessInfoService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_PROCESS_INFO_SERVICE_H
 #define ANDROID_PROCESS_INFO_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IProcessInfoService.h>
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
@@ -78,5 +80,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_PROCESS_INFO_SERVICE_H
 
diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h
index 3d10456..171be77 100644
--- a/libs/binder/include/private/binder/Static.h
+++ b/libs/binder/include/private/binder/Static.h
@@ -21,7 +21,9 @@
 
 #include <binder/IBinder.h>
 #include <binder/ProcessState.h>
+#ifndef __ANDROID_VNDK__
 #include <binder/IPermissionController.h>
+#endif
 #include <binder/IServiceManager.h>
 
 namespace android {
@@ -30,12 +32,15 @@
 extern Vector<int32_t> gTextBuffers;
 
 // For ProcessState.cpp
-extern Mutex gProcessMutex;
+extern Mutex& gProcessMutex;
 extern sp<ProcessState> gProcess;
 
 // For IServiceManager.cpp
 extern Mutex gDefaultServiceManagerLock;
 extern sp<IServiceManager> gDefaultServiceManager;
+#ifndef __ANDROID_VNDK__
 extern sp<IPermissionController> gPermissionController;
+#endif
+extern bool gSystemBootCompleted;
 
 }   // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 3071408..c451780 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -14,9 +14,20 @@
 // limitations under the License.
 //
 
+cc_defaults {
+    name: "binder_test_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-private-field",
+        "-Wno-unused-variable",
+    ],
+}
+
 cc_test {
     name: "binderDriverInterfaceTest_IPC_32",
     srcs: ["binderDriverInterfaceTest.cpp"],
+    defaults: ["binder_test_defaults"],
     compile_multilib: "32",
     cflags: ["-DBINDER_IPC_32BIT=1"],
 }
@@ -30,11 +41,13 @@
 
     name: "binderDriverInterfaceTest",
     srcs: ["binderDriverInterfaceTest.cpp"],
+    defaults: ["binder_test_defaults"],
 }
 
 cc_test {
     name: "binderValueTypeTest",
     srcs: ["binderValueTypeTest.cpp"],
+    defaults: ["binder_test_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -44,6 +57,7 @@
 cc_test {
     name: "binderLibTest_IPC_32",
     srcs: ["binderLibTest.cpp"],
+    defaults: ["binder_test_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -59,6 +73,7 @@
         },
     },
 
+    defaults: ["binder_test_defaults"],
     name: "binderLibTest",
     srcs: ["binderLibTest.cpp"],
     shared_libs: [
@@ -70,6 +85,7 @@
 cc_test {
     name: "binderThroughputTest",
     srcs: ["binderThroughputTest.cpp"],
+    defaults: ["binder_test_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -77,8 +93,6 @@
     clang: true,
     cflags: [
         "-g",
-        "-Wall",
-        "-Werror",
         "-Wno-missing-field-initializers",
         "-Wno-sign-compare",
         "-O3",
@@ -88,6 +102,7 @@
 cc_test {
     name: "binderTextOutputTest",
     srcs: ["binderTextOutputTest.cpp"],
+    defaults: ["binder_test_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -98,6 +113,7 @@
 cc_test {
     name: "schd-dbg",
     srcs: ["schd-dbg.cpp"],
+    defaults: ["binder_test_defaults"],
     shared_libs: [
         "libbinder",
         "libutils",
@@ -108,9 +124,9 @@
 cc_test {
     name: "binderSafeInterfaceTest",
     srcs: ["binderSafeInterfaceTest.cpp"],
+    defaults: ["binder_test_defaults"],
 
     cppflags: [
-        "-Werror",
         "-Weverything",
         "-Wno-c++98-compat",
         "-Wno-c++98-compat-pedantic",
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 9b289c0..4f00bc1 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -149,6 +149,12 @@
     ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version);
 }
 
+TEST_F(BinderDriverInterfaceTest, OpenNoMmap) {
+    int binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+    ASSERT_GE(binderFd, 0);
+    close(binderFd);
+}
+
 TEST_F(BinderDriverInterfaceTest, WriteReadNull) {
     binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT);
 }
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index a04869a..1611e11 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -28,10 +28,19 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include <sys/epoll.h>
+
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
 
 using namespace android;
 
+static ::testing::AssertionResult IsPageAligned(void *buf) {
+    if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0)
+        return ::testing::AssertionSuccess();
+    else
+        return ::testing::AssertionFailure() << buf << " is not page aligned";
+}
+
 static testing::Environment* binder_env;
 static char *binderservername;
 static char *binderserversuffix;
@@ -43,7 +52,10 @@
     BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
     BINDER_LIB_TEST_REGISTER_SERVER,
     BINDER_LIB_TEST_ADD_SERVER,
+    BINDER_LIB_TEST_ADD_POLL_SERVER,
     BINDER_LIB_TEST_CALL_BACK,
+    BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
+    BINDER_LIB_TEST_DELAYED_CALL_BACK,
     BINDER_LIB_TEST_NOP_CALL_BACK,
     BINDER_LIB_TEST_GET_SELF_TRANSACTION,
     BINDER_LIB_TEST_GET_ID_TRANSACTION,
@@ -60,7 +72,7 @@
     BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
 };
 
-pid_t start_server_process(int arg2)
+pid_t start_server_process(int arg2, bool usePoll = false)
 {
     int ret;
     pid_t pid;
@@ -68,11 +80,13 @@
     int pipefd[2];
     char stri[16];
     char strpipefd1[16];
+    char usepoll[2];
     char *childargv[] = {
         binderservername,
         binderserverarg,
         stri,
         strpipefd1,
+        usepoll,
         binderserversuffix,
         NULL
     };
@@ -83,6 +97,7 @@
 
     snprintf(stri, sizeof(stri), "%d", arg2);
     snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]);
+    snprintf(usepoll, sizeof(usepoll), "%d", usePoll ? 1 : 0);
 
     pid = fork();
     if (pid == -1)
@@ -167,14 +182,14 @@
         virtual void TearDown() {
         }
     protected:
-        sp<IBinder> addServer(int32_t *idPtr = NULL)
+        sp<IBinder> addServerEtc(int32_t *idPtr, int code)
         {
             int ret;
             int32_t id;
             Parcel data, reply;
             sp<IBinder> binder;
 
-            ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply);
+            ret = m_server->transact(code, data, &reply);
             EXPECT_EQ(NO_ERROR, ret);
 
             EXPECT_FALSE(binder != NULL);
@@ -186,6 +201,17 @@
                 *idPtr = id;
             return binder;
         }
+
+        sp<IBinder> addServer(int32_t *idPtr = NULL)
+        {
+            return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_SERVER);
+        }
+
+        sp<IBinder> addPollServer(int32_t *idPtr = NULL)
+        {
+            return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_POLL_SERVER);
+        }
+
         void waitForReadData(int fd, int timeout_ms) {
             int ret;
             pollfd pfd = pollfd();
@@ -265,17 +291,23 @@
             pthread_mutex_unlock(&m_waitMutex);
             return ret;
         }
+        pthread_t getTriggeringThread()
+        {
+            return m_triggeringThread;
+        }
     protected:
         void triggerEvent(void) {
             pthread_mutex_lock(&m_waitMutex);
             pthread_cond_signal(&m_waitCond);
             m_eventTriggered = true;
+            m_triggeringThread = pthread_self();
             pthread_mutex_unlock(&m_waitMutex);
         };
     private:
         pthread_mutex_t m_waitMutex;
         pthread_cond_t m_waitCond;
         bool m_eventTriggered;
+        pthread_t m_triggeringThread;
 };
 
 class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent
@@ -283,6 +315,7 @@
     public:
         BinderLibTestCallBack()
             : m_result(NOT_ENOUGH_DATA)
+            , m_prev_end(NULL)
         {
         }
         status_t getResult(void)
@@ -298,16 +331,43 @@
             (void)reply;
             (void)flags;
             switch(code) {
-            case BINDER_LIB_TEST_CALL_BACK:
-                m_result = data.readInt32();
+            case BINDER_LIB_TEST_CALL_BACK: {
+                status_t status = data.readInt32(&m_result);
+                if (status != NO_ERROR) {
+                    m_result = status;
+                }
                 triggerEvent();
                 return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF: {
+                sp<IBinder> server;
+                int ret;
+                const uint8_t *buf = data.data();
+                size_t size = data.dataSize();
+                if (m_prev_end) {
+                    /* 64-bit kernel needs at most 8 bytes to align buffer end */
+                    EXPECT_LE((size_t)(buf - m_prev_end), (size_t)8);
+                } else {
+                    EXPECT_TRUE(IsPageAligned((void *)buf));
+                }
+
+                m_prev_end = buf + size + data.objectsCount() * sizeof(binder_size_t);
+
+                if (size > 0) {
+                    server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
+                    ret = server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION,
+                                           data, reply);
+                    EXPECT_EQ(NO_ERROR, ret);
+                }
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             }
         }
 
         status_t m_result;
+        const uint8_t *m_prev_end;
 };
 
 class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent
@@ -606,6 +666,65 @@
     }
 }
 
+TEST_F(BinderLibTest, DeathNotificationThread)
+{
+    status_t ret;
+    sp<BinderLibTestCallBack> callback;
+    sp<IBinder> target = addServer();
+    ASSERT_TRUE(target != NULL);
+    sp<IBinder> client = addServer();
+    ASSERT_TRUE(client != NULL);
+
+    sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
+
+    ret = target->linkToDeath(testDeathRecipient);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    {
+        Parcel data, reply;
+        ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
+        EXPECT_EQ(0, ret);
+    }
+
+    /* Make sure it's dead */
+    testDeathRecipient->waitEvent(5);
+
+    /* Now, pass the ref to another process and ask that process to
+     * call linkToDeath() on it, and wait for a response. This tests
+     * two things:
+     * 1) You still get death notifications when calling linkToDeath()
+     *    on a ref that is already dead when it was passed to you.
+     * 2) That death notifications are not directly pushed to the thread
+     *    registering them, but to the threadpool (proc workqueue) instead.
+     *
+     * 2) is tested because the thread handling BINDER_LIB_TEST_DEATH_TRANSACTION
+     * is blocked on a condition variable waiting for the death notification to be
+     * called; therefore, that thread is not available for handling proc work.
+     * So, if the death notification was pushed to the thread workqueue, the callback
+     * would never be called, and the test would timeout and fail.
+     *
+     * Note that we can't do this part of the test from this thread itself, because
+     * the binder driver would only push death notifications to the thread if
+     * it is a looper thread, which this thread is not.
+     *
+     * See b/23525545 for details.
+     */
+    {
+        Parcel data, reply;
+
+        callback = new BinderLibTestCallBack();
+        data.writeStrongBinder(target);
+        data.writeStrongBinder(callback);
+        ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
+        EXPECT_EQ(NO_ERROR, ret);
+    }
+
+    ret = callback->waitEvent(5);
+    EXPECT_EQ(NO_ERROR, ret);
+    ret = callback->getResult();
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 TEST_F(BinderLibTest, PassFile) {
     int ret;
     int pipefd[2];
@@ -681,7 +800,7 @@
 
     const flat_binder_object *fb = reply.readObject(false);
     ASSERT_TRUE(fb != NULL);
-    EXPECT_EQ(BINDER_TYPE_HANDLE, fb->type);
+    EXPECT_EQ(BINDER_TYPE_HANDLE, fb->hdr.type);
     EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle));
     EXPECT_EQ((binder_uintptr_t)0, fb->cookie);
     EXPECT_EQ((uint64_t)0, (uint64_t)fb->binder >> 32);
@@ -728,6 +847,61 @@
     }
 }
 
+TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
+    status_t ret;
+    Parcel data, reply;
+    sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+    for (int i = 0; i < 2; i++) {
+        BinderLibTestBundle datai;
+        datai.appendFrom(&data, 0, data.dataSize());
+
+        data.freeData();
+        data.writeInt32(1);
+        data.writeStrongBinder(callBack);
+        data.writeInt32(BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF);
+
+        datai.appendTo(&data);
+    }
+    ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, OnewayQueueing)
+{
+    status_t ret;
+    Parcel data, data2;
+
+    sp<IBinder> pollServer = addPollServer();
+
+    sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
+    data.writeStrongBinder(callBack);
+    data.writeInt32(500000); // delay in us before calling back
+
+    sp<BinderLibTestCallBack> callBack2 = new BinderLibTestCallBack();
+    data2.writeStrongBinder(callBack2);
+    data2.writeInt32(0); // delay in us
+
+    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, NULL, TF_ONE_WAY);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    // The delay ensures that this second transaction will end up on the async_todo list
+    // (for a single-threaded server)
+    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, NULL, TF_ONE_WAY);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    // The server will ensure that the two transactions are handled in the expected order;
+    // If the ordering is not as expected, an error will be returned through the callbacks.
+    ret = callBack->waitEvent(2);
+    EXPECT_EQ(NO_ERROR, ret);
+    ret = callBack->getResult();
+    EXPECT_EQ(NO_ERROR, ret);
+
+    ret = callBack2->waitEvent(2);
+    EXPECT_EQ(NO_ERROR, ret);
+    ret = callBack2->getResult();
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 class BinderLibTestService : public BBinder
 {
     public:
@@ -735,6 +909,7 @@
             : m_id(id)
             , m_nextServerId(id + 1)
             , m_serverStartRequested(false)
+            , m_callback(NULL)
         {
             pthread_mutex_init(&m_serverWaitMutex, NULL);
             pthread_cond_init(&m_serverWaitCond, NULL);
@@ -743,6 +918,16 @@
         {
             exit(EXIT_SUCCESS);
         }
+
+        void processPendingCall() {
+            if (m_callback != NULL) {
+                Parcel data;
+                data.writeInt32(NO_ERROR);
+                m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
+                m_callback = NULL;
+            }
+        }
+
         virtual status_t onTransact(uint32_t code,
                                     const Parcel& data, Parcel* reply,
                                     uint32_t flags = 0) {
@@ -774,6 +959,7 @@
                 pthread_mutex_unlock(&m_serverWaitMutex);
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_ADD_POLL_SERVER:
             case BINDER_LIB_TEST_ADD_SERVER: {
                 int ret;
                 uint8_t buf[1] = { 0 };
@@ -788,9 +974,10 @@
                 } else {
                     serverid = m_nextServerId++;
                     m_serverStartRequested = true;
+                    bool usePoll = code == BINDER_LIB_TEST_ADD_POLL_SERVER;
 
                     pthread_mutex_unlock(&m_serverWaitMutex);
-                    ret = start_server_process(serverid);
+                    ret = start_server_process(serverid, usePoll);
                     pthread_mutex_lock(&m_serverWaitMutex);
                 }
                 if (ret > 0) {
@@ -818,6 +1005,42 @@
             }
             case BINDER_LIB_TEST_NOP_TRANSACTION:
                 return NO_ERROR;
+            case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
+                // Note: this transaction is only designed for use with a
+                // poll() server. See comments around epoll_wait().
+                if (m_callback != NULL) {
+                    // A callback was already pending; this means that
+                    // we received a second call while still processing
+                    // the first one. Fail the test.
+                    sp<IBinder> callback = data.readStrongBinder();
+                    Parcel data2;
+                    data2.writeInt32(UNKNOWN_ERROR);
+
+                    callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, NULL, TF_ONE_WAY);
+                } else {
+                    m_callback = data.readStrongBinder();
+                    int32_t delayUs = data.readInt32();
+                    /*
+                     * It's necessary that we sleep here, so the next
+                     * transaction the caller makes will be queued to
+                     * the async queue.
+                     */
+                    usleep(delayUs);
+
+                    /*
+                     * Now when we return, libbinder will tell the kernel
+                     * we are done with this transaction, and the kernel
+                     * can move the queued transaction to either the
+                     * thread todo worklist (for kernels without the fix),
+                     * or the proc todo worklist. In case of the former,
+                     * the next outbound call will pick up the pending
+                     * transaction, which leads to undesired reentrant
+                     * behavior. This is caught in the if() branch above.
+                     */
+                }
+
+                return NO_ERROR;
+            }
             case BINDER_LIB_TEST_NOP_CALL_BACK: {
                 Parcel data2, reply2;
                 sp<IBinder> binder;
@@ -825,7 +1048,7 @@
                 if (binder == NULL) {
                     return BAD_VALUE;
                 }
-                reply2.writeInt32(NO_ERROR);
+                data2.writeInt32(NO_ERROR);
                 binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
                 return NO_ERROR;
             }
@@ -967,16 +1190,26 @@
         bool m_serverStartRequested;
         sp<IBinder> m_serverStarted;
         sp<IBinder> m_strongRef;
+        bool m_callbackPending;
+        sp<IBinder> m_callback;
 };
 
-int run_server(int index, int readypipefd)
+int run_server(int index, int readypipefd, bool usePoll)
 {
     binderLibTestServiceName += String16(binderserversuffix);
 
     status_t ret;
     sp<IServiceManager> sm = defaultServiceManager();
+    BinderLibTestService* testServicePtr;
     {
         sp<BinderLibTestService> testService = new BinderLibTestService(index);
+        /*
+         * We need this below, but can't hold a sp<> because it prevents the
+         * node from being cleaned up automatically. It's safe in this case
+         * because of how the tests are written.
+         */
+        testServicePtr = testService.get();
+
         if (index == 0) {
             ret = sm->addService(binderLibTestServiceName, testService);
         } else {
@@ -994,8 +1227,53 @@
     if (ret)
         return 1;
     //printf("%s: joinThreadPool\n", __func__);
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
+    if (usePoll) {
+        int fd;
+        struct epoll_event ev;
+        int epoll_fd;
+        IPCThreadState::self()->setupPolling(&fd);
+        if (fd < 0) {
+            return 1;
+        }
+        IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
+
+        epoll_fd = epoll_create1(0);
+        if (epoll_fd == -1) {
+            return 1;
+        }
+
+        ev.events = EPOLLIN;
+        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+            return 1;
+        }
+
+        while (1) {
+             /*
+              * We simulate a single-threaded process using the binder poll
+              * interface; besides handling binder commands, it can also
+              * issue outgoing transactions, by storing a callback in
+              * m_callback and setting m_callbackPending.
+              *
+              * processPendingCall() will then issue that transaction.
+              */
+             struct epoll_event events[1];
+             int numEvents = epoll_wait(epoll_fd, events, 1, 1000);
+             if (numEvents < 0) {
+                 if (errno == EINTR) {
+                     continue;
+                 }
+                 return 1;
+             }
+             if (numEvents > 0) {
+                 IPCThreadState::self()->handlePolledCommands();
+                 IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER
+                 testServicePtr->processPendingCall();
+             }
+        }
+    } else {
+        ProcessState::self()->startThreadPool();
+        IPCThreadState::self()->joinThreadPool();
+    }
     //printf("%s: joinThreadPool returned\n", __func__);
     return 1; /* joinThreadPool should not return */
 }
@@ -1009,9 +1287,9 @@
         binderservername = argv[0];
     }
 
-    if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
-        binderserversuffix = argv[4];
-        return run_server(atoi(argv[2]), atoi(argv[3]));
+    if (argc == 6 && !strcmp(argv[1], binderserverarg)) {
+        binderserversuffix = argv[5];
+        return run_server(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) == 1);
     }
     binderserversuffix = new char[16];
     snprintf(binderserversuffix, 16, "%d", getpid());
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 455f2c4..bf41e0b 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -215,7 +215,7 @@
         int target = cs_pair ? num % server_count : rand() % workers.size();
         int sz = payload_size;
 
-        while (sz > sizeof(uint32_t)) {
+        while (sz >= sizeof(uint32_t)) {
             data.writeInt32(0);
             sz -= sizeof(uint32_t);
         }
@@ -381,6 +381,7 @@
             // No need to run training round in this case.
             if (atoi(argv[i+1]) > 0) {
                 max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+                time_per_bucket = max_time_bucket / num_buckets;
                 i++;
             } else {
                 cout << "Max latency -m must be positive." << endl;
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
index 156ddff..a826306 100644
--- a/libs/diskusage/Android.bp
+++ b/libs/diskusage/Android.bp
@@ -15,4 +15,5 @@
 cc_library_static {
     name: "libdiskusage",
     srcs: ["dirsize.c"],
+    cflags: ["-Wall", "-Werror"],
 }
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
new file mode 100644
index 0000000..3412e14
--- /dev/null
+++ b/libs/dumputils/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+cc_library {
+    name: "libdumputils",
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: ["dump_utils.cpp"],
+
+    cflags: ["-Wall", "-Werror"],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
new file mode 100644
index 0000000..8b2f842
--- /dev/null
+++ b/libs/dumputils/dump_utils.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+#include <set>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <dumputils/dump_utils.h>
+#include <log/log.h>
+
+/* list of native processes to include in the native dumps */
+// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
+static const char* native_processes_to_dump[] = {
+        "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
+        "/system/bin/mediaextractor", // media.extractor
+        "/system/bin/mediametrics", // media.metrics
+        "/system/bin/mediaserver",
+        "/system/bin/sdcard",
+        "/system/bin/statsd",
+        "/system/bin/surfaceflinger",
+        "/system/bin/vehicle_network_service",
+        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
+        NULL,
+};
+
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.audio@4.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.drm@1.0::IDrmFactory",
+        "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.media.omx@1.0::IOmx",
+        "android.hardware.media.omx@1.0::IOmxStore",
+        "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.vr@1.0::IVr",
+        NULL,
+};
+
+bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool should_dump_native_traces(const char* path) {
+    for (const char** p = native_processes_to_dump; *p; p++) {
+        if (!strcmp(*p, path)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
+bool IsZygote(int pid) {
+    static const std::string kZygotePrefix = "zygote";
+
+    std::string cmdline;
+    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+                                         &cmdline)) {
+        return true;
+    }
+
+    return (cmdline.find(kZygotePrefix) == 0);
+}
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/libs/dumputils/include/dumputils/dump_utils.h
similarity index 61%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to libs/dumputils/include/dumputils/dump_utils.h
index 0eda0af..25f7127 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -1,11 +1,11 @@
-/*
- * Copyright 2015 The Android Open Source Project
+/**
+ * Copyright (c) 2016, 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
+ *     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,
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#ifndef DUMPUTILS_H_
+#define DUMPUTILS_H_
 
-using namespace vulkan;
+#include <set>
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+bool should_dump_native_traces(const char* path);
+
+std::set<int> get_interesting_hal_pids();
+
+bool IsZygote(int pid);
+
+#endif  // DUMPUTILS_H_
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index f2686d5..4da30e9 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -19,8 +19,9 @@
         "GraphicsEnv.cpp",
     ],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: [
-        "libnativeloader",
         "liblog",
     ],
 
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 39b5829..961f101 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -20,12 +20,23 @@
 
 #include <mutex>
 
+#include <android/dlext.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
 
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+     ANDROID_NAMESPACE_TYPE_SHARED = 2,
+  };
 }
 
 namespace android {
@@ -45,6 +56,32 @@
     mDriverPath = path;
 }
 
+void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) {
+    if (mLayerPaths.empty()) {
+        mLayerPaths = layerPaths;
+        mAppNamespace = appNamespace;
+    } else {
+        ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
+                layerPaths.c_str(), appNamespace);
+    }
+}
+
+android_namespace_t* GraphicsEnv::getAppNamespace() {
+    return mAppNamespace;
+}
+
+const std::string GraphicsEnv::getLayerPaths(){
+    return mLayerPaths;
+}
+
+const std::string GraphicsEnv::getDebugLayers() {
+    return mDebugLayers;
+}
+
+void GraphicsEnv::setDebugLayers(const std::string layers) {
+    mDebugLayers = layers;
+}
+
 android_namespace_t* GraphicsEnv::getDriverNamespace() {
     static std::once_flag once;
     std::call_once(once, [this]() {
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 7817076..213580c 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -35,10 +35,20 @@
     void setDriverPath(const std::string path);
     android_namespace_t* getDriverNamespace();
 
+    void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths);
+    android_namespace_t* getAppNamespace();
+    const std::string getLayerPaths();
+
+    void setDebugLayers(const std::string layers);
+    const std::string getDebugLayers();
+
 private:
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mDebugLayers;
+    std::string mLayerPaths;
     android_namespace_t* mDriverNamespace = nullptr;
+    android_namespace_t* mAppNamespace = nullptr;
 };
 
 } // namespace android
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3996305..73f2147 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -19,15 +19,18 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: true,
+    vendor_available: false,
     vndk: {
         enabled: true,
     },
 
     clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     cppflags: [
         "-Weverything",
-        "-Werror",
 
         // The static constructors and destructors in this library have not been noted to
         // introduce significant overheads
@@ -59,6 +62,12 @@
         // Allow documentation warnings
         "-Wno-documentation",
 
+        // Allow implicit instantiation for templated class function
+        "-Wno-undefined-func-template",
+
+        // Allow explicitly marking struct as packed even when unnecessary
+        "-Wno-packed",
+
         "-DDEBUG_ONLY_CODE=0",
     ],
 
@@ -76,6 +85,8 @@
 
     srcs: [
         "BitTube.cpp",
+        "BufferHubConsumer.cpp",
+        "BufferHubProducer.cpp",
         "BufferItem.cpp",
         "BufferItemConsumer.cpp",
         "BufferQueue.cpp",
@@ -89,6 +100,7 @@
         "FrameTimestamps.cpp",
         "GLConsumer.cpp",
         "GuiConfig.cpp",
+        "HdrMetadata.cpp",
         "IDisplayEventConnection.cpp",
         "IConsumerListener.cpp",
         "IGraphicBufferConsumer.cpp",
@@ -96,6 +108,7 @@
         "IProducerListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
+        "LayerDebugInfo.cpp",
         "LayerState.cpp",
         "OccupancyTracker.cpp",
         "StreamSplitter.cpp",
@@ -109,8 +122,11 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.common@1.1",
         "libsync",
         "libbinder",
+        "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+        "libpdx_default_transport",
         "libcutils",
         "libEGL",
         "libGLESv2",
@@ -126,9 +142,26 @@
         "android.hardware.configstore-utils",
     ],
 
+    // bufferhub is not used when building libgui for vendors
+    target: {
+        vendor: {
+            cflags: ["-DNO_BUFFERHUB"],
+            exclude_srcs: [
+                "BufferHubConsumer.cpp",
+                "BufferHubProducer.cpp",
+            ],
+            exclude_shared_libs: [
+                "libbufferhubqueue",
+                "libpdx_default_transport",
+            ],
+        },
+    },
+
     header_libs: [
+        "libdvr_headers",
         "libnativebase_headers",
         "libgui_headers",
+        "libpdx_headers",
     ],
 
     export_shared_lib_headers: [
@@ -138,6 +171,7 @@
         "libui",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.common@1.1",
     ],
 
     export_header_lib_headers: [
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
new file mode 100644
index 0000000..b5cdeb2
--- /dev/null
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferHubConsumer.h>
+
+namespace android {
+
+using namespace dvr;
+
+/* static */
+sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) {
+    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
+    consumer->mQueue = queue;
+    return consumer;
+}
+
+/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) {
+    if (!parcelable.IsValid()) {
+        ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable.");
+        return nullptr;
+    }
+
+    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
+    consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle());
+    return consumer;
+}
+
+status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/,
+                                          uint64_t /*maxFrameNumber*/) {
+    ALOGE("BufferHubConsumer::acquireBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::detachBuffer(int /*slot*/) {
+    ALOGE("BufferHubConsumer::detachBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) {
+    ALOGE("BufferHubConsumer::attachBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/,
+                                          EGLDisplay /*display*/, EGLSyncKHR /*fence*/,
+                                          const sp<Fence>& /*releaseFence*/) {
+    ALOGE("BufferHubConsumer::releaseBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/,
+                                            bool /*controlledByApp*/) {
+    ALOGE("BufferHubConsumer::consumerConnect: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::consumerDisconnect() {
+    ALOGE("BufferHubConsumer::consumerDisconnect: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) {
+    ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) {
+    ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) {
+    ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) {
+    ALOGE("BufferHubConsumer::setConsumerName: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) {
+    ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) {
+    ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) {
+    ALOGE("BufferHubConsumer::setTransformHint: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const {
+    ALOGE("BufferHubConsumer::getSidebandStream: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getOccupancyHistory(
+        bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) {
+    ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::discardFreeBuffers() {
+    ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
+    ALOGE("BufferHubConsumer::dumpState: not implemented.");
+    return INVALID_OPERATION;
+}
+
+IBinder* BufferHubConsumer::onAsBinder() {
+    ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder "
+          "object.");
+    return nullptr;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
new file mode 100644
index 0000000..ae5cca2
--- /dev/null
+++ b/libs/gui/BufferHubProducer.cpp
@@ -0,0 +1,717 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dvr/dvr_api.h>
+#include <gui/BufferHubProducer.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <system/window.h>
+
+namespace android {
+
+using namespace dvr;
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) {
+    sp<BufferHubProducer> producer = new BufferHubProducer;
+    producer->queue_ = queue;
+    return producer;
+}
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) {
+    if (!parcelable.IsValid()) {
+        ALOGE("BufferHubProducer::Create: Invalid producer parcelable.");
+        return nullptr;
+    }
+
+    sp<BufferHubProducer> producer = new BufferHubProducer;
+    producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
+    return producer;
+}
+
+status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ALOGV("requestBuffer: slot=%d", slot);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("requestBuffer: BufferHubProducer has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (buffers_[slot].mGraphicBuffer != nullptr) {
+        ALOGE("requestBuffer: slot %d is not empty.", slot);
+        return BAD_VALUE;
+    } else if (buffers_[slot].mBufferProducer == nullptr) {
+        ALOGE("requestBuffer: slot %d is not dequeued.", slot);
+        return BAD_VALUE;
+    }
+
+    const auto& buffer_producer = buffers_[slot].mBufferProducer;
+    sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+
+    buffers_[slot].mGraphicBuffer = graphic_buffer;
+    buffers_[slot].mRequestBufferCalled = true;
+
+    *buf = graphic_buffer;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) {
+    ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (max_dequeued_buffers <= 0 ||
+        max_dequeued_buffers >
+                int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) {
+        ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers,
+              BufferHubQueue::kMaxQueueCapacity);
+        return BAD_VALUE;
+    }
+
+    // The new dequeued_buffers count should not be violated by the number
+    // of currently dequeued buffers.
+    int dequeued_count = 0;
+    for (const auto& buf : buffers_) {
+        if (buf.mBufferState.isDequeued()) {
+            dequeued_count++;
+        }
+    }
+    if (dequeued_count > max_dequeued_buffers) {
+        ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers"
+              "count (%d) exceeds the current dequeued buffer count (%d)",
+              max_dequeued_buffers, dequeued_count);
+        return BAD_VALUE;
+    }
+
+    max_dequeued_buffer_count_ = max_dequeued_buffers;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAsyncMode(bool async) {
+    if (async) {
+        // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
+        // automatically and behaves differently from IGraphicBufferConsumer. Thus,
+        // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
+        // to prevent dequeueBuffer from being blocking) technically does not apply
+        // here.
+        //
+        // In Daydream, non-blocking producer side dequeue is guaranteed by careful
+        // buffer consumer implementations. In another word, BufferHubQueue based
+        // dequeueBuffer should never block whether setAsyncMode(true) is set or
+        // not.
+        //
+        // See: IGraphicBufferProducer::setAsyncMode and
+        // BufferQueueProducer::setAsyncMode for more about original implementation.
+        ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be "
+              "asynchronous. This call makes no effact.");
+        return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
+                                          uint32_t height, PixelFormat format, uint64_t usage,
+                                          uint64_t* /*outBufferAge*/,
+                                          FrameEventHistoryDelta* /* out_timestamps */) {
+    ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage);
+
+    status_t ret;
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("dequeueBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    const uint32_t kLayerCount = 1;
+    if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
+        // Lazy allocation. When the capacity of |queue_| has not reached
+        // |max_dequeued_buffer_count_|, allocate new buffer.
+        // TODO(jwcai) To save memory, the really reasonable thing to do is to go
+        // over existing slots and find first existing one to dequeue.
+        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+        if (ret < 0) return ret;
+    }
+
+    size_t slot = 0;
+    std::shared_ptr<BufferProducer> buffer_producer;
+
+    for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
+        LocalHandle fence;
+        auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
+        if (!buffer_status) return NO_MEMORY;
+
+        buffer_producer = buffer_status.take();
+        if (!buffer_producer) return NO_MEMORY;
+
+        if (width == buffer_producer->width() && height == buffer_producer->height() &&
+            uint32_t(format) == buffer_producer->format()) {
+            // The producer queue returns a buffer producer matches the request.
+            break;
+        }
+
+        // Needs reallocation.
+        // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
+        ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
+              "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
+              "re-allocattion.",
+              width, height, format, slot, buffer_producer->width(), buffer_producer->height(),
+              buffer_producer->format());
+        // Mark the slot as reallocating, so that later we can set
+        // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
+        buffers_[slot].mIsReallocating = true;
+
+        // Remove the old buffer once the allocation before allocating its
+        // replacement.
+        RemoveBuffer(slot);
+
+        // Allocate a new producer buffer with new buffer configs. Note that if
+        // there are already multiple buffers in the queue, the next one returned
+        // from |queue_->Dequeue| may not be the new buffer we just reallocated.
+        // Retry up to BufferHubQueue::kMaxQueueCapacity times.
+        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+        if (ret < 0) return ret;
+    }
+
+    // With the BufferHub backed solution. Buffer slot returned from
+    // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
+    // It's either in free state (if the buffer has never been used before) or
+    // in queued state (if the buffer has been dequeued and queued back to
+    // BufferHubQueue).
+    LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
+                         !buffers_[slot].mBufferState.isQueued()),
+                        "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+                        buffers_[slot].mBufferState.string());
+
+    buffers_[slot].mBufferState.freeQueued();
+    buffers_[slot].mBufferState.dequeue();
+    ALOGV("dequeueBuffer: slot=%zu", slot);
+
+    // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
+    // just need to exopose that through |BufferHubQueue| once we need fence.
+    *out_fence = Fence::NO_FENCE;
+    *out_slot = int(slot);
+    ret = NO_ERROR;
+
+    if (buffers_[slot].mIsReallocating) {
+        ret |= BUFFER_NEEDS_REALLOCATION;
+        buffers_[slot].mIsReallocating = false;
+    }
+
+    return ret;
+}
+
+status_t BufferHubProducer::detachBuffer(int /* slot */) {
+    ALOGE("BufferHubProducer::detachBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
+                                             sp<Fence>* /* out_fence */) {
+    ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
+                                         const sp<GraphicBuffer>& /* buffer */) {
+    // With this BufferHub backed implementation, we assume (for now) all buffers
+    // are allocated and owned by the BufferHub. Thus the attempt of transfering
+    // ownership of a buffer to the buffer queue is intentionally unsupported.
+    LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
+                                        QueueBufferOutput* output) {
+    ALOGV("queueBuffer: slot %d", slot);
+
+    if (output == nullptr) {
+        return BAD_VALUE;
+    }
+
+    int64_t timestamp;
+    bool is_auto_timestamp;
+    android_dataspace dataspace;
+    Rect crop(Rect::EMPTY_RECT);
+    int scaling_mode;
+    uint32_t transform;
+    sp<Fence> fence;
+
+    input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform,
+                  &fence);
+
+    // Check input scaling mode is valid.
+    switch (scaling_mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
+            return BAD_VALUE;
+    }
+
+    // Check input fence is valid.
+    if (fence == nullptr) {
+        ALOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("queueBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) {
+        ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
+              "mGraphicBuffer=%p)",
+              slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get());
+        return BAD_VALUE;
+    }
+
+    // Post the buffer producer with timestamp in the metadata.
+    const auto& buffer_producer = buffers_[slot].mBufferProducer;
+
+    // Check input crop is not out of boundary of current buffer.
+    Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
+    Rect cropped_rect(Rect::EMPTY_RECT);
+    crop.intersect(buffer_rect, &cropped_rect);
+    if (cropped_rect != crop) {
+        ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
+        return BAD_VALUE;
+    }
+
+    LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
+
+    DvrNativeBufferMetadata meta_data;
+    meta_data.timestamp = timestamp;
+    meta_data.is_auto_timestamp = int32_t(is_auto_timestamp);
+    meta_data.dataspace = int32_t(dataspace);
+    meta_data.crop_left = crop.left;
+    meta_data.crop_top = crop.top;
+    meta_data.crop_right = crop.right;
+    meta_data.crop_bottom = crop.bottom;
+    meta_data.scaling_mode = int32_t(scaling_mode);
+    meta_data.transform = int32_t(transform);
+
+    buffer_producer->PostAsync(&meta_data, fence_fd);
+    buffers_[slot].mBufferState.queue();
+
+    output->width = buffer_producer->width();
+    output->height = buffer_producer->height();
+    output->transformHint = 0; // default value, we don't use it yet.
+
+    // |numPendingBuffers| counts of the number of buffers that has been enqueued
+    // by the producer but not yet acquired by the consumer. Due to the nature
+    // of BufferHubQueue design, this is hard to trace from the producer's client
+    // side, but it's safe to assume it's zero.
+    output->numPendingBuffers = 0;
+
+    // Note that we are not setting nextFrameNumber here as it seems to be only
+    // used by surface flinger. See more at b/22802885, ag/791760.
+    output->nextFrameNumber = 0;
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("cancelBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (fence == nullptr) {
+        ALOGE("cancelBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    auto buffer_producer = buffers_[slot].mBufferProducer;
+    queue_->Enqueue(buffer_producer, size_t(slot), 0ULL);
+    buffers_[slot].mBufferState.cancel();
+    buffers_[slot].mFence = fence;
+    ALOGV("cancelBuffer: slot %d", slot);
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::query(int what, int* out_value) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (out_value == nullptr) {
+        ALOGE("query: out_value was NULL");
+        return BAD_VALUE;
+    }
+
+    int value = 0;
+    switch (what) {
+        case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+            // TODO(b/36187402) This should be the maximum number of buffers that this
+            // producer queue's consumer can acquire. Set to be at least one. Need to
+            // find a way to set from the consumer side.
+            value = kDefaultUndequeuedBuffers;
+            break;
+        case NATIVE_WINDOW_BUFFER_AGE:
+            value = 0;
+            break;
+        case NATIVE_WINDOW_WIDTH:
+            value = int32_t(queue_->default_width());
+            break;
+        case NATIVE_WINDOW_HEIGHT:
+            value = int32_t(queue_->default_height());
+            break;
+        case NATIVE_WINDOW_FORMAT:
+            value = int32_t(queue_->default_format());
+            break;
+        case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+            // BufferHubQueue is always operating in async mode, thus semantically
+            // consumer can never be running behind. See BufferQueueCore.cpp core
+            // for more information about the original meaning of this flag.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+            // TODO(jwcai) This is currently not implement as we don't need
+            // IGraphicBufferConsumer parity.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_DEFAULT_DATASPACE:
+            // TODO(jwcai) Return the default value android::BufferQueue is using as
+            // there is no way dvr::ConsumerQueue can set it.
+            value = 0; // HAL_DATASPACE_UNKNOWN
+            break;
+        case NATIVE_WINDOW_STICKY_TRANSFORM:
+            // TODO(jwcai) Return the default value android::BufferQueue is using as
+            // there is no way dvr::ConsumerQueue can set it.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
+            // In Daydream's implementation, the consumer end (i.e. VR Compostior)
+            // knows how to handle protected buffers.
+            value = 1;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    ALOGV("query: key=%d, v=%d", what, value);
+    *out_value = value;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api,
+                                    bool /* producer_controlled_by_app */,
+                                    QueueBufferOutput* output) {
+    // Consumer interaction are actually handled by buffer hub, and we need
+    // to maintain consumer operations here. We only need to perform basic input
+    // parameter checks here.
+    ALOGV(__FUNCTION__);
+
+    if (output == nullptr) {
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ != kNoConnectedApi) {
+        return BAD_VALUE;
+    }
+
+    if (!queue_->is_connected()) {
+        ALOGE("BufferHubProducer::connect: This BufferHubProducer is not "
+              "connected to bufferhud. Has it been taken out as a parcelable?");
+        return BAD_VALUE;
+    }
+
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            connected_api_ = api;
+
+            output->width = queue_->default_width();
+            output->height = queue_->default_height();
+
+            // default values, we don't use them yet.
+            output->transformHint = 0;
+            output->numPendingBuffers = 0;
+            output->nextFrameNumber = 0;
+            output->bufferReplaced = false;
+
+            break;
+        default:
+            ALOGE("BufferHubProducer::connect: unknow API %d", api);
+            return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) {
+    // Consumer interaction are actually handled by buffer hub, and we need
+    // to maintain consumer operations here.  We only need to perform basic input
+    // parameter checks here.
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (kNoConnectedApi == connected_api_) {
+        return NO_INIT;
+    } else if (api != connected_api_) {
+        return BAD_VALUE;
+    }
+
+    FreeAllBuffers();
+    connected_api_ = kNoConnectedApi;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    if (stream != nullptr) {
+        // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
+        // metadata.
+        ALOGE("SidebandStream is not currently supported.");
+        return INVALID_OPERATION;
+    }
+    return NO_ERROR;
+}
+
+void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */,
+                                        PixelFormat /* format */, uint64_t /* usage */) {
+    // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
+    // of buffers permitted by the current BufferQueue configuration (aka
+    // |max_buffer_count_|).
+    ALOGE("BufferHubProducer::allocateBuffers not implemented.");
+}
+
+status_t BufferHubProducer::allowAllocation(bool /* allow */) {
+    ALOGE("BufferHubProducer::allowAllocation not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+    generation_number_ = generation_number;
+    return NO_ERROR;
+}
+
+String8 BufferHubProducer::getConsumerName() const {
+    // BufferHub based implementation could have one to many producer/consumer
+    // relationship, thus |getConsumerName| from the producer side does not
+    // make any sense.
+    ALOGE("BufferHubProducer::getConsumerName not supported.");
+    return String8("BufferHubQueue::DummyConsumer");
+}
+
+status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
+    if (shared_buffer_mode) {
+        ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported.");
+        // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
+        return INVALID_OPERATION;
+    }
+    // Setting to default should just work as a no-op.
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) {
+    if (auto_refresh) {
+        ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported.");
+        return INVALID_OPERATION;
+    }
+    // Setting to default should just work as a no-op.
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+    dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */,
+                                                sp<Fence>* /* out_fence */,
+                                                float /*out_transform_matrix*/[16]) {
+    ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {
+    ALOGE("BufferHubProducer::getFrameTimestamps not implemented.");
+}
+
+status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const {
+    ALOGV(__FUNCTION__);
+
+    *out_id = unique_id_;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const {
+    ALOGV(__FUNCTION__);
+
+    // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+    *out_usage = 0;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) {
+    if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE;
+
+    if (connected_api_ != kNoConnectedApi) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has "
+              "connected client. Must disconnect first.");
+        return BAD_VALUE;
+    }
+
+    if (!queue_->is_connected()) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer "
+              "is not connected to bufferhud. Has it been taken out as a "
+              "parcelable?");
+        return BAD_VALUE;
+    }
+
+    auto status = queue_->TakeAsParcelable();
+    if (!status) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out "
+              "ProducuerQueueParcelable from the producer queue, error: %s.",
+              status.GetErrorMessage().c_str());
+        return BAD_VALUE;
+    }
+
+    *out_parcelable = status.take();
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                                           PixelFormat format, uint64_t usage) {
+    auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage);
+    if (!status) {
+        ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s",
+              status.GetErrorMessage().c_str());
+        return NO_MEMORY;
+    }
+
+    size_t slot = status.get();
+    auto buffer_producer = queue_->GetBuffer(slot);
+
+    LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu",
+                        slot);
+
+    buffers_[slot].mBufferProducer = buffer_producer;
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::RemoveBuffer(size_t slot) {
+    auto status = queue_->RemoveBuffer(slot);
+    if (!status) {
+        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
+              status.GetErrorMessage().c_str());
+        return INVALID_OPERATION;
+    }
+
+    // Reset in memory objects related the the buffer.
+    buffers_[slot].mBufferProducer = nullptr;
+    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mBufferState.detachProducer();
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::FreeAllBuffers() {
+    for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+        // Reset in memory objects related the the buffer.
+        buffers_[slot].mGraphicBuffer = nullptr;
+        buffers_[slot].mBufferState.reset();
+        buffers_[slot].mRequestBufferCalled = false;
+        buffers_[slot].mBufferProducer = nullptr;
+        buffers_[slot].mFence = Fence::NO_FENCE;
+    }
+
+    auto status = queue_->FreeAllBuffers();
+    if (!status) {
+        ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on "
+              "the queue: %s",
+              status.GetErrorMessage().c_str());
+    }
+
+    if (queue_->capacity() != 0 || queue_->count() != 0) {
+        LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed.");
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::exportToParcel(Parcel* parcel) {
+    status_t res = TakeAsParcelable(&pending_producer_parcelable_);
+    if (res != NO_ERROR) return res;
+
+    if (!pending_producer_parcelable_.IsValid()) {
+        ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object.");
+        return BAD_VALUE;
+    }
+
+    res = parcel->writeUint32(USE_BUFFER_HUB);
+    if (res != NO_ERROR) {
+        ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res);
+        return res;
+    }
+
+    return pending_producer_parcelable_.writeToParcel(parcel);
+}
+
+IBinder* BufferHubProducer::onAsBinder() {
+    ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder "
+          "object.");
+    return nullptr;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 69b5962..f50379b 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -55,7 +55,8 @@
     mSurfaceDamage(),
     mAutoRefresh(false),
     mQueuedBuffer(true),
-    mIsStale(false) {
+    mIsStale(false),
+    mApi(0) {
 }
 
 BufferItem::~BufferItem() {}
@@ -84,6 +85,7 @@
     addAligned(size, mAutoRefresh);
     addAligned(size, mQueuedBuffer);
     addAligned(size, mIsStale);
+    addAligned(size, mApi);
     return size;
 }
 
@@ -98,6 +100,7 @@
         size = FlattenableUtils::align<4>(size);
     }
     size += mSurfaceDamage.getFlattenedSize();
+    size += mHdrMetadata.getFlattenedSize();
     size = FlattenableUtils::align<8>(size);
     return size + getPodSize();
 }
@@ -151,6 +154,10 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
+    err = mHdrMetadata.flatten(buffer, size);
+    if (err) return err;
+    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -172,6 +179,7 @@
     writeAligned(buffer, size, mAutoRefresh);
     writeAligned(buffer, size, mQueuedBuffer);
     writeAligned(buffer, size, mIsStale);
+    writeAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
@@ -212,6 +220,10 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
+    err = mHdrMetadata.unflatten(buffer, size);
+    if (err) return err;
+    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -238,6 +250,7 @@
     readAligned(buffer, size, mAutoRefresh);
     readAligned(buffer, size, mQueuedBuffer);
     readAligned(buffer, size, mIsStale);
+    readAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index da42956..89bc0c4 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -49,16 +49,6 @@
 
 BufferItemConsumer::~BufferItemConsumer() {}
 
-void BufferItemConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        BI_LOGE("setName: BufferItemConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
 void BufferItemConsumer::setBufferFreedListener(
         const wp<BufferFreedListener>& listener) {
     Mutex::Autolock _l(mMutex);
@@ -102,10 +92,13 @@
     Mutex::Autolock _l(mMutex);
 
     err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
+    if (err != OK) {
+        BI_LOGE("Failed to addReleaseFenceLocked");
+    }
 
     err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY,
             EGL_NO_SYNC_KHR);
-    if (err != OK) {
+    if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
         BI_LOGE("Failed to release buffer: %s (%d)",
                 strerror(-err), err);
     }
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 4151212..a8da134 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -18,6 +18,11 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
+#ifndef NO_BUFFERHUB
+#include <gui/BufferHubConsumer.h>
+#include <gui/BufferHubProducer.h>
+#endif
+
 #include <gui/BufferQueue.h>
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
@@ -101,4 +106,32 @@
     *outConsumer = consumer;
 }
 
+#ifndef NO_BUFFERHUB
+void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
+                                       sp<IGraphicBufferConsumer>* outConsumer) {
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL");
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+    dvr::ProducerQueueConfigBuilder configBuilder;
+    std::shared_ptr<dvr::ProducerQueue> producerQueue =
+            dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
+    LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue.");
+
+    std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
+    LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue.");
+
+    producer = BufferHubProducer::Create(producerQueue);
+    consumer = BufferHubConsumer::Create(consumerQueue);
+
+    LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer");
+    LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer");
+
+    *outProducer = producer;
+    *outConsumer = consumer;
+}
+#endif
+
 }; // namespace android
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 17cf677..d70e142 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -35,7 +35,9 @@
 #include <gui/IProducerListener.h>
 
 #include <binder/IPCThreadState.h>
+#ifndef __ANDROID_VNDK__
 #include <binder/PermissionCache.h>
+#endif
 
 #include <system/window.h>
 
@@ -757,12 +759,18 @@
     }
 
     const IPCThreadState* ipc = IPCThreadState::self();
-    const pid_t pid = ipc->getCallingPid();
     const uid_t uid = ipc->getCallingUid();
+#ifndef __ANDROID_VNDK__
+    // permission check can't be done for vendors as vendors have no access to
+    // the PermissionController
+    const pid_t pid = ipc->getCallingPid();
     if ((uid != shellUid) &&
         !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
         outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
                 "from pid=%d, uid=%d\n", pid, uid);
+#else
+    if (uid != shellUid) {
+#endif
         android_errorWriteWithInfoLog(0x534e4554, "27046057",
                 static_cast<int32_t>(uid), NULL, 0);
         return PERMISSION_DENIED;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 625dc5b..c96a2dd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -381,7 +381,6 @@
 
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
-        mCore->waitWhileAllocatingLocked();
 
         if (format == 0) {
             format = mCore->mDefaultBufferFormat;
@@ -764,7 +763,8 @@
     input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
             &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
             &getFrameTimestamps);
-    Region surfaceDamage = input.getSurfaceDamage();
+    const Region& surfaceDamage = input.getSurfaceDamage();
+    const HdrMetadata& hdrMetadata = input.getHdrMetadata();
 
     if (acquireFence == NULL) {
         BQ_LOGE("queueBuffer: fence is NULL");
@@ -825,9 +825,9 @@
         }
 
         BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
-                " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
-                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
-                dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+                " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
+                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
+                hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
                 transform,
                 BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
 
@@ -866,6 +866,7 @@
         item.mTimestamp = requestedPresentTimestamp;
         item.mIsAutoTimestamp = isAutoTimestamp;
         item.mDataSpace = dataSpace;
+        item.mHdrMetadata = hdrMetadata;
         item.mFrameNumber = currentFrameNumber;
         item.mSlot = slot;
         item.mFence = acquireFence;
@@ -876,6 +877,7 @@
         item.mSurfaceDamage = surfaceDamage;
         item.mQueuedBuffer = true;
         item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+        item.mApi = mCore->mConnectedApi;
 
         mStickyTransform = stickyTransform;
 
@@ -1118,6 +1120,9 @@
         case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
             value = static_cast<int32_t>(mCore->mConsumerIsProtected);
             break;
+        case NATIVE_WINDOW_MAX_BUFFER_COUNT:
+            value = static_cast<int32_t>(mCore->mMaxBufferCount);
+            break;
         default:
             return BAD_VALUE;
     }
@@ -1328,6 +1333,7 @@
         uint32_t allocHeight = 0;
         PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
         uint64_t allocUsage = 0;
+        std::string allocName;
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
             mCore->waitWhileAllocatingLocked();
@@ -1338,7 +1344,9 @@
                 return;
             }
 
-            newBufferCount = mCore->mFreeSlots.size();
+            // Only allocate one buffer at a time to reduce risks of overlapping an allocation from
+            // both allocateBuffers and dequeueBuffer.
+            newBufferCount = mCore->mFreeSlots.empty() ? 0 : 1;
             if (newBufferCount == 0) {
                 return;
             }
@@ -1347,15 +1355,16 @@
             allocHeight = height > 0 ? height : mCore->mDefaultHeight;
             allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
             allocUsage = usage | mCore->mConsumerUsageBits;
+            allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size());
 
             mCore->mIsAllocating = true;
         } // Autolock scope
 
         Vector<sp<GraphicBuffer>> buffers;
-        for (size_t i = 0; i <  newBufferCount; ++i) {
+        for (size_t i = 0; i < newBufferCount; ++i) {
             sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                     allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
-                    allocUsage, {mConsumerName.string(), mConsumerName.size()});
+                    allocUsage, allocName);
 
             status_t result = graphicBuffer->initCheck();
 
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 7aa7872..f9e292e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -182,6 +182,16 @@
     return mAbandoned;
 }
 
+void ConsumerBase::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setName: ConsumerBase is abandoned!");
+        return;
+    }
+    mName = name;
+    mConsumer->setConsumerName(name);
+}
+
 void ConsumerBase::setFrameAvailableListener(
         const wp<FrameAvailableListener>& listener) {
     CB_LOGV("setFrameAvailableListener");
@@ -237,6 +247,50 @@
     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
 }
 
+status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setConsumerUsageBits(usage);
+}
+
+status_t ConsumerBase::setTransformHint(uint32_t hint) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setTransformHint: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setTransformHint(hint);
+}
+
+status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
+sp<NativeHandle> ConsumerBase::getSidebandStream() const {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("getSidebandStream: ConsumerBase is abandoned!");
+        return nullptr;
+    }
+
+    sp<NativeHandle> stream;
+    status_t err = mConsumer->getSidebandStream(&stream);
+    if (err != NO_ERROR) {
+        CB_LOGE("failed to get sideband stream: %d", err);
+        return nullptr;
+    }
+
+    return stream;
+}
+
 status_t ConsumerBase::getOccupancyHistory(bool forceFlush,
         std::vector<OccupancyTracker::Segment>* outHistory) {
     Mutex::Autolock _l(mMutex);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index ae7c65c..8edf604 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "CpuConsumer"
 //#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <cutils/compiler.h>
-#include <utils/Log.h>
-#include <gui/BufferItem.h>
 #include <gui/CpuConsumer.h>
 
+#include <gui/BufferItem.h>
+#include <utils/Log.h>
+
 #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
@@ -44,20 +44,19 @@
     mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers));
 }
 
-CpuConsumer::~CpuConsumer() {
-    // ConsumerBase destructor does all the work.
+size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const {
+    for (size_t i = 0; i < mMaxLockedBuffers; i++) {
+        const auto& ab = mAcquiredBuffers[i];
+        // note that this finds AcquiredBuffer::kUnusedId as well
+        if (ab.mLockedBufferId == id) {
+            return i;
+        }
+    }
+    return mMaxLockedBuffers; // an invalid index
 }
 
-
-
-void CpuConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CC_LOGE("setName: CpuConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
+static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) {
+    return reinterpret_cast<uintptr_t>(buffer.data);
 }
 
 static bool isPossiblyYUV(PixelFormat format) {
@@ -88,10 +87,74 @@
     }
 }
 
+status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const {
+    android_ycbcr ycbcr = android_ycbcr();
+
+    PixelFormat format = item.mGraphicBuffer->getPixelFormat();
+    PixelFormat flexFormat = format;
+    if (isPossiblyYUV(format)) {
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                           item.mCrop, &ycbcr, fenceFd);
+        if (err == OK) {
+            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                CC_LOGV("locking buffer of format %#x as flex YUV", format);
+            }
+        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+    }
+
+    if (ycbcr.y != nullptr) {
+        outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y);
+        outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride);
+        outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+        outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+        outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
+        outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
+    } else {
+        // not flexible YUV; try lockAsync
+        void* bufferPointer = nullptr;
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                      item.mCrop, &bufferPointer, fenceFd);
+        if (err != OK) {
+            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+
+        outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer);
+        outBuffer->stride = item.mGraphicBuffer->getStride();
+        outBuffer->dataCb = nullptr;
+        outBuffer->dataCr = nullptr;
+        outBuffer->chromaStride = 0;
+        outBuffer->chromaStep = 0;
+    }
+
+    outBuffer->width = item.mGraphicBuffer->getWidth();
+    outBuffer->height = item.mGraphicBuffer->getHeight();
+    outBuffer->format = format;
+    outBuffer->flexFormat = flexFormat;
+
+    outBuffer->crop = item.mCrop;
+    outBuffer->transform = item.mTransform;
+    outBuffer->scalingMode = item.mScalingMode;
+    outBuffer->timestamp = item.mTimestamp;
+    outBuffer->dataSpace = item.mDataSpace;
+    outBuffer->frameNumber = item.mFrameNumber;
+
+    return OK;
+}
+
 status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
     status_t err;
 
     if (!nativeBuffer) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
     if (mCurrentLockedBuffers == mMaxLockedBuffers) {
         CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.",
                 mMaxLockedBuffers);
@@ -99,9 +162,6 @@
     }
 
     BufferItem b;
-
-    Mutex::Autolock _l(mMutex);
-
     err = acquireBufferLocked(&b, 0);
     if (err != OK) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -112,94 +172,23 @@
         }
     }
 
-    int slot = b.mSlot;
-
-    void *bufferPointer = NULL;
-    android_ycbcr ycbcr = android_ycbcr();
-
-    PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat();
-    PixelFormat flexFormat = format;
-    if (isPossiblyYUV(format)) {
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lockYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr);
-        }
-        if (err == OK) {
-            bufferPointer = ycbcr.y;
-            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
-            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                CC_LOGV("locking buffer of format %#x as flex YUV", format);
-            }
-        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    if (b.mGraphicBuffer == nullptr) {
+        b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer;
     }
 
-    if (bufferPointer == NULL) { // not flexible YUV
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsync(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lock(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer);
-        }
-        if (err != OK) {
-            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    err = lockBufferItem(b, nativeBuffer);
+    if (err != OK) {
+        return err;
     }
 
-    size_t lockedIdx = 0;
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (mAcquiredBuffers[lockedIdx].mSlot ==
-                BufferQueue::INVALID_BUFFER_SLOT) {
-            break;
-        }
-    }
-    assert(lockedIdx < mMaxLockedBuffers);
+    // find an unused AcquiredBuffer
+    size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId);
+    ALOG_ASSERT(lockedIdx < mMaxLockedBuffers);
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = slot;
-    ab.mBufferPointer = bufferPointer;
-    ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
-
-    nativeBuffer->data   =
-            reinterpret_cast<uint8_t*>(bufferPointer);
-    nativeBuffer->width  = mSlots[slot].mGraphicBuffer->getWidth();
-    nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight();
-    nativeBuffer->format = format;
-    nativeBuffer->flexFormat = flexFormat;
-    nativeBuffer->stride = (ycbcr.y != NULL) ?
-            static_cast<uint32_t>(ycbcr.ystride) :
-            mSlots[slot].mGraphicBuffer->getStride();
-
-    nativeBuffer->crop        = b.mCrop;
-    nativeBuffer->transform   = b.mTransform;
-    nativeBuffer->scalingMode = b.mScalingMode;
-    nativeBuffer->timestamp   = b.mTimestamp;
-    nativeBuffer->dataSpace   = b.mDataSpace;
-    nativeBuffer->frameNumber = b.mFrameNumber;
-
-    nativeBuffer->dataCb       = reinterpret_cast<uint8_t*>(ycbcr.cb);
-    nativeBuffer->dataCr       = reinterpret_cast<uint8_t*>(ycbcr.cr);
-    nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
-    nativeBuffer->chromaStep   = static_cast<uint32_t>(ycbcr.chroma_step);
+    ab.mSlot = b.mSlot;
+    ab.mGraphicBuffer = b.mGraphicBuffer;
+    ab.mLockedBufferId = getLockedBufferId(*nativeBuffer);
 
     mCurrentLockedBuffers++;
 
@@ -208,60 +197,34 @@
 
 status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
     Mutex::Autolock _l(mMutex);
-    size_t lockedIdx = 0;
 
-    void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break;
-    }
+    uintptr_t id = getLockedBufferId(nativeBuffer);
+    size_t lockedIdx =
+        (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers;
     if (lockedIdx == mMaxLockedBuffers) {
         CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
         return BAD_VALUE;
     }
 
-    return releaseAcquiredBufferLocked(lockedIdx);
-}
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) {
-    status_t err;
-    int fd = -1;
-
-    err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd);
+    int fenceFd = -1;
+    status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd);
     if (err != OK) {
         CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__,
                 lockedIdx);
         return err;
     }
-    int buf = mAcquiredBuffers[lockedIdx].mSlot;
-    if (CC_LIKELY(fd != -1)) {
-        sp<Fence> fence(new Fence(fd));
-        addReleaseFenceLocked(
-            mAcquiredBuffers[lockedIdx].mSlot,
-            mSlots[buf].mGraphicBuffer,
-            fence);
-    }
 
-    // release the buffer if it hasn't already been freed by the BufferQueue.
-    // This can happen, for example, when the producer of this buffer
-    // disconnected after this buffer was acquired.
-    if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
-            mSlots[buf].mGraphicBuffer)) {
-        releaseBufferLocked(
-                buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer,
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
-    }
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence);
+    releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    ab.mBufferPointer = NULL;
-    ab.mGraphicBuffer.clear();
+    ab.reset();
 
     mCurrentLockedBuffers--;
-    return OK;
-}
 
-void CpuConsumer::freeBufferLocked(int slotIndex) {
-    ConsumerBase::freeBufferLocked(slotIndex);
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index fccca97..a379ad6 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -628,7 +628,6 @@
         ALOGE("FrameEventHistoryDelta assign clobbering history.");
     }
     mDeltas = std::move(src.mDeltas);
-    ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
     return *this;
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 14d9937..885efec 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,6 +31,8 @@
 
 #include <hardware/hardware.h>
 
+#include <math/mat4.h>
+
 #include <gui/BufferItem.h>
 #include <gui/GLConsumer.h>
 #include <gui/ISurfaceComposer.h>
@@ -75,33 +77,7 @@
     "_______________"
 };
 
-// Transform matrices
-static float mtxIdentity[16] = {
-    1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    0, 0, 0, 1,
-};
-static float mtxFlipH[16] = {
-    -1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-static float mtxFlipV[16] = {
-    1, 0, 0, 0,
-    0, -1, 0, 0,
-    0, 0, 1, 0,
-    0, 1, 0, 1,
-};
-static float mtxRot90[16] = {
-    0, 1, 0, 0,
-    -1, 0, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-
-static void mtxMul(float out[16], const float a[16], const float b[16]);
+static const mat4 mtxIdentity;
 
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
@@ -173,7 +149,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -202,7 +178,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -758,25 +734,6 @@
     return OK;
 }
 
-bool GLConsumer::isExternalFormat(PixelFormat format)
-{
-    switch (format) {
-    // supported YUV formats
-    case HAL_PIXEL_FORMAT_YV12:
-    // Legacy/deprecated YUV formats
-    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-    case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        return true;
-    }
-
-    // Any OEM format needs to be considered
-    if (format>=0x100 && format<=0x1FF)
-        return true;
-
-    return false;
-}
-
 uint32_t GLConsumer::getCurrentTextureTarget() const {
     return mTexTarget;
 }
@@ -820,34 +777,37 @@
 void GLConsumer::computeTransformMatrix(float outTransform[16],
         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
         bool filtering) {
+    // Transform matrices
+    static const mat4 mtxFlipH(
+        -1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+    static const mat4 mtxFlipV(
+        1, 0, 0, 0,
+        0, -1, 0, 0,
+        0, 0, 1, 0,
+        0, 1, 0, 1
+    );
+    static const mat4 mtxRot90(
+        0, 1, 0, 0,
+        -1, 0, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
 
-    float xform[16];
-    for (int i = 0; i < 16; i++) {
-        xform[i] = mtxIdentity[i];
-    }
+    mat4 xform;
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipH);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipH;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipV);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipV;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        float result[16];
-        mtxMul(result, xform, mtxRot90);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxRot90;
     }
 
-    float mtxBeforeFlipV[16];
     if (!cropRect.isEmpty()) {
         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
         float bufferWidth = buf->getWidth();
@@ -893,25 +853,63 @@
             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
                     bufferHeight;
         }
-        float crop[16] = {
+
+        mat4 crop(
             sx, 0, 0, 0,
             0, sy, 0, 0,
             0, 0, 1, 0,
-            tx, ty, 0, 1,
-        };
-
-        mtxMul(mtxBeforeFlipV, crop, xform);
-    } else {
-        for (int i = 0; i < 16; i++) {
-            mtxBeforeFlipV[i] = xform[i];
-        }
+            tx, ty, 0, 1
+        );
+        xform = crop * xform;
     }
 
     // SurfaceFlinger expects the top of its window textures to be at a Y
     // coordinate of 0, so GLConsumer must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
+    xform = mtxFlipV * xform;
+
+    memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
+    Rect outCrop = crop;
+
+    uint32_t newWidth = static_cast<uint32_t>(crop.width());
+    uint32_t newHeight = static_cast<uint32_t>(crop.height());
+
+    if (newWidth * bufferHeight > newHeight * bufferWidth) {
+        newWidth = newHeight * bufferWidth / bufferHeight;
+        ALOGV("too wide: newWidth = %d", newWidth);
+    } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
+        newHeight = newWidth * bufferHeight / bufferWidth;
+        ALOGV("too tall: newHeight = %d", newHeight);
+    }
+
+    uint32_t currentWidth = static_cast<uint32_t>(crop.width());
+    uint32_t currentHeight = static_cast<uint32_t>(crop.height());
+
+    // The crop is too wide
+    if (newWidth < currentWidth) {
+        uint32_t dw = currentWidth - newWidth;
+        auto halfdw = dw / 2;
+        outCrop.left += halfdw;
+        // Not halfdw because it would subtract 1 too few when dw is odd
+        outCrop.right -= (dw - halfdw);
+        // The crop is too tall
+    } else if (newHeight < currentHeight) {
+        uint32_t dh = currentHeight - newHeight;
+        auto halfdh = dh / 2;
+        outCrop.top += halfdh;
+        // Not halfdh because it would subtract 1 too few when dh is odd
+        outCrop.bottom -= (dh - halfdh);
+    }
+
+    ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
+            outCrop.left, outCrop.top,
+            outCrop.right,outCrop.bottom);
+
+    return outCrop;
 }
 
 nsecs_t GLConsumer::getTimestamp() {
@@ -945,45 +943,9 @@
 
 Rect GLConsumer::getCurrentCrop() const {
     Mutex::Autolock lock(mMutex);
-
-    Rect outCrop = mCurrentCrop;
-    if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
-            newWidth = newHeight * mDefaultWidth / mDefaultHeight;
-            GLC_LOGV("too wide: newWidth = %d", newWidth);
-        } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
-            newHeight = newWidth * mDefaultHeight / mDefaultWidth;
-            GLC_LOGV("too tall: newHeight = %d", newHeight);
-        }
-
-        uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        // The crop is too wide
-        if (newWidth < currentWidth) {
-            uint32_t dw = currentWidth - newWidth;
-            auto halfdw = dw / 2;
-            outCrop.left += halfdw;
-            // Not halfdw because it would subtract 1 too few when dw is odd
-            outCrop.right -= (dw - halfdw);
-        // The crop is too tall
-        } else if (newHeight < currentHeight) {
-            uint32_t dh = currentHeight - newHeight;
-            auto halfdh = dh / 2;
-            outCrop.top += halfdh;
-            // Not halfdh because it would subtract 1 too few when dh is odd
-            outCrop.bottom -= (dh - halfdh);
-        }
-
-        GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
-            outCrop.left, outCrop.top,
-            outCrop.right,outCrop.bottom);
-    }
-
-    return outCrop;
+    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+        ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+        : mCurrentCrop;
 }
 
 uint32_t GLConsumer::getCurrentTransform() const {
@@ -1006,11 +968,6 @@
     return mCurrentFenceTime;
 }
 
-status_t GLConsumer::doGLFenceWait() const {
-    Mutex::Autolock lock(mMutex);
-    return doGLFenceWaitLocked();
-}
-
 status_t GLConsumer::doGLFenceWaitLocked() const {
 
     EGLDisplay dpy = eglGetCurrentDisplay();
@@ -1027,7 +984,8 @@
     }
 
     if (mCurrentFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync()) {
+        if (SyncFeatures::getInstance().useWaitSync() &&
+            SyncFeatures::getInstance().useNativeFenceSync()) {
             // Create an EGLSyncKHR from the current fence.
             int fenceFd = mCurrentFence->dup();
             if (fenceFd == -1) {
@@ -1086,61 +1044,8 @@
     ConsumerBase::abandonLocked();
 }
 
-void GLConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setName: GLConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
-status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t GLConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    usage |= DEFAULT_USAGE_FLAGS;
-    return mConsumer->setConsumerUsageBits(usage);
-}
-
-status_t GLConsumer::setTransformHint(uint32_t hint) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setTransformHint: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setTransformHint(hint);
-}
-
-status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
 }
 
 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
@@ -1155,28 +1060,6 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-static void mtxMul(float out[16], const float a[16], const float b[16]) {
-    out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
-    out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
-    out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
-    out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
-
-    out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
-    out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
-    out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
-    out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
-
-    out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
-    out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
-    out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
-    out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
-
-    out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
-    out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
-    out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
-    out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
-}
-
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
new file mode 100644
index 0000000..b715e43
--- /dev/null
+++ b/libs/gui/HdrMetadata.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/HdrMetadata.h>
+
+namespace android {
+
+size_t HdrMetadata::getFlattenedSize() const {
+    size_t size = sizeof(validTypes);
+    if (validTypes & SMPTE2086) {
+        size += sizeof(smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        size += sizeof(cta8613);
+    }
+    return size;
+}
+
+status_t HdrMetadata::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, validTypes);
+    if (validTypes & SMPTE2086) {
+        FlattenableUtils::write(buffer, size, smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        FlattenableUtils::write(buffer, size, cta8613);
+    }
+
+    return NO_ERROR;
+}
+
+status_t HdrMetadata::unflatten(void const* buffer, size_t size) {
+    if (size < sizeof(validTypes)) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, validTypes);
+    if (validTypes & SMPTE2086) {
+        if (size < sizeof(smpte2086)) {
+            return NO_MEMORY;
+        }
+        FlattenableUtils::read(buffer, size, smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        if (size < sizeof(cta8613)) {
+            return NO_MEMORY;
+        }
+        FlattenableUtils::read(buffer, size, cta8613);
+    }
+
+    return NO_ERROR;
+}
+
+bool HdrMetadata::operator==(const HdrMetadata& rhs) const {
+    if (validTypes != rhs.validTypes) return false;
+
+    if ((validTypes & SMPTE2086) == SMPTE2086) {
+        if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x ||
+            smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y ||
+            smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x ||
+            smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y ||
+            smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x ||
+            smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y ||
+            smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x ||
+            smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y ||
+            smpte2086.maxLuminance != rhs.smpte2086.maxLuminance ||
+            smpte2086.minLuminance != rhs.smpte2086.minLuminance) {
+            return false;
+        }
+    }
+
+    if ((validTypes & CTA861_3) == CTA861_3) {
+        if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel ||
+            cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 71e22ce..0b37960 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,6 +27,9 @@
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
 
+#ifndef NO_BUFFERHUB
+#include <gui/BufferHubProducer.h>
+#endif
 #include <gui/BufferQueueDefs.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
@@ -352,7 +355,7 @@
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint64(usage);
-        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
+        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, TF_ONE_WAY);
         if (result != NO_ERROR) {
             ALOGE("allocateBuffers failed to transact: %d", result);
         }
@@ -653,6 +656,79 @@
 
 // ----------------------------------------------------------------------
 
+status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
+    status_t res = OK;
+    res = parcel->writeUint32(USE_BUFFER_QUEUE);
+    if (res != NO_ERROR) {
+        ALOGE("exportToParcel: Cannot write magic, res=%d.", res);
+        return res;
+    }
+
+    return parcel->writeStrongBinder(IInterface::asBinder(this));
+}
+
+/* static */
+status_t IGraphicBufferProducer::exportToParcel(const sp<IGraphicBufferProducer>& producer,
+                                                Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("exportToParcel: Invalid parcel object.");
+        return BAD_VALUE;
+    }
+
+    if (producer == nullptr) {
+        status_t res = OK;
+        res = parcel->writeUint32(IGraphicBufferProducer::USE_BUFFER_QUEUE);
+        if (res != NO_ERROR) return res;
+        return parcel->writeStrongBinder(nullptr);
+    } else {
+        return producer->exportToParcel(parcel);
+    }
+}
+
+/* static */
+sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel* parcel) {
+    uint32_t outMagic = 0;
+    status_t res = NO_ERROR;
+
+    res = parcel->readUint32(&outMagic);
+    if (res != NO_ERROR) {
+        ALOGE("createFromParcel: Failed to read magic, error=%d.", res);
+        return nullptr;
+    }
+
+    switch (outMagic) {
+        case USE_BUFFER_QUEUE: {
+            sp<IBinder> binder;
+            res = parcel->readNullableStrongBinder(&binder);
+            if (res != NO_ERROR) {
+                ALOGE("createFromParcel: Can't read strong binder.");
+                return nullptr;
+            }
+            return interface_cast<IGraphicBufferProducer>(binder);
+        }
+        case USE_BUFFER_HUB: {
+            ALOGE("createFromParcel: BufferHub not implemented.");
+#ifndef NO_BUFFERHUB
+            dvr::ProducerQueueParcelable producerParcelable;
+            res = producerParcelable.readFromParcel(parcel);
+            if (res != NO_ERROR) {
+                ALOGE("createFromParcel: Failed to read from parcel, error=%d", res);
+                return nullptr;
+            }
+            return BufferHubProducer::Create(std::move(producerParcelable));
+#else
+            return nullptr;
+#endif
+        }
+        default: {
+            ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic);
+            return nullptr;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 status_t BnGraphicBufferProducer::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -951,7 +1027,8 @@
 size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
     return minFlattenedSize() +
             fence->getFlattenedSize() +
-            surfaceDamage.getFlattenedSize();
+            surfaceDamage.getFlattenedSize() +
+            hdrMetadata.getFlattenedSize();
 }
 
 size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -978,7 +1055,12 @@
     if (result != NO_ERROR) {
         return result;
     }
-    return surfaceDamage.flatten(buffer, size);
+    result = surfaceDamage.flatten(buffer, size);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+    return hdrMetadata.flatten(buffer, size);
 }
 
 status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
@@ -1002,7 +1084,12 @@
     if (result != NO_ERROR) {
         return result;
     }
-    return surfaceDamage.unflatten(buffer, size);
+    result = surfaceDamage.unflatten(buffer, size);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+    return hdrMetadata.unflatten(buffer, size);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0a0d112..d2d27e8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -28,8 +28,8 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
 
 #include <system/graphics.h>
 
@@ -43,6 +43,8 @@
 
 namespace android {
 
+using ui::ColorMode;
+
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
 {
 public:
@@ -100,17 +102,13 @@
         remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
     }
 
-    virtual status_t captureScreen(const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            ISurfaceComposer::Rotation rotation)
-    {
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   ISurfaceComposer::Rotation rotation) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        data.writeStrongBinder(IInterface::asBinder(producer));
         data.write(sourceCrop);
         data.writeUint32(reqWidth);
         data.writeUint32(reqHeight);
@@ -118,8 +116,46 @@
         data.writeInt32(maxLayerZ);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
-        remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
-        return reply.readInt32();
+        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = reply.readInt32();
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        *outBuffer = new GraphicBuffer();
+        reply.read(**outBuffer);
+        return err;
+    }
+
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   float frameScale, bool childrenOnly) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(layerHandleBinder);
+        data.write(sourceCrop);
+        data.writeFloat(frameScale);
+        data.writeBool(childrenOnly);
+        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = reply.readInt32();
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        *outBuffer = new GraphicBuffer();
+        reply.read(**outBuffer);
+
+        return err;
     }
 
     virtual bool authenticateSurfaceTexture(
@@ -296,6 +332,34 @@
         return result;
     }
 
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result == NO_ERROR) {
+            result = reply.read(*outViewport);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayViewport failed to read: %d", result);
+                return result;
+            }
+        }
+        return result;
+    }
+
     virtual int getActiveConfig(const sp<IBinder>& display)
     {
         Parcel data, reply;
@@ -316,7 +380,7 @@
     }
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) {
+            Vector<ColorMode>* outColorModes) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -339,34 +403,34 @@
             outColorModes->clear();
             outColorModes->resize(numModes);
             for (size_t i = 0; i < numModes; ++i) {
-                outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i);
+                outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i);
             }
         }
         return result;
     }
 
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) {
+    virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = data.writeStrongBinder(display);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to transact: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
-        return static_cast<android_color_mode_t>(reply.readInt32());
+        return static_cast<ColorMode>(reply.readInt32());
     }
 
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) {
+            ColorMode colorMode) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -378,7 +442,7 @@
             ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
             return result;
         }
-        result = data.writeInt32(colorMode);
+        result = data.writeInt32(static_cast<int32_t>(colorMode));
         if (result != NO_ERROR) {
             ALOGE("setActiveColorMode failed to writeInt32: %d", result);
             return result;
@@ -469,6 +533,36 @@
         return result;
     }
 
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+    {
+        if (!outLayers) {
+            return UNEXPECTED_NULL;
+        }
+
+        Parcel data, reply;
+
+        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        outLayers->clear();
+        return reply.readParcelableVector(outLayers);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -540,8 +634,7 @@
         case CAPTURE_SCREEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
-            sp<IGraphicBufferProducer> producer =
-                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
@@ -551,11 +644,30 @@
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
 
-            status_t res = captureScreen(display, producer,
-                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform,
-                    static_cast<ISurfaceComposer::Rotation>(rotation));
+            status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight,
+                                         minLayerZ, maxLayerZ, useIdentityTransform,
+                                         static_cast<ISurfaceComposer::Rotation>(rotation));
             reply->writeInt32(res);
+            if (res == NO_ERROR) {
+                reply->write(*outBuffer);
+            }
+            return NO_ERROR;
+        }
+        case CAPTURE_LAYERS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> layerHandleBinder = data.readStrongBinder();
+            sp<GraphicBuffer> outBuffer;
+            Rect sourceCrop(Rect::EMPTY_RECT);
+            data.read(sourceCrop);
+            float frameScale = data.readFloat();
+            bool childrenOnly = data.readBool();
+
+            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
+                                         childrenOnly);
+            reply->writeInt32(res);
+            if (res == NO_ERROR) {
+                reply->write(*outBuffer);
+            }
             return NO_ERROR;
         }
         case AUTHENTICATE_SURFACE: {
@@ -640,6 +752,26 @@
             }
             return NO_ERROR;
         }
+        case GET_DISPLAY_VIEWPORT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            Rect outViewport;
+            sp<IBinder> display = nullptr;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayViewport failed to readStrongBinder: %d", result);
+                return result;
+            }
+            result = getDisplayViewport(display, &outViewport);
+            result = reply->writeInt32(result);
+            if (result == NO_ERROR) {
+                result = reply->write(outViewport);
+                if (result != NO_ERROR) {
+                    ALOGE("getDisplayViewport failed to write: %d", result);
+                    return result;
+                }
+            }
+            return NO_ERROR;
+        }
         case GET_ACTIVE_CONFIG: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
@@ -657,7 +789,7 @@
         }
         case GET_DISPLAY_COLOR_MODES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<android_color_mode_t> colorModes;
+            Vector<ColorMode> colorModes;
             sp<IBinder> display = nullptr;
             status_t result = data.readStrongBinder(&display);
             if (result != NO_ERROR) {
@@ -669,7 +801,7 @@
             if (result == NO_ERROR) {
                 reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
                 for (size_t i = 0; i < colorModes.size(); ++i) {
-                    reply->writeInt32(colorModes[i]);
+                    reply->writeInt32(static_cast<int32_t>(colorModes[i]));
                 }
             }
             return NO_ERROR;
@@ -682,7 +814,7 @@
                 ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
                 return result;
             }
-            android_color_mode_t colorMode = getActiveColorMode(display);
+            ColorMode colorMode = getActiveColorMode(display);
             result = reply->writeInt32(static_cast<int32_t>(colorMode));
             return result;
         }
@@ -701,7 +833,7 @@
                 return result;
             }
             result = setActiveColorMode(display,
-                    static_cast<android_color_mode_t>(colorModeInt));
+                    static_cast<ColorMode>(colorModeInt));
             result = reply->writeInt32(result);
             return result;
         }
@@ -763,6 +895,17 @@
             }
             return injectVSync(when);
         }
+        case GET_LAYER_DEBUG_INFO: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            std::vector<LayerDebugInfo> outLayers;
+            status_t result = getLayerDebugInfo(&outLayers);
+            reply->writeInt32(result);
+            if (result == NO_ERROR)
+            {
+                result = reply->writeParcelableVector(outLayers);
+            }
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 679f44b..a6890ee 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -47,8 +47,8 @@
     ~BpSurfaceComposerClient() override;
 
     status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
-                           uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                           uint32_t ownerUid, sp<IBinder>* handle,
+                           uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                           int32_t ownerUid, sp<IBinder>* handle,
                            sp<IGraphicBufferProducer>* gbp) override {
         return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                                                                             name, width, height,
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
new file mode 100644
index 0000000..d3dc16d
--- /dev/null
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/LayerDebugInfo.h>
+
+#include <ui/DebugUtils.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/String8.h>
+
+using namespace android;
+
+#define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
+
+namespace android {
+
+status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
+    RETURN_ON_ERROR(parcel->writeCString(mName.c_str()));
+    RETURN_ON_ERROR(parcel->writeCString(mParentName.c_str()));
+    RETURN_ON_ERROR(parcel->writeCString(mType.c_str()));
+    RETURN_ON_ERROR(parcel->write(mTransparentRegion));
+    RETURN_ON_ERROR(parcel->write(mVisibleRegion));
+    RETURN_ON_ERROR(parcel->write(mSurfaceDamageRegion));
+    RETURN_ON_ERROR(parcel->writeUint32(mLayerStack));
+    RETURN_ON_ERROR(parcel->writeFloat(mX));
+    RETURN_ON_ERROR(parcel->writeFloat(mY));
+    RETURN_ON_ERROR(parcel->writeUint32(mZ));
+    RETURN_ON_ERROR(parcel->writeInt32(mWidth));
+    RETURN_ON_ERROR(parcel->writeInt32(mHeight));
+    RETURN_ON_ERROR(parcel->write(mCrop));
+    RETURN_ON_ERROR(parcel->write(mFinalCrop));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.a));
+    RETURN_ON_ERROR(parcel->writeUint32(mFlags));
+    RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
+    RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
+    for (size_t index = 0; index < 4; index++) {
+        RETURN_ON_ERROR(parcel->writeFloat(mMatrix[index / 2][index % 2]));
+    }
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferWidth));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferHeight));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride));
+    RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat));
+    RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames));
+    RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
+    RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
+    RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
+    return NO_ERROR;
+}
+
+status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) {
+    mName = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mParentName = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mType = parcel->readCString();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    RETURN_ON_ERROR(parcel->read(mTransparentRegion));
+    RETURN_ON_ERROR(parcel->read(mVisibleRegion));
+    RETURN_ON_ERROR(parcel->read(mSurfaceDamageRegion));
+    RETURN_ON_ERROR(parcel->readUint32(&mLayerStack));
+    RETURN_ON_ERROR(parcel->readFloat(&mX));
+    RETURN_ON_ERROR(parcel->readFloat(&mY));
+    RETURN_ON_ERROR(parcel->readUint32(&mZ));
+    RETURN_ON_ERROR(parcel->readInt32(&mWidth));
+    RETURN_ON_ERROR(parcel->readInt32(&mHeight));
+    RETURN_ON_ERROR(parcel->read(mCrop));
+    RETURN_ON_ERROR(parcel->read(mFinalCrop));
+    mColor.r = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.g = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.b = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.a = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    RETURN_ON_ERROR(parcel->readUint32(&mFlags));
+    RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
+    // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
+    mDataSpace = static_cast<android_dataspace>(parcel->readUint32());
+    RETURN_ON_ERROR(parcel->errorCheck());
+    for (size_t index = 0; index < 4; index++) {
+        RETURN_ON_ERROR(parcel->readFloat(&mMatrix[index / 2][index % 2]));
+    }
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferWidth));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferHeight));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride));
+    RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat));
+    RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames));
+    RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
+    RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
+    RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
+    return NO_ERROR;
+}
+
+std::string to_string(const LayerDebugInfo& info) {
+    String8 result;
+
+    result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
+    info.mTransparentRegion.dump(result, "TransparentRegion");
+    info.mVisibleRegion.dump(result, "VisibleRegion");
+    info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
+
+    result.appendFormat("      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
+            info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
+            info.mWidth, info.mHeight);
+
+    result.appendFormat("crop=%s, finalCrop=%s, ",
+            to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
+    result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
+    result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
+    result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
+    result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+            static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+            static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+            info.mFlags);
+    result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
+            static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
+            static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
+    result.append("\n");
+    result.appendFormat("      parent=%s\n", info.mParentName.c_str());
+    result.appendFormat("      activeBuffer=[%4ux%4u:%4u,%s],",
+            info.mActiveBufferWidth, info.mActiveBufferHeight,
+            info.mActiveBufferStride,
+            decodePixelFormat(info.mActiveBufferFormat).c_str());
+    result.appendFormat(" queued-frames=%d, mRefreshPending=%d",
+            info.mNumQueuedFrames, info.mRefreshPending);
+    result.append("\n");
+    return std::string(result.c_str());
+}
+
+} // android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9b06e63..01acc2d 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -18,7 +18,7 @@
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/IGraphicBufferProducer.h>
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
@@ -45,6 +45,10 @@
     output.writeInt32(overrideScalingMode);
     output.writeStrongBinder(IInterface::asBinder(barrierGbp));
     output.writeStrongBinder(relativeLayerHandle);
+    output.writeStrongBinder(parentHandleForChild);
+    output.writeFloat(color.r);
+    output.writeFloat(color.g);
+    output.writeFloat(color.b);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -77,6 +81,10 @@
     barrierGbp =
         interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
+    parentHandleForChild = input.readStrongBinder();
+    color.r = input.readFloat();
+    color.g = input.readFloat();
+    color.b = input.readFloat();
     input.read(transparentRegion);
     return NO_ERROR;
 }
@@ -128,5 +136,104 @@
     return NO_ERROR;
 }
 
+void DisplayState::merge(const DisplayState& other) {
+    if (other.what & eSurfaceChanged) {
+        what |= eSurfaceChanged;
+        surface = other.surface;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eDisplayProjectionChanged) {
+        what |= eDisplayProjectionChanged;
+        orientation = other.orientation;
+        viewport = other.viewport;
+        frame = other.frame;
+    }
+    if (other.what & eDisplaySizeChanged) {
+        what |= eDisplaySizeChanged;
+        width = other.width;
+        height = other.height;
+    }
+}
+
+void layer_state_t::merge(const layer_state_t& other) {
+    if (other.what & ePositionChanged) {
+        what |= ePositionChanged;
+        x = other.x;
+        y = other.y;
+    }
+    if (other.what & eLayerChanged) {
+        what |= eLayerChanged;
+        z = other.z;
+    }
+    if (other.what & eSizeChanged) {
+        what |= eSizeChanged;
+        w = other.w;
+        h = other.h;
+    }
+    if (other.what & eAlphaChanged) {
+        what |= eAlphaChanged;
+        alpha = other.alpha;
+    }
+    if (other.what & eMatrixChanged) {
+        what |= eMatrixChanged;
+        matrix = other.matrix;
+    }
+    if (other.what & eTransparentRegionChanged) {
+        what |= eTransparentRegionChanged;
+        transparentRegion = other.transparentRegion;
+    }
+    if (other.what & eFlagsChanged) {
+        what |= eFlagsChanged;
+        flags = other.flags;
+        mask = other.mask;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eDeferTransaction) {
+        what |= eDeferTransaction;
+        barrierHandle = other.barrierHandle;
+        barrierGbp = other.barrierGbp;
+        frameNumber = other.frameNumber;
+    }
+    if (other.what & eFinalCropChanged) {
+        what |= eFinalCropChanged;
+        finalCrop = other.finalCrop;
+    }
+    if (other.what & eOverrideScalingModeChanged) {
+        what |= eOverrideScalingModeChanged;
+        overrideScalingMode = other.overrideScalingMode;
+    }
+    if (other.what & eGeometryAppliesWithResize) {
+        what |= eGeometryAppliesWithResize;
+    }
+    if (other.what & eReparentChildren) {
+        what |= eReparentChildren;
+        reparentHandle = other.reparentHandle;
+    }
+    if (other.what & eDetachChildren) {
+        what |= eDetachChildren;
+    }
+    if (other.what & eRelativeLayerChanged) {
+        what |= eRelativeLayerChanged;
+        z = other.z;
+        relativeLayerHandle = other.relativeLayerHandle;
+    }
+    if (other.what & eReparent) {
+        what |= eReparent;
+        parentHandleForChild = other.parentHandleForChild;
+    }
+    if (other.what & eDestroySurface) {
+        what |= eDestroySurface;
+    }
+}
 
 }; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5b1c599..2de14c8 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,6 +44,9 @@
 
 namespace android {
 
+using ui::ColorMode;
+using ui::Dataspace;
+
 Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
       : mGraphicBufferProducer(bufferProducer),
         mCrop(Rect::EMPTY_RECT),
@@ -78,7 +81,7 @@
     mReqFormat = 0;
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
-    mDataSpace = HAL_DATASPACE_UNKNOWN;
+    mDataSpace = Dataspace::UNKNOWN;
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -153,7 +156,10 @@
     ATRACE_CALL();
 
     DisplayStatInfo stats;
-    status_t err = composerService()->getDisplayStats(NULL, &stats);
+    status_t result = composerService()->getDisplayStats(NULL, &stats);
+    if (result != NO_ERROR) {
+        return result;
+    }
 
     *outRefreshDuration = stats.vsyncPeriod;
 
@@ -323,7 +329,7 @@
 
     sp<IBinder> display(
         composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    Vector<android_color_mode_t> colorModes;
+    Vector<ColorMode> colorModes;
     status_t err =
         composerService()->getDisplayColorModes(display, &colorModes);
 
@@ -335,11 +341,11 @@
                 &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
     *supported = false;
-    for (android_color_mode_t colorMode : colorModes) {
+    for (ColorMode colorMode : colorModes) {
         switch (colorMode) {
-            case HAL_COLOR_MODE_DISPLAY_P3:
-            case HAL_COLOR_MODE_ADOBE_RGB:
-            case HAL_COLOR_MODE_DCI_P3:
+            case ColorMode::DISPLAY_P3:
+            case ColorMode::ADOBE_RGB:
+            case ColorMode::DCI_P3:
                 if (wideColorBoardConfig) {
                     *supported = true;
                 }
@@ -458,8 +464,12 @@
     if (interval > maxSwapInterval)
         interval = maxSwapInterval;
 
+    const bool wasSwapIntervalZero = mSwapIntervalZero;
     mSwapIntervalZero = (interval == 0);
-    mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero);
+
+    if (mSwapIntervalZero != wasSwapIntervalZero) {
+        mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero);
+    }
 
     return NO_ERROR;
 }
@@ -661,8 +671,12 @@
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
-            mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
-            fence, mStickyTransform, mEnableFrameTimestamps);
+            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
+            mTransform ^ mStickyTransform, fence, mStickyTransform,
+            mEnableFrameTimestamps);
+
+    // we should send HDR metadata as needed if this becomes a bottleneck
+    input.setHdrMetadata(mHdrMetadata);
 
     if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
         input.setSurfaceDamage(Region::INVALID_REGION);
@@ -875,6 +889,10 @@
                 *value = mGraphicBufferProducer != nullptr ? 1 : 0;
                 return NO_ERROR;
             }
+            case NATIVE_WINDOW_DATASPACE: {
+                *value = static_cast<int>(mDataSpace);
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
@@ -941,6 +959,12 @@
     case NATIVE_WINDOW_SET_BUFFERS_DATASPACE:
         res = dispatchSetBuffersDataSpace(args);
         break;
+    case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA:
+        res = dispatchSetBuffersSmpte2086Metadata(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA:
+        res = dispatchSetBuffersCta8613Metadata(args);
+        break;
     case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
         res = dispatchSetSurfaceDamage(args);
         break;
@@ -1080,11 +1104,22 @@
 }
 
 int Surface::dispatchSetBuffersDataSpace(va_list args) {
-    android_dataspace dataspace =
-            static_cast<android_dataspace>(va_arg(args, int));
+    Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int));
     return setBuffersDataSpace(dataspace);
 }
 
+int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) {
+    const android_smpte2086_metadata* metadata =
+        va_arg(args, const android_smpte2086_metadata*);
+    return setBuffersSmpte2086Metadata(metadata);
+}
+
+int Surface::dispatchSetBuffersCta8613Metadata(va_list args) {
+    const android_cta861_3_metadata* metadata =
+        va_arg(args, const android_cta861_3_metadata*);
+    return setBuffersCta8613Metadata(metadata);
+}
+
 int Surface::dispatchSetSurfaceDamage(va_list args) {
     android_native_rect_t* rects = va_arg(args, android_native_rect_t*);
     size_t numRects = va_arg(args, size_t);
@@ -1501,7 +1536,7 @@
     return NO_ERROR;
 }
 
-int Surface::setBuffersDataSpace(android_dataspace dataSpace)
+int Surface::setBuffersDataSpace(Dataspace dataSpace)
 {
     ALOGV("Surface::setBuffersDataSpace");
     Mutex::Autolock lock(mMutex);
@@ -1509,6 +1544,36 @@
     return NO_ERROR;
 }
 
+int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) {
+    ALOGV("Surface::setBuffersSmpte2086Metadata");
+    Mutex::Autolock lock(mMutex);
+    if (metadata) {
+        mHdrMetadata.smpte2086 = *metadata;
+        mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
+    } else {
+        mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086;
+    }
+    return NO_ERROR;
+}
+
+int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) {
+    ALOGV("Surface::setBuffersCta8613Metadata");
+    Mutex::Autolock lock(mMutex);
+    if (metadata) {
+        mHdrMetadata.cta8613 = *metadata;
+        mHdrMetadata.validTypes |= HdrMetadata::CTA861_3;
+    } else {
+        mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3;
+    }
+    return NO_ERROR;
+}
+
+Dataspace Surface::getBuffersDataSpace() {
+    ALOGV("Surface::getBuffersDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mDataSpace;
+}
+
 void Surface::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].buffer = 0;
@@ -1751,4 +1816,25 @@
     return OK;
 }
 
+status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+    int err = static_cast<ANativeWindow*>(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT,
+                                                            NATIVE_WINDOW_API_CPU);
+    if (err != OK) {
+        return err;
+    }
+    err = surface->attachBuffer(buffer->getNativeBuffer());
+    if (err != OK) {
+        return err;
+    }
+    err = static_cast<ANativeWindow*>(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1);
+    if (err != OK) {
+        return err;
+    }
+    err = surface->disconnect(NATIVE_WINDOW_API_CPU);
+    return err;
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7ae2672..f3c6fd2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -21,7 +21,6 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include <utils/Singleton.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
@@ -37,13 +36,15 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 namespace android {
+
+using ui::ColorMode;
 // ---------------------------------------------------------------------------
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
@@ -97,233 +98,144 @@
 
 // ---------------------------------------------------------------------------
 
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
-    if (lhs.client < rhs.client)  return -1;
-    if (lhs.client > rhs.client)  return 1;
-    if (lhs.state.surface < rhs.state.surface)  return -1;
-    if (lhs.state.surface > rhs.state.surface)  return 1;
-    return 0;
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
+    mForceSynchronous(other.mForceSynchronous),
+    mTransactionNestCount(other.mTransactionNestCount),
+    mAnimation(other.mAnimation),
+    mEarlyWakeup(other.mEarlyWakeup) {
+    mDisplayStates = other.mDisplayStates;
+    mComposerStates = other.mComposerStates;
 }
 
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
-    return compare_type(lhs.token, rhs.token);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+    for (auto const& kv : other.mComposerStates) {
+        if (mComposerStates.count(kv.first) == 0) {
+            mComposerStates[kv.first] = kv.second;
+        } else {
+            mComposerStates[kv.first].state.merge(kv.second.state);
+        }
+    }
+    other.mComposerStates.clear();
+
+    for (auto const& state : other.mDisplayStates) {
+        ssize_t index = mDisplayStates.indexOf(state);
+        if (index < 0) {
+            mDisplayStates.add(state);
+        } else {
+            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+        }
+    }
+    other.mDisplayStates.clear();
+
+    return *this;
 }
 
-class Composer : public Singleton<Composer>
-{
-    friend class Singleton<Composer>;
-
-    mutable Mutex               mLock;
-    SortedVector<ComposerState> mComposerStates;
-    SortedVector<DisplayState > mDisplayStates;
-    uint32_t                    mForceSynchronous;
-    uint32_t                    mTransactionNestCount;
-    bool                        mAnimation;
-
-    Composer() : Singleton<Composer>(),
-        mForceSynchronous(0), mTransactionNestCount(0),
-        mAnimation(false)
-    { }
-
-    void openGlobalTransactionImpl();
-    void closeGlobalTransactionImpl(bool synchronous);
-    void setAnimationTransactionImpl();
-    status_t enableVSyncInjectionsImpl(bool enable);
-    status_t injectVSyncImpl(nsecs_t when);
-
-    layer_state_t* getLayerStateLocked(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
-
-    DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
-
-public:
-    sp<IBinder> createDisplay(const String8& displayName, bool secure);
-    void destroyDisplay(const sp<IBinder>& display);
-    sp<IBinder> getBuiltInDisplay(int32_t id);
-
-    status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float x, float y);
-    status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t w, uint32_t h);
-    status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            int32_t z);
-    status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t z);
-    status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t flags, uint32_t mask);
-    status_t setTransparentRegionHint(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Region& transparentRegion);
-    status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float alpha);
-    status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t setOrientation(int orientation);
-    status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Rect& crop);
-    status_t setFinalCrop(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const Rect& crop);
-    status_t setLayerStack(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, uint32_t layerStack);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<IBinder>& handle,
-            uint64_t frameNumber);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<Surface>& barrierSurface,
-            uint64_t frameNumber);
-    status_t reparentChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t detachChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-    status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, int32_t overrideScalingMode);
-    status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-
-    status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
-    void setDisplayProjection(const sp<IBinder>& token,
-            uint32_t orientation,
-            const Rect& layerStackRect,
-            const Rect& displayRect);
-    void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    static void setAnimationTransaction() {
-        Composer::getInstance().setAnimationTransactionImpl();
+status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
     }
 
-    static void openGlobalTransaction() {
-        Composer::getInstance().openGlobalTransactionImpl();
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    Vector<ComposerState> composerStates;
+    Vector<DisplayState> displayStates;
+    uint32_t flags = 0;
+
+    mForceSynchronous |= synchronous;
+
+    for (auto const& kv : mComposerStates){
+        composerStates.add(kv.second);
     }
 
-    static void closeGlobalTransaction(bool synchronous) {
-        Composer::getInstance().closeGlobalTransactionImpl(synchronous);
+    mComposerStates.clear();
+
+    displayStates = mDisplayStates;
+    mDisplayStates.clear();
+
+    if (mForceSynchronous) {
+        flags |= ISurfaceComposer::eSynchronous;
+    }
+    if (mAnimation) {
+        flags |= ISurfaceComposer::eAnimation;
+    }
+    if (mEarlyWakeup) {
+        flags |= ISurfaceComposer::eEarlyWakeup;
     }
 
-    static status_t enableVSyncInjections(bool enable) {
-        return Composer::getInstance().enableVSyncInjectionsImpl(enable);
-    }
+    mForceSynchronous = false;
+    mAnimation = false;
+    mEarlyWakeup = false;
 
-    static status_t injectVSync(nsecs_t when) {
-        return Composer::getInstance().injectVSyncImpl(when);
-    }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
+    sf->setTransactionState(composerStates, displayStates, flags);
+    mStatus = NO_ERROR;
+    return NO_ERROR;
+}
 
 // ---------------------------------------------------------------------------
 
-sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) {
+sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
     return ComposerService::getComposerService()->createDisplay(displayName,
             secure);
 }
 
-void Composer::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->destroyDisplay(display);
 }
 
-sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
+sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
     return ComposerService::getComposerService()->getBuiltInDisplay(id);
 }
 
-void Composer::openGlobalTransactionImpl() {
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mTransactionNestCount += 1;
-    }
-}
-
-void Composer::closeGlobalTransactionImpl(bool synchronous) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-
-    Vector<ComposerState> transaction;
-    Vector<DisplayState> displayTransaction;
-    uint32_t flags = 0;
-
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mForceSynchronous |= synchronous;
-        if (!mTransactionNestCount) {
-            ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
-                    "call to openGlobalTransaction().");
-        } else if (--mTransactionNestCount) {
-            return;
-        }
-
-        transaction = mComposerStates;
-        mComposerStates.clear();
-
-        displayTransaction = mDisplayStates;
-        mDisplayStates.clear();
-
-        if (mForceSynchronous) {
-            flags |= ISurfaceComposer::eSynchronous;
-        }
-        if (mAnimation) {
-            flags |= ISurfaceComposer::eAnimation;
-        }
-
-        mForceSynchronous = false;
-        mAnimation = false;
-    }
-
-   sm->setTransactionState(transaction, displayTransaction, flags);
-}
-
-status_t Composer::enableVSyncInjectionsImpl(bool enable) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->enableVSyncInjections(enable);
-}
-
-status_t Composer::injectVSyncImpl(nsecs_t when) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->injectVSync(when);
-}
-
-void Composer::setAnimationTransactionImpl() {
-    Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setAnimationTransaction() {
     mAnimation = true;
 }
 
-layer_state_t* Composer::getLayerStateLocked(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
-
-    ComposerState s;
-    s.client = client->mClient;
-    s.state.surface = id;
-
-    ssize_t index = mComposerStates.indexOf(s);
-    if (index < 0) {
-        // we don't have it, add an initialized layer_state to our list
-        index = mComposerStates.add(s);
-    }
-
-    ComposerState* const out = mComposerStates.editArray();
-    return &(out[index].state);
+void SurfaceComposerClient::Transaction::setEarlyWakeup() {
+    mEarlyWakeup = true;
 }
 
-status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float x, float y) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
+    if (mComposerStates.count(sc) == 0) {
+        // we don't have it, add an initialized layer_state to our list
+        ComposerState s;
+        s.client = sc->getClient()->mClient;
+        s.state.surface = sc->getHandle();
+        mComposerStates[sc] = s;
+    }
+
+    return &(mComposerStates[sc].state);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
+        const sp<SurfaceControl>& sc, float x, float y) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::ePositionChanged;
     s->x = x;
     s->y = y;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, 0, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize(
+        const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eSizeChanged;
     s->w = w;
     s->h = h;
@@ -331,41 +243,41 @@
     // Resizing a surface makes the transaction synchronous.
     mForceSynchronous = true;
 
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer(
+        const sp<SurfaceControl>& sc, int32_t z) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerChanged;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo,
         int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eRelativeLayerChanged;
     s->relativeLayerHandle = relativeTo;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t flags,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags(
+        const sp<SurfaceControl>& sc, uint32_t flags,
         uint32_t mask) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     if ((mask & layer_state_t::eLayerOpaque) ||
             (mask & layer_state_t::eLayerHidden) ||
             (mask & layer_state_t::eLayerSecure)) {
@@ -374,50 +286,54 @@
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setTransparentRegionHint(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint(
+        const sp<SurfaceControl>& sc,
         const Region& transparentRegion) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float alpha) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
+        const sp<SurfaceControl>& sc, float alpha) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eAlphaChanged;
     s->alpha = alpha;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
+        const sp<SurfaceControl>& sc, uint32_t layerStack) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerStackChanged;
     s->layerStack = layerStack;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float dsdx, float dtdx,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix(
+        const sp<SurfaceControl>& sc, float dsdx, float dtdx,
         float dtdy, float dsdy) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eMatrixChanged;
     layer_state_t::matrix22_t matrix;
     matrix.dsdx = dsdx;
@@ -425,93 +341,115 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eCropChanged;
     s->crop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eFinalCropChanged;
     s->finalCrop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& handle, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierHandle = handle;
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::reparentChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& newParentHandle) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eReparentChildren;
     s->reparentHandle = newParentHandle;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::detachChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
+        const sp<SurfaceControl>& sc,
+        const sp<IBinder>& newParentHandle) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eReparent;
+    s->parentHandleForChild = newParentHandle;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor(
+        const sp<SurfaceControl>& sc,
+        const half3& color) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorChanged;
+    s->color = color;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eDetachChildren;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setOverrideScalingMode(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
+        const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
 
     switch (overrideScalingMode) {
@@ -524,29 +462,40 @@
         default:
             ALOGE("unknown scaling mode: %d",
                     overrideScalingMode);
-            return BAD_VALUE;
+            mStatus = BAD_VALUE;
+            return *this;
     }
 
     s->what |= layer_state_t::eOverrideScalingModeChanged;
     s->overrideScalingMode = overrideScalingMode;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setGeometryAppliesWithResize(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eGeometryAppliesWithResize;
-    return NO_ERROR;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDestroySurface;
+    return *this;
 }
 
 // ---------------------------------------------------------------------------
 
-DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
     DisplayState s;
     s.token = token;
     ssize_t index = mDisplayStates.indexOf(s);
@@ -558,8 +507,8 @@
     return mDisplayStates.editItemAt(static_cast<size_t>(index));
 }
 
-status_t Composer::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
+status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
+        const sp<IGraphicBufferProducer>& bufferProducer) {
     if (bufferProducer.get() != nullptr) {
         // Make sure that composition can never be stalled by a virtual display
         // consumer that isn't processing buffers fast enough.
@@ -571,27 +520,24 @@
             return err;
         }
     }
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.surface = bufferProducer;
     s.what |= DisplayState::eSurfaceChanged;
     return NO_ERROR;
 }
 
-void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
         uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.layerStack = layerStack;
     s.what |= DisplayState::eLayerStackChanged;
 }
 
-void Composer::setDisplayProjection(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
         uint32_t orientation,
         const Rect& layerStackRect,
         const Rect& displayRect) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.orientation = orientation;
     s.viewport = layerStackRect;
     s.frame = displayRect;
@@ -599,9 +545,8 @@
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
-void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
+    DisplayState& s(getDisplayState(token));
     s.width = width;
     s.height = height;
     s.what |= DisplayState::eDisplaySizeChanged;
@@ -610,22 +555,27 @@
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::SurfaceComposerClient()
-    : mStatus(NO_INIT), mComposer(Composer::getInstance())
+    : mStatus(NO_INIT)
 {
 }
 
 SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
-    : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root)
+    : mStatus(NO_INIT), mParent(root)
+{
+}
+
+SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
+    : mStatus(NO_ERROR), mClient(client)
 {
 }
 
 void SurfaceComposerClient::onFirstRef() {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    if (sm != 0) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    if (sf != 0 && mStatus == NO_INIT) {
         auto rootProducer = mParent.promote();
         sp<ISurfaceComposerClient> conn;
-        conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
-                sm->createConnection();
+        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
+                sf->createConnection();
         if (conn != 0) {
             mClient = conn;
             mStatus = NO_ERROR;
@@ -648,8 +598,8 @@
 status_t SurfaceComposerClient::linkToComposerDeath(
         const sp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags);
 }
 
 void SurfaceComposerClient::dispose() {
@@ -670,10 +620,28 @@
         PixelFormat format,
         uint32_t flags,
         SurfaceControl* parent,
-        uint32_t windowType,
-        uint32_t ownerUid)
+        int32_t windowType,
+        int32_t ownerUid)
+{
+    sp<SurfaceControl> s;
+    createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+    return s;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(
+        const String8& name,
+        uint32_t w,
+        uint32_t h,
+        PixelFormat format,
+        sp<SurfaceControl>* outSurface,
+        uint32_t flags,
+        SurfaceControl* parent,
+        int32_t windowType,
+        int32_t ownerUid)
 {
     sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
     if (mStatus == NO_ERROR) {
         sp<IBinder> handle;
         sp<IBinder> parentHandle;
@@ -682,27 +650,14 @@
         if (parent != nullptr) {
             parentHandle = parent->getHandle();
         }
-        status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
+        err = mClient->createSurface(name, w, h, format, flags, parentHandle,
                 windowType, ownerUid, &handle, &gbp);
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            sur = new SurfaceControl(this, handle, gbp);
+            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
         }
     }
-    return sur;
-}
-
-sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
-        bool secure) {
-    return Composer::getInstance().createDisplay(displayName, secure);
-}
-
-void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
-    Composer::getInstance().destroyDisplay(display);
-}
-
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
-    return Composer::getInstance().getBuiltInDisplay(id);
+    return err;
 }
 
 status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
@@ -727,152 +682,18 @@
     return mClient->getLayerFrameStats(token, outStats);
 }
 
-inline Composer& SurfaceComposerClient::getComposer() {
-    return mComposer;
-}
-
 // ----------------------------------------------------------------------------
 
-void SurfaceComposerClient::openGlobalTransaction() {
-    Composer::openGlobalTransaction();
-}
-
-void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
-    Composer::closeGlobalTransaction(synchronous);
-}
-
-void SurfaceComposerClient::setAnimationTransaction() {
-    Composer::setAnimationTransaction();
-}
-
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
-    return Composer::enableVSyncInjections(enable);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->enableVSyncInjections(enable);
 }
 
 status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
-    return Composer::injectVSync(when);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->injectVSync(when);
 }
 
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
-    return getComposer().setCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id,
-        const Rect& crop) {
-    return getComposer().setFinalCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
-    return getComposer().setPosition(this, id, x, y);
-}
-
-status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    return getComposer().setSize(this, id, w, h);
-}
-
-status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
-    return getComposer().setLayer(this, id, z);
-}
-
-status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
-        const sp<IBinder>& relativeTo, int32_t z) {
-    return getComposer().setRelativeLayer(this, id, relativeTo, z);
-}
-
-status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            layer_state_t::eLayerHidden,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            0,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags,
-        uint32_t mask) {
-    return getComposer().setFlags(this, id, flags, mask);
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id,
-        const Region& transparentRegion) {
-    return getComposer().setTransparentRegionHint(this, id, transparentRegion);
-}
-
-status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) {
-    return getComposer().setAlpha(this, id, alpha);
-}
-
-status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
-    return getComposer().setLayerStack(this, id, layerStack);
-}
-
-status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
-        float dtdy, float dsdy) {
-    return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<IBinder>& handle, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber);
-}
-
-status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id,
-        const sp<IBinder>& newParentHandle) {
-    return getComposer().reparentChildren(this, id, newParentHandle);
-}
-
-status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
-    return getComposer().detachChildren(this, id);
-}
-
-status_t SurfaceComposerClient::setOverrideScalingMode(
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    return getComposer().setOverrideScalingMode(
-            this, id, overrideScalingMode);
-}
-
-status_t SurfaceComposerClient::setGeometryAppliesWithResize(
-        const sp<IBinder>& id) {
-    return getComposer().setGeometryAppliesWithResize(this, id);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
-    return Composer::getInstance().setDisplaySurface(token, bufferProducer);
-}
-
-void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
-        uint32_t layerStack) {
-    Composer::getInstance().setDisplayLayerStack(token, layerStack);
-}
-
-void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
-        uint32_t orientation,
-        const Rect& layerStackRect,
-        const Rect& displayRect) {
-    Composer::getInstance().setDisplayProjection(token, orientation,
-            layerStackRect, displayRect);
-}
-
-void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token,
-        uint32_t width, uint32_t height) {
-    Composer::getInstance().setDisplaySize(token, width, height);
-}
-
-// ----------------------------------------------------------------------------
-
 status_t SurfaceComposerClient::getDisplayConfigs(
         const sp<IBinder>& display, Vector<DisplayInfo>* configs)
 {
@@ -897,6 +718,10 @@
     return NO_ERROR;
 }
 
+status_t SurfaceComposerClient::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+    return ComposerService::getComposerService()->getDisplayViewport(display, outViewport);
+}
+
 int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveConfig(display);
 }
@@ -906,16 +731,16 @@
 }
 
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
+        Vector<ColorMode>* outColorModes) {
     return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
 }
 
-android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveColorMode(display);
 }
 
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
+        ColorMode colorMode) {
     return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
 }
 
@@ -940,149 +765,37 @@
 
 // ----------------------------------------------------------------------------
 
-status_t ScreenshotClient::capture(
-        const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
+                                   uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
+                                   bool useIdentityTransform, uint32_t rotation,
+                                   sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
-    return s->captureScreen(display, producer, sourceCrop,
-            reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
-}
-
-status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
-        uint32_t rotation,
-        sp<GraphicBuffer>* outBuffer) {
-    sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
-
-    sp<IGraphicBufferConsumer> gbpConsumer;
-    sp<IGraphicBufferProducer> producer;
-    BufferQueue::createBufferQueue(&producer, &gbpConsumer);
-    sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
-           GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER,
-           1, true));
-
-    status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight,
-            minLayerZ, maxLayerZ, useIdentityTransform,
-            static_cast<ISurfaceComposer::Rotation>(rotation));
+    status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ,
+                                    maxLayerZ, useIdentityTransform,
+                                    static_cast<ISurfaceComposer::Rotation>(rotation));
     if (ret != NO_ERROR) {
         return ret;
     }
-    BufferItem b;
-    consumer->acquireBuffer(&b, 0, true);
-    *outBuffer = b.mGraphicBuffer;
     return ret;
 }
 
-ScreenshotClient::ScreenshotClient()
-    : mHaveBuffer(false) {
-    memset(&mBuffer, 0, sizeof(mBuffer));
-}
-
-ScreenshotClient::~ScreenshotClient() {
-    ScreenshotClient::release();
-}
-
-sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
-    if (mCpuConsumer == NULL) {
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&mProducer, &consumer);
-        mCpuConsumer = new CpuConsumer(consumer, 1);
-        mCpuConsumer->setName(String8("ScreenshotClient"));
-    }
-    return mCpuConsumer;
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, uint32_t rotation) {
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                         float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
-    sp<CpuConsumer> cpuConsumer = getCpuConsumer();
-
-    if (mHaveBuffer) {
-        mCpuConsumer->unlockBuffer(mBuffer);
-        memset(&mBuffer, 0, sizeof(mBuffer));
-        mHaveBuffer = false;
-    }
-
-    status_t err = s->captureScreen(display, mProducer, sourceCrop,
-            reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
-            static_cast<ISurfaceComposer::Rotation>(rotation));
-
-    if (err == NO_ERROR) {
-        err = mCpuConsumer->lockNextBuffer(&mBuffer);
-        if (err == NO_ERROR) {
-            mHaveBuffer = true;
-        }
-    }
-    return err;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    false /* childrenOnly */);
+    return ret;
 }
 
-status_t ScreenshotClient::update(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform) {
-
-    return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
-            minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone);
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                              float frameScale, sp<GraphicBuffer>* outBuffer) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    true /* childrenOnly */);
+    return ret;
 }
-
-status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
-        bool useIdentityTransform) {
-    return ScreenshotClient::update(display, sourceCrop, 0, 0,
-            INT32_MIN, INT32_MAX,
-            useIdentityTransform, ISurfaceComposer::eRotateNone);
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
-        uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) {
-    return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
-            INT32_MIN, INT32_MAX,
-            useIdentityTransform, ISurfaceComposer::eRotateNone);
-}
-
-void ScreenshotClient::release() {
-    if (mHaveBuffer) {
-        mCpuConsumer->unlockBuffer(mBuffer);
-        memset(&mBuffer, 0, sizeof(mBuffer));
-        mHaveBuffer = false;
-    }
-    mCpuConsumer.clear();
-}
-
-void const* ScreenshotClient::getPixels() const {
-    return mBuffer.data;
-}
-
-uint32_t ScreenshotClient::getWidth() const {
-    return mBuffer.width;
-}
-
-uint32_t ScreenshotClient::getHeight() const {
-    return mBuffer.height;
-}
-
-PixelFormat ScreenshotClient::getFormat() const {
-    return mBuffer.format;
-}
-
-uint32_t ScreenshotClient::getStride() const {
-    return mBuffer.stride;
-}
-
-size_t ScreenshotClient::getSize() const {
-    return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
-}
-
-android_dataspace ScreenshotClient::getDataSpace() const {
-    return mBuffer.dataSpace;
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 58bd273..5eafbb3 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -48,8 +48,9 @@
 SurfaceControl::SurfaceControl(
         const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& handle,
-        const sp<IGraphicBufferProducer>& gbp)
-    : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
+        const sp<IGraphicBufferProducer>& gbp,
+        bool owned)
+    : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned)
 {
 }
 
@@ -60,7 +61,9 @@
 
 void SurfaceControl::destroy()
 {
-    if (isValid()) {
+    // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
+    // retrieved it from another process.
+    if (isValid() && mOwned) {
         mClient->destroySurface(mHandle);
     }
     // clear all references and trigger an IPC now, to make sure things
@@ -97,112 +100,6 @@
     return lhs->mHandle == rhs->mHandle;
 }
 
-status_t SurfaceControl::setLayerStack(uint32_t layerStack) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayerStack(mHandle, layerStack);
-}
-
-status_t SurfaceControl::setLayer(int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayer(mHandle, layer);
-}
-
-status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setRelativeLayer(mHandle, relativeTo, layer);
-}
-
-status_t SurfaceControl::setPosition(float x, float y) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setPosition(mHandle, x, y);
-}
-status_t SurfaceControl::setGeometryAppliesWithResize() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setGeometryAppliesWithResize(mHandle);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setSize(mHandle, w, h);
-}
-status_t SurfaceControl::hide() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->hide(mHandle);
-}
-status_t SurfaceControl::show() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->show(mHandle);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFlags(mHandle, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setTransparentRegionHint(mHandle, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setAlpha(mHandle, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setCrop(mHandle, crop);
-}
-status_t SurfaceControl::setFinalCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFinalCrop(mHandle, crop);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->reparentChildren(mHandle, newParentHandle);
-}
-
-status_t SurfaceControl::detachChildren() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->detachChildren(mHandle);
-}
-
-status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
-}
-
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
     if (err < 0) return err;
@@ -267,5 +164,35 @@
     return mHandle;
 }
 
+sp<SurfaceComposerClient> SurfaceControl::getClient() const
+{
+    return mClient;
+}
+
+void SurfaceControl::writeToParcel(Parcel* parcel)
+{
+    parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient()));
+    parcel->writeStrongBinder(mHandle);
+    parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
+}
+
+sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel)
+{
+    sp<IBinder> client = parcel->readStrongBinder();
+    sp<IBinder> handle = parcel->readStrongBinder();
+    if (client == nullptr || handle == nullptr)
+    {
+        ALOGE("Invalid parcel");
+        return nullptr;
+    }
+    sp<IBinder> gbp;
+    parcel->readNullableStrongBinder(&gbp);
+
+    // We aren't the original owner of the surface.
+    return new SurfaceControl(new SurfaceComposerClient(
+                    interface_cast<ISurfaceComposerClient>(client)),
+            handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */);
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
new file mode 100644
index 0000000..d380770
--- /dev/null
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_
+#define ANDROID_GUI_BUFFERHUBCONSUMER_H_
+
+#include <gui/IGraphicBufferConsumer.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
+
+namespace android {
+
+class BufferHubConsumer : public IGraphicBufferConsumer {
+public:
+    // Creates a BufferHubConsumer instance by importing an existing producer queue.
+    static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue);
+
+    // Creates a BufferHubConsumer instance by importing an existing producer
+    // parcelable. Note that this call takes the ownership of the parcelable
+    // object and is guaranteed to succeed if parcelable object is valid.
+    static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable);
+
+    // See |IGraphicBufferConsumer::acquireBuffer|
+    status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+                           uint64_t maxFrameNumber = 0) override;
+
+    // See |IGraphicBufferConsumer::detachBuffer|
+    status_t detachBuffer(int slot) override;
+
+    // See |IGraphicBufferConsumer::attachBuffer|
+    status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override;
+
+    // See |IGraphicBufferConsumer::releaseBuffer|
+    status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence,
+                           const sp<Fence>& releaseFence) override;
+
+    // See |IGraphicBufferConsumer::consumerConnect|
+    status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override;
+
+    // See |IGraphicBufferConsumer::consumerDisconnect|
+    status_t consumerDisconnect() override;
+
+    // See |IGraphicBufferConsumer::getReleasedBuffers|
+    status_t getReleasedBuffers(uint64_t* slotMask) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferSize|
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+    // See |IGraphicBufferConsumer::setMaxBufferCount|
+    status_t setMaxBufferCount(int bufferCount) override;
+
+    // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount|
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
+
+    // See |IGraphicBufferConsumer::setConsumerName|
+    status_t setConsumerName(const String8& name) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferFormat|
+    status_t setDefaultBufferFormat(PixelFormat defaultFormat) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferDataSpace|
+    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override;
+
+    // See |IGraphicBufferConsumer::setConsumerUsageBits|
+    status_t setConsumerUsageBits(uint64_t usage) override;
+
+    // See |IGraphicBufferConsumer::setConsumerIsProtected|
+    status_t setConsumerIsProtected(bool isProtected) override;
+
+    // See |IGraphicBufferConsumer::setTransformHint|
+    status_t setTransformHint(uint32_t hint) override;
+
+    // See |IGraphicBufferConsumer::getSidebandStream|
+    status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
+
+    // See |IGraphicBufferConsumer::getOccupancyHistory|
+    status_t getOccupancyHistory(bool forceFlush,
+                                 std::vector<OccupancyTracker::Segment>* outHistory) override;
+
+    // See |IGraphicBufferConsumer::discardFreeBuffers|
+    status_t discardFreeBuffers() override;
+
+    // See |IGraphicBufferConsumer::dumpState|
+    status_t dumpState(const String8& prefix, String8* outResult) const override;
+
+    // BufferHubConsumer provides its own logic to cast to a binder object.
+    IBinder* onAsBinder() override;
+
+private:
+    // Private constructor to force use of |Create|.
+    BufferHubConsumer() = default;
+
+    // Concrete implementation backed by BufferHubBuffer.
+    std::shared_ptr<dvr::ConsumerQueue> mQueue;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
new file mode 100644
index 0000000..23c9909
--- /dev/null
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_
+#define ANDROID_GUI_BUFFERHUBPRODUCER_H_
+
+#include <gui/BufferSlot.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
+
+namespace android {
+
+class BufferHubProducer : public IGraphicBufferProducer {
+public:
+    static constexpr int kNoConnectedApi = -1;
+
+    // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
+    // side logic doesn't limit the number of buffer it can acquire
+    // simultaneously. We need a way for consumer logic to configure and enforce
+    // that.
+    static constexpr int kDefaultUndequeuedBuffers = 1;
+
+    // Creates a BufferHubProducer instance by importing an existing prodcuer
+    // queue.
+    static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer);
+
+    // Creates a BufferHubProducer instance by importing an existing prodcuer
+    // parcelable. Note that this call takes the ownership of the parcelable
+    // object and is guaranteed to succeed if parcelable object is valid.
+    static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable);
+
+    // See |IGraphicBufferProducer::requestBuffer|
+    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+
+    // For the BufferHub based implementation. All buffers in the queue are
+    // allowed to be dequeued from the consumer side. It call always returns
+    // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
+    // |max_dequeued_buffers| here can be considered the same as setting queue
+    // capacity.
+    //
+    // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
+    status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
+
+    // See |IGraphicBufferProducer::setAsyncMode|
+    status_t setAsyncMode(bool async) override;
+
+    // See |IGraphicBufferProducer::dequeueBuffer|
+    status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
+                           PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                           FrameEventHistoryDelta* outTimestamps) override;
+
+    // See |IGraphicBufferProducer::detachBuffer|
+    status_t detachBuffer(int slot) override;
+
+    // See |IGraphicBufferProducer::detachNextBuffer|
+    status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override;
+
+    // See |IGraphicBufferProducer::attachBuffer|
+    status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override;
+
+    // See |IGraphicBufferProducer::queueBuffer|
+    status_t queueBuffer(int slot, const QueueBufferInput& input,
+                         QueueBufferOutput* output) override;
+
+    // See |IGraphicBufferProducer::cancelBuffer|
+    status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+
+    // See |IGraphicBufferProducer::query|
+    status_t query(int what, int* out_value) override;
+
+    // See |IGraphicBufferProducer::connect|
+    status_t connect(const sp<IProducerListener>& listener, int api,
+                     bool producer_controlled_by_app, QueueBufferOutput* output) override;
+
+    // See |IGraphicBufferProducer::disconnect|
+    status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override;
+
+    // See |IGraphicBufferProducer::setSidebandStream|
+    status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+
+    // See |IGraphicBufferProducer::allocateBuffers|
+    void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
+                         uint64_t usage) override;
+
+    // See |IGraphicBufferProducer::allowAllocation|
+    status_t allowAllocation(bool allow) override;
+
+    // See |IGraphicBufferProducer::setGenerationNumber|
+    status_t setGenerationNumber(uint32_t generation_number) override;
+
+    // See |IGraphicBufferProducer::getConsumerName|
+    String8 getConsumerName() const override;
+
+    // See |IGraphicBufferProducer::setSharedBufferMode|
+    status_t setSharedBufferMode(bool shared_buffer_mode) override;
+
+    // See |IGraphicBufferProducer::setAutoRefresh|
+    status_t setAutoRefresh(bool auto_refresh) override;
+
+    // See |IGraphicBufferProducer::setDequeueTimeout|
+    status_t setDequeueTimeout(nsecs_t timeout) override;
+
+    // See |IGraphicBufferProducer::getLastQueuedBuffer|
+    status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence,
+                                 float out_transform_matrix[16]) override;
+
+    // See |IGraphicBufferProducer::getFrameTimestamps|
+    void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
+
+    // See |IGraphicBufferProducer::getUniqueId|
+    status_t getUniqueId(uint64_t* out_id) const override;
+
+    // See |IGraphicBufferProducer::getConsumerUsage|
+    status_t getConsumerUsage(uint64_t* out_usage) const override;
+
+    // Takes out the current producer as a binder parcelable object. Note that the
+    // producer must be disconnected to be exportable. After successful export,
+    // the producer queue can no longer be connected again. Returns NO_ERROR when
+    // takeout is successful and out_parcelable will hold the new parcelable
+    // object. Also note that out_parcelable cannot be NULL and must points to an
+    // invalid parcelable.
+    status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable);
+
+    IBinder* onAsBinder() override;
+
+protected:
+    // See |IGraphicBufferProducer::exportToParcel|
+    status_t exportToParcel(Parcel* parcel) override;
+
+private:
+    using LocalHandle = pdx::LocalHandle;
+
+    // Private constructor to force use of |Create|.
+    BufferHubProducer() {}
+
+    static uint64_t genUniqueId() {
+        static std::atomic<uint32_t> counter{0};
+        static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
+        return id | counter++;
+    }
+
+    // Allocate new buffer through BufferHub and add it into |queue_| for
+    // bookkeeping.
+    status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                            PixelFormat format, uint64_t usage);
+
+    // Remove a buffer via BufferHubRPC.
+    status_t RemoveBuffer(size_t slot);
+
+    // Free all buffers which are owned by the prodcuer. Note that if graphic
+    // buffers are acquired by the consumer, we can't .
+    status_t FreeAllBuffers();
+
+    // Concreate implementation backed by BufferHubBuffer.
+    std::shared_ptr<dvr::ProducerQueue> queue_;
+
+    // Mutex for thread safety.
+    std::mutex mutex_;
+
+    // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
+    int connected_api_{kNoConnectedApi};
+
+    // |max_buffer_count_| sets the capacity of the underlying buffer queue.
+    int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity};
+
+    // |max_dequeued_buffer_count_| set the maximum number of buffers that can
+    // be dequeued at the same momment.
+    int32_t max_dequeued_buffer_count_{1};
+
+    // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
+    // slot is not yet available. The timeout is stored in milliseconds.
+    int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut};
+
+    // |generation_number_| stores the current generation number of the attached
+    // producer. Any attempt to attach a buffer with a different generation
+    // number will fail.
+    // TOOD(b/38137191) Currently not used as we don't support
+    // IGraphicBufferProducer::detachBuffer.
+    uint32_t generation_number_{0};
+
+    // |buffers_| stores the buffers that have been dequeued from
+    // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
+    // filled in with the result of |Dequeue|.
+    // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
+    // requested buffer usage or geometry differs from that of the buffer
+    // allocated to a slot.
+    struct BufferHubSlot : public BufferSlot {
+        BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
+        // BufferSlot comes from android framework, using m prefix to comply with
+        // the name convention with the reset of data fields from BufferSlot.
+        std::shared_ptr<dvr::BufferProducer> mBufferProducer;
+        bool mIsReallocating;
+    };
+    BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
+
+    // A uniqueId used by IGraphicBufferProducer interface.
+    const uint64_t unique_id_{genUniqueId()};
+
+    // A pending parcelable object which keeps the bufferhub channel alive.
+    dvr::ProducerQueueParcelable pending_producer_parcelable_;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_
diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
index 55637a9..218bb42 100644
--- a/libs/gui/include/gui/BufferItem.h
+++ b/libs/gui/include/gui/BufferItem.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GUI_BUFFERITEM_H
 #define ANDROID_GUI_BUFFERITEM_H
 
+#include <gui/HdrMetadata.h>
+
 #include <ui/FenceTime.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -86,6 +88,9 @@
     // dataSpace is format-dependent.
     android_dataspace mDataSpace;
 
+    // mHdrMetadata is the HDR metadata associated with this buffer slot.
+    HdrMetadata mHdrMetadata;
+
     // mFrameNumber is the number of the queued frame for this slot.
     uint64_t mFrameNumber;
 
@@ -122,6 +127,9 @@
     // Indicates that this BufferItem contains a stale buffer which has already
     // been released by the BufferQueue.
     bool mIsStale;
+
+    // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+    int mApi;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index d9c5775..a905610 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -57,10 +57,6 @@
 
     ~BufferItemConsumer() override;
 
-    // set the name of the BufferItemConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
     // setBufferFreedListener sets the listener object that will be notified
     // when an old buffer is being freed.
     void setBufferFreedListener(const wp<BufferFreedListener>& listener);
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index ba5cbf7..da95274 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -79,6 +79,12 @@
             sp<IGraphicBufferConsumer>* outConsumer,
             bool consumerIsSurfaceFlinger = false);
 
+#ifndef NO_BUFFERHUB
+    // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub.
+    static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
+                                     sp<IGraphicBufferConsumer>* outConsumer);
+#endif
+
     BufferQueue() = delete; // Create through createBufferQueue
 };
 
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index e9fc8fd..366ced3 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -89,6 +89,18 @@
     // See IGraphicBufferConsumer::setDefaultBufferDataSpace
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
 
+    // See IGraphicBufferConsumer::setConsumerUsageBits
+    status_t setConsumerUsageBits(uint64_t usage);
+
+    // See IGraphicBufferConsumer::setTransformHint
+    status_t setTransformHint(uint32_t hint);
+
+    // See IGraphicBufferConsumer::setMaxAcquiredBufferCount
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // See IGraphicBufferConsumer::getSidebandStream
+    sp<NativeHandle> getSidebandStream() const;
+
     // See IGraphicBufferConsumer::getOccupancyHistory
     status_t getOccupancyHistory(bool forceFlush,
             std::vector<OccupancyTracker::Segment>* outHistory);
@@ -187,7 +199,7 @@
     // ConsumerBase::releaseBufferLocked.
     virtual status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer,
-            EGLDisplay display, EGLSyncKHR eglFence);
+            EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
 
     // returns true iff the slot still has the graphicBuffer in it.
     bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index 58602bf..d375611 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -94,12 +94,6 @@
     CpuConsumer(const sp<IGraphicBufferConsumer>& bq,
             size_t maxLockedBuffers, bool controlledByApp = false);
 
-    virtual ~CpuConsumer();
-
-    // set the name of the CpuConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
     // Gets the next graphics buffer from the producer and locks it for CPU use,
     // filling out the passed-in locked buffer structure with the native pointer
     // and metadata. Returns BAD_VALUE if no new buffer is available, and
@@ -119,31 +113,39 @@
 
   private:
     // Maximum number of buffers that can be locked at a time
-    size_t mMaxLockedBuffers;
-
-    status_t releaseAcquiredBufferLocked(size_t lockedIdx);
-
-    virtual void freeBufferLocked(int slotIndex);
+    const size_t mMaxLockedBuffers;
 
     // Tracking for buffers acquired by the user
     struct AcquiredBuffer {
+        static constexpr uintptr_t kUnusedId = 0;
+
         // Need to track the original mSlot index and the buffer itself because
         // the mSlot entry may be freed/reused before the acquired buffer is
         // released.
         int mSlot;
         sp<GraphicBuffer> mGraphicBuffer;
-        void *mBufferPointer;
+        uintptr_t mLockedBufferId;
 
         AcquiredBuffer() :
                 mSlot(BufferQueue::INVALID_BUFFER_SLOT),
-                mBufferPointer(NULL) {
+                mLockedBufferId(kUnusedId) {
+        }
+
+        void reset() {
+            mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+            mGraphicBuffer.clear();
+            mLockedBufferId = kUnusedId;
         }
     };
+
+    size_t findAcquiredBufferLocked(uintptr_t id) const;
+
+    status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const;
+
     Vector<AcquiredBuffer> mAcquiredBuffers;
 
     // Count of currently locked buffers
     size_t mCurrentLockedBuffers;
-
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 75f2cca..71ed3bf 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -138,6 +138,10 @@
             const sp<GraphicBuffer>& buf, const Rect& cropRect,
             uint32_t transform, bool filtering);
 
+    // Scale the crop down horizontally or vertically such that it has the
+    // same aspect ratio as the buffer does.
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
     //
@@ -197,22 +201,9 @@
     // buffer is ready to be read from.
     std::shared_ptr<FenceTime> getCurrentFenceTime() const;
 
-    // doGLFenceWait inserts a wait command into the OpenGL ES command stream
-    // to ensure that it is safe for future OpenGL ES commands to access the
-    // current texture buffer.
-    status_t doGLFenceWait() const;
-
-    // set the name of the GLConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
-    // These functions call the corresponding BufferQueue implementation
-    // so the refactoring can proceed smoothly
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
+    // setConsumerUsageBits overrides the ConsumerBase method to OR
+    // DEFAULT_USAGE_FLAGS to usage.
     status_t setConsumerUsageBits(uint64_t usage);
-    status_t setTransformHint(uint32_t hint);
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // detachFromContext detaches the GLConsumer from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
@@ -267,8 +258,6 @@
         return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence);
     }
 
-    static bool isExternalFormat(PixelFormat format);
-
     struct PendingRelease {
         PendingRelease() : isPending(false), currentTexture(-1),
                 graphicBuffer(), display(nullptr), fence(nullptr) {}
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
new file mode 100644
index 0000000..9800602
--- /dev/null
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <system/graphics.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct HdrMetadata : public LightFlattenable<HdrMetadata> {
+    enum Type : uint32_t {
+        SMPTE2086 = 1 << 0,
+        CTA861_3  = 1 << 1,
+    };
+    uint32_t validTypes{0};
+
+    android_smpte2086_metadata smpte2086{};
+    android_cta861_3_metadata cta8613{};
+
+    // LightFlattenable
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
+
+    bool operator==(const HdrMetadata& rhs) const;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 039dc0d..887654e 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,6 +31,7 @@
 #include <ui/Region.h>
 
 #include <gui/FrameTimestamps.h>
+#include <gui/HdrMetadata.h>
 
 #include <hidl/HybridInterface.h>
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
@@ -72,6 +73,14 @@
         RELEASE_ALL_BUFFERS       = 0x2,
     };
 
+    enum {
+        // A parcelable magic indicates using Binder BufferQueue as transport
+        // backend.
+        USE_BUFFER_QUEUE = 0x62717565, // 'bque'
+        // A parcelable magic indicates using BufferHub as transport backend.
+        USE_BUFFER_HUB = 0x62687562, // 'bhub'
+    };
+
     // requestBuffer requests a new buffer for the given index. The server (i.e.
     // the IGraphicBufferProducer implementation) assigns the newly created
     // buffer to the given slot index, and the client is expected to mirror the
@@ -354,6 +363,9 @@
         const Region& getSurfaceDamage() const { return surfaceDamage; }
         void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
 
+        const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
+        void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
+
     private:
         int64_t timestamp{0};
         int isAutoTimestamp{0};
@@ -365,6 +377,7 @@
         sp<Fence> fence;
         Region surfaceDamage;
         bool getFrameTimestamps{false};
+        HdrMetadata hdrMetadata;
     };
 
     struct QueueBufferOutput : public Flattenable<QueueBufferOutput> {
@@ -599,6 +612,24 @@
     // returned by querying the now deprecated
     // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
     virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
+
+    // Static method exports any IGraphicBufferProducer object to a parcel. It
+    // handles null producer as well.
+    static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
+                                   Parcel* parcel);
+
+    // Factory method that creates a new IBGP instance from the parcel.
+    static sp<IGraphicBufferProducer> createFromParcel(const Parcel* parcel);
+
+protected:
+    // Exports the current producer as a binder parcelable object. Note that the
+    // producer must be disconnected to be exportable. After successful export,
+    // the producer queue can no longer be connected again. Returns NO_ERROR
+    // when the export is successful and writes an implementation defined
+    // parcelable object into the parcel. For traditional Android BufferQueue,
+    // it writes a strong binder object; for BufferHub, it writes a
+    // ProducerQueueParcelable object.
+    virtual status_t exportToParcel(Parcel* parcel);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index f80ba00..99a3a75 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -29,6 +29,8 @@
 
 #include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
 
 #include <vector>
 
@@ -39,6 +41,7 @@
 struct DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
+class LayerDebugInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
 class IGraphicBufferProducer;
@@ -58,6 +61,11 @@
     enum {
         eSynchronous = 0x01,
         eAnimation   = 0x02,
+
+        // Indicates that this transaction will likely result in a lot of layers being composed, and
+        // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this
+        // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns)
+        eEarlyWakeup = 0x04
     };
 
     enum {
@@ -149,6 +157,9 @@
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats) = 0;
 
+    /* returns display viewport information of the given display */
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) = 0;
+
     /* indicates which of the configurations returned by getDisplayInfo is
      * currently active */
     virtual int getActiveConfig(const sp<IBinder>& display) = 0;
@@ -158,20 +169,25 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) = 0;
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0;
+            Vector<ui::ColorMode>* outColorModes) = 0;
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) = 0;
+            ui::ColorMode colorMode) = 0;
 
     /* Capture the specified screen. requires READ_FRAME_BUFFER permission
      * This function will fail if there is a secure window on screen.
      */
-    virtual status_t captureScreen(const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            Rotation rotation = eRotateNone) = 0;
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   Rotation rotation = eRotateNone) = 0;
+
+    /**
+     * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     */
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   float frameScale = 1.0, bool childrenOnly = false) = 0;
 
     /* Clears the frame statistics for animations.
      *
@@ -195,6 +211,12 @@
     virtual status_t enableVSyncInjections(bool enable) = 0;
 
     virtual status_t injectVSync(nsecs_t when) = 0;
+
+    /* Gets the list of active layers in Z order for debugging purposes
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -219,6 +241,7 @@
         SET_ACTIVE_CONFIG,
         CONNECT_DISPLAY,
         CAPTURE_SCREEN,
+        CAPTURE_LAYERS,
         CLEAR_ANIMATION_FRAME_STATS,
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
@@ -229,7 +252,9 @@
         SET_ACTIVE_COLOR_MODE,
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
-        CREATE_SCOPED_CONNECTION
+        GET_LAYER_DEBUG_INFO,
+        CREATE_SCOPED_CONNECTION,
+        GET_DISPLAY_VIEWPORT
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2c613ea..8dfc99a 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -41,7 +41,7 @@
         eCursorWindow = 0x00002000,
 
         eFXSurfaceNormal = 0x00000000,
-        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceColor = 0x00020000,
         eFXSurfaceMask = 0x000F0000,
     };
 
@@ -49,8 +49,8 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                                   uint32_t ownerUid, sp<IBinder>* handle,
+                                   uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                                   int32_t ownerUid, sp<IBinder>* handle,
                                    sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
new file mode 100644
index 0000000..92bd8c5
--- /dev/null
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcelable.h>
+
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <string>
+#include <math/vec4.h>
+
+namespace android {
+
+/* Class for transporting debug info from SurfaceFlinger to authorized
+ * recipients.  The class is intended to be a data container. There are
+ * no getters or setters.
+ */
+class LayerDebugInfo : public Parcelable {
+public:
+    LayerDebugInfo() = default;
+    LayerDebugInfo(const LayerDebugInfo&) = default;
+    virtual ~LayerDebugInfo() = default;
+
+    virtual status_t writeToParcel(Parcel* parcel) const;
+    virtual status_t readFromParcel(const Parcel* parcel);
+
+    std::string mName = std::string("NOT FILLED");
+    std::string mParentName = std::string("NOT FILLED");
+    std::string mType = std::string("NOT FILLED");
+    Region mTransparentRegion = Region::INVALID_REGION;
+    Region mVisibleRegion = Region::INVALID_REGION;
+    Region mSurfaceDamageRegion = Region::INVALID_REGION;
+    uint32_t mLayerStack = 0;
+    float mX = 0.f;
+    float mY = 0.f;
+    uint32_t mZ = 0 ;
+    int32_t mWidth = -1;
+    int32_t mHeight = -1;
+    Rect mCrop = Rect::INVALID_RECT;
+    Rect mFinalCrop = Rect::INVALID_RECT;
+    half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
+    uint32_t mFlags = 0;
+    PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    // Row-major transform matrix (SurfaceControl::setMatrix())
+    float mMatrix[2][2] = {{0.f, 0.f}, {0.f, 0.f}};
+    int32_t mActiveBufferWidth = -1;
+    int32_t mActiveBufferHeight = -1;
+    int32_t mActiveBufferStride = 0;
+    PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE;
+    int32_t mNumQueuedFrames = -1;
+    bool mRefreshPending = false;
+    bool mIsOpaque = false;
+    bool mContentDirty = false;
+};
+
+std::string to_string(const LayerDebugInfo& info);
+
+} // namespace android
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
similarity index 84%
rename from libs/gui/include/private/gui/LayerState.h
rename to libs/gui/include/gui/LayerState.h
index 307c764..788962e 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -25,6 +25,7 @@
 #include <ui/Region.h>
 #include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -59,7 +60,10 @@
         eGeometryAppliesWithResize  = 0x00001000,
         eReparentChildren           = 0x00002000,
         eDetachChildren             = 0x00004000,
-        eRelativeLayerChanged       = 0x00008000
+        eRelativeLayerChanged       = 0x00008000,
+        eReparent                   = 0x00010000,
+        eColorChanged               = 0x00020000,
+        eDestroySurface             = 0x00040000
     };
 
     layer_state_t()
@@ -74,6 +78,7 @@
         matrix.dsdy = matrix.dtdx = 0.0f;
     }
 
+    void merge(const layer_state_t& other);
     status_t    write(Parcel& output) const;
     status_t    read(const Parcel& input);
 
@@ -107,6 +112,10 @@
 
             sp<IBinder>     relativeLayerHandle;
 
+            sp<IBinder>     parentHandleForChild;
+
+            half3           color;
+
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
@@ -137,6 +146,7 @@
     };
 
     DisplayState();
+    void merge(const DisplayState& other);
 
     uint32_t what;
     sp<IBinder> token;
@@ -150,6 +160,20 @@
     status_t read(const Parcel& input);
 };
 
+static inline
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+    if (lhs.client < rhs.client) return -1;
+    if (lhs.client > rhs.client) return 1;
+    if (lhs.state.surface < rhs.state.surface)  return -1;
+    if (lhs.state.surface > rhs.state.surface)  return 1;
+    return 0;
+}
+
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+    return compare_type(lhs.token, rhs.token);
+}
+
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55dd6bf..9aeafae 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -17,10 +17,12 @@
 #ifndef ANDROID_GUI_SURFACE_H
 #define ANDROID_GUI_SURFACE_H
 
-#include <gui/IGraphicBufferProducer.h>
 #include <gui/BufferQueueDefs.h>
+#include <gui/HdrMetadata.h>
+#include <gui/IGraphicBufferProducer.h>
 
 #include <ui/ANativeObjectBase.h>
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #include <utils/Condition.h>
@@ -214,6 +216,8 @@
     int dispatchUnlockAndPost(va_list args);
     int dispatchSetSidebandStream(va_list args);
     int dispatchSetBuffersDataSpace(va_list args);
+    int dispatchSetBuffersSmpte2086Metadata(va_list args);
+    int dispatchSetBuffersCta8613Metadata(va_list args);
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
@@ -242,7 +246,9 @@
     virtual int setBuffersTransform(uint32_t transform);
     virtual int setBuffersStickyTransform(uint32_t transform);
     virtual int setBuffersTimestamp(int64_t timestamp);
-    virtual int setBuffersDataSpace(android_dataspace dataSpace);
+    virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
+    virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
+    virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
     virtual int setCrop(Rect const* rect);
     virtual int setUsage(uint64_t reqUsage);
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
@@ -281,6 +287,10 @@
     // detachNextBuffer, or attachBuffer call.
     status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
 
+    ui::Dataspace getBuffersDataSpace();
+
+    static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer);
+
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -331,9 +341,13 @@
     int64_t mTimestamp;
 
     // mDataSpace is the buffer dataSpace that will be used for the next buffer
-    // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which
+    // queue operation. It defaults to Dataspace::UNKNOWN, which
     // means that the buffer contains some type of color data.
-    android_dataspace mDataSpace;
+    ui::Dataspace mDataSpace;
+
+    // mHdrMetadata is the HDR metadata that will be used for the next buffer
+    // queue operation.  There is no HDR metadata by default.
+    HdrMetadata mHdrMetadata;
 
     // mCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 145c059..ad8a8b0 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 
 #include <binder/IBinder.h>
 
@@ -28,17 +29,19 @@
 #include <utils/threads.h>
 
 #include <ui/FrameStats.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
 #include <gui/SurfaceControl.h>
+#include <math/vec3.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
 struct DisplayInfo;
-class Composer;
 class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
@@ -51,6 +54,7 @@
     friend class Composer;
 public:
                 SurfaceComposerClient();
+                SurfaceComposerClient(const sp<ISurfaceComposerClient>& client);
                 SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
     virtual     ~SurfaceComposerClient();
 
@@ -75,6 +79,9 @@
     static status_t getDisplayInfo(const sp<IBinder>& display,
             DisplayInfo* info);
 
+    // Get the display viewport for the given display
+    static status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
+
     // Get the index of the current active configuration (relative to the list
     // returned by getDisplayInfo)
     static int getActiveConfig(const sp<IBinder>& display);
@@ -85,13 +92,14 @@
 
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes);
+            Vector<ui::ColorMode>* outColorModes);
 
     // Gets the active color mode for the given display
-    static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+    static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
 
     // Sets the active color mode for the given display
-    static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+    static status_t setActiveColorMode(const sp<IBinder>& display,
+            ui::ColorMode colorMode);
 
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
@@ -107,8 +115,20 @@
             PixelFormat format, // pixel-format desired
             uint32_t flags = 0, // usage flags
             SurfaceControl* parent = nullptr, // parent
-            uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            uint32_t ownerUid = 0 // UID of the task
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
+    );
+
+    status_t createSurfaceChecked(
+            const String8& name,// name of the surface
+            uint32_t w,         // width in pixel
+            uint32_t h,         // height in pixel
+            PixelFormat format, // pixel-format desired
+            sp<SurfaceControl>* outSurface,
+            uint32_t flags = 0, // usage flags
+            SurfaceControl* parent = nullptr, // parent
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
     );
 
     //! Create a virtual display
@@ -121,157 +141,185 @@
     //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
     static sp<IBinder> getBuiltInDisplay(int32_t id);
 
-    // ------------------------------------------------------------------------
-    // Composer parameters
-    // All composer parameters must be changed within a transaction
-    // several surfaces can be updated in one transaction, all changes are
-    // committed at once when the transaction is closed.
-    // closeGlobalTransaction() requires an IPC with the server.
-
-    //! Open a composer transaction on all active SurfaceComposerClients.
-    static void openGlobalTransaction();
-
-    //! Close a composer transaction on all active SurfaceComposerClients.
-    static void closeGlobalTransaction(bool synchronous = false);
-
     static status_t enableVSyncInjections(bool enable);
 
     static status_t injectVSync(nsecs_t when);
 
-    //! Flag the currently open transaction as an animation transaction.
-    static void setAnimationTransaction();
+    struct SCHash {
+        std::size_t operator()(const sp<SurfaceControl>& sc) const {
+            return std::hash<SurfaceControl *>{}(sc.get());
+        }
+    };
 
-    status_t    hide(const sp<IBinder>& id);
-    status_t    show(const sp<IBinder>& id);
-    status_t    setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
-    status_t    setLayer(const sp<IBinder>& id, int32_t layer);
-    status_t    setRelativeLayer(const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setAlpha(const sp<IBinder>& id, float alpha=1.0f);
-    status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setPosition(const sp<IBinder>& id, float x, float y);
-    status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
-    status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setFinalCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<IBinder>& handle, uint64_t frameNumber);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<Surface>& handle, uint64_t frameNumber);
-    status_t    reparentChildren(const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t    detachChildren(const sp<IBinder>& id);
-    status_t    setOverrideScalingMode(const sp<IBinder>& id,
-            int32_t overrideScalingMode);
-    status_t    setGeometryAppliesWithResize(const sp<IBinder>& id);
+    class Transaction {
+        std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+        SortedVector<DisplayState > mDisplayStates;
+        uint32_t                    mForceSynchronous = 0;
+        uint32_t                    mTransactionNestCount = 0;
+        bool                        mAnimation = false;
+        bool                        mEarlyWakeup = false;
+
+        int mStatus = NO_ERROR;
+
+        layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+        DisplayState& getDisplayState(const sp<IBinder>& token);
+
+    public:
+        Transaction() = default;
+        virtual ~Transaction() = default;
+        Transaction(Transaction const& other);
+
+        status_t apply(bool synchronous = false);
+        // Merge another transaction in to this one, clearing other
+        // as if it had been applied.
+        Transaction& merge(Transaction&& other);
+        Transaction& show(const sp<SurfaceControl>& sc);
+        Transaction& hide(const sp<SurfaceControl>& sc);
+        Transaction& setPosition(const sp<SurfaceControl>& sc,
+                float x, float y);
+        Transaction& setSize(const sp<SurfaceControl>& sc,
+                uint32_t w, uint32_t h);
+        Transaction& setLayer(const sp<SurfaceControl>& sc,
+                int32_t z);
+
+        // Sets a Z order relative to the Surface specified by "relativeTo" but
+        // without becoming a full child of the relative. Z-ordering works exactly
+        // as if it were a child however.
+        //
+        // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+        //
+        // This overrides any previous call and is overriden by any future calls
+        // to setLayer.
+        //
+        // If the relative is removed, the Surface will have no layer and be
+        // invisible, until the next time set(Relative)Layer is called.
+        Transaction& setRelativeLayer(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& relativeTo, int32_t z);
+        Transaction& setFlags(const sp<SurfaceControl>& sc,
+                uint32_t flags, uint32_t mask);
+        Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
+                const Region& transparentRegion);
+        Transaction& setAlpha(const sp<SurfaceControl>& sc,
+                float alpha);
+        Transaction& setMatrix(const sp<SurfaceControl>& sc,
+                float dsdx, float dtdx, float dtdy, float dsdy);
+        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+        // Defers applying any changes made in this transaction until the Layer
+        // identified by handle reaches the given frameNumber. If the Layer identified
+        // by handle is removed, then we will apply this transaction regardless of
+        // what frame number has been reached.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& handle,
+                uint64_t frameNumber);
+        // A variant of deferTransactionUntil which identifies the Layer we wait for by
+        // Surface instead of Handle. Useful for clients which may not have the
+        // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<Surface>& barrierSurface,
+                uint64_t frameNumber);
+        // Reparents all children of this layer to the new parent handle.
+        Transaction& reparentChildren(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        /// Reparents the current layer to the new parent handle. The new parent must not be null.
+        // This can be used instead of reparentChildren if the caller wants to
+        // only re-parent a specific child.
+        Transaction& reparent(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+
+        // Detaches all child surfaces (and their children recursively)
+        // from their SurfaceControl.
+        // The child SurfaceControls will not throw exceptions or return errors,
+        // but transactions will have no effect.
+        // The child surfaces will continue to follow their parent surfaces,
+        // and remain eligible for rendering, but their relative state will be
+        // frozen. We use this in the WindowManager, in app shutdown/relaunch
+        // scenarios, where the app would otherwise clean up its child Surfaces.
+        // Sometimes the WindowManager needs to extend their lifetime slightly
+        // in order to perform an exit animation or prevent flicker.
+        Transaction& detachChildren(const sp<SurfaceControl>& sc);
+        // Set an override scaling mode as documented in <system/window.h>
+        // the override scaling mode will take precedence over any client
+        // specified scaling mode. -1 will clear the override scaling mode.
+        Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
+                int32_t overrideScalingMode);
+
+        // If the size changes in this transaction, all geometry updates specified
+        // in this transaction will not complete until a buffer of the new size
+        // arrives. As some elements normally apply immediately, this enables
+        // freezing the total geometry of a surface until a resize is completed.
+        Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
+
+        Transaction& destroySurface(const sp<SurfaceControl>& sc);
+
+        status_t setDisplaySurface(const sp<IBinder>& token,
+                const sp<IGraphicBufferProducer>& bufferProducer);
+
+        void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+
+        /* setDisplayProjection() defines the projection of layer stacks
+         * to a given display.
+         *
+         * - orientation defines the display's orientation.
+         * - layerStackRect defines which area of the window manager coordinate
+         * space will be used.
+         * - displayRect defines where on the display will layerStackRect be
+         * mapped to. displayRect is specified post-orientation, that is
+         * it uses the orientation seen by the end-user.
+         */
+        void setDisplayProjection(const sp<IBinder>& token,
+                uint32_t orientation,
+                const Rect& layerStackRect,
+                const Rect& displayRect);
+        void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
+        void setAnimationTransaction();
+        void setEarlyWakeup();
+    };
 
     status_t    destroySurface(const sp<IBinder>& id);
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
     status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
-
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
     static status_t getHdrCapabilities(const sp<IBinder>& display,
             HdrCapabilities* outCapabilities);
 
-    static status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    static void setDisplayLayerStack(const sp<IBinder>& token,
-            uint32_t layerStack);
-    static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    /* setDisplayProjection() defines the projection of layer stacks
-     * to a given display.
-     *
-     * - orientation defines the display's orientation.
-     * - layerStackRect defines which area of the window manager coordinate
-     * space will be used.
-     * - displayRect defines where on the display will layerStackRect be
-     * mapped to. displayRect is specified post-orientation, that is
-     * it uses the orientation seen by the end-user.
-     */
     static void setDisplayProjection(const sp<IBinder>& token,
             uint32_t orientation,
             const Rect& layerStackRect,
             const Rect& displayRect);
 
+    inline sp<ISurfaceComposerClient> getClient() { return mClient; }
+
 private:
     virtual void onFirstRef();
-    Composer& getComposer();
 
     mutable     Mutex                       mLock;
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
-                Composer&                   mComposer;
                 wp<IGraphicBufferProducer>  mParent;
 };
 
 // ---------------------------------------------------------------------------
 
-class ScreenshotClient
-{
+class ScreenshotClient {
 public:
     // if cropping isn't required, callers may pass in a default Rect, e.g.:
     //   capture(display, producer, Rect(), reqWidth, ...);
-    static status_t capture(
-            const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform);
-    static status_t captureToBuffer(
-            const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            uint32_t rotation,
-            sp<GraphicBuffer>* outbuffer);
-private:
-    mutable sp<CpuConsumer> mCpuConsumer;
-    mutable sp<IGraphicBufferProducer> mProducer;
-    CpuConsumer::LockedBuffer mBuffer;
-    bool mHaveBuffer;
-
-public:
-    ScreenshotClient();
-    ~ScreenshotClient();
-
-    // frees the previous screenshot and captures a new one
-    // if cropping isn't required, callers may pass in a default Rect, e.g.:
-    //   update(display, Rect(), useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform, uint32_t rotation);
-
-    sp<CpuConsumer> getCpuConsumer() const;
-
-    // release memory occupied by the screenshot
-    void release();
-
-    // pixels are valid until this object is freed or
-    // release() or update() is called
-    void const* getPixels() const;
-
-    uint32_t getWidth() const;
-    uint32_t getHeight() const;
-    PixelFormat getFormat() const;
-    uint32_t getStride() const;
-    // size of allocated memory in bytes
-    size_t getSize() const;
-    android_dataspace getDataSpace() const;
+    static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
+                            uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
+                            bool useIdentityTransform, uint32_t rotation,
+                            sp<GraphicBuffer>* outBuffer);
+    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
+                                  sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                       float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 8bb705c..bd987dd 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -29,6 +29,7 @@
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -43,6 +44,9 @@
 class SurfaceControl : public RefBase
 {
 public:
+    static sp<SurfaceControl> readFromParcel(Parcel* parcel);
+    void writeToParcel(Parcel* parcel);
+
     static bool isValid(const sp<SurfaceControl>& surface) {
         return (surface != 0) && surface->isValid();
     }
@@ -60,77 +64,6 @@
     // disconnect any api that's connected
     void        disconnect();
 
-    status_t    setLayerStack(uint32_t layerStack);
-    status_t    setLayer(int32_t layer);
-
-    // Sets a Z order relative to the Surface specified by "relativeTo" but
-    // without becoming a full child of the relative. Z-ordering works exactly
-    // as if it were a child however.
-    //
-    // As a nod to sanity, only non-child surfaces may have a relative Z-order.
-    //
-    // This overrides any previous and is overriden by any future calls
-    // to setLayer.
-    //
-    // If the relative dissapears, the Surface will have no layer and be
-    // invisible, until the next time set(Relative)Layer is called.
-    //
-    // TODO: This is probably a hack. Currently it exists only to work around
-    // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
-    // which allows inserting a window between a SurfaceView and it's main application
-    // window. However, since we are using child windows for the SurfaceView, but not using
-    // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
-    // This is only used by the "TvInputService" and following the port of ViewRootImpl
-    // to child surfaces, we can then port this and remove this method.
-    status_t    setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setPosition(float x, float y);
-    status_t    setSize(uint32_t w, uint32_t h);
-    status_t    hide();
-    status_t    show();
-    status_t    setFlags(uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const Region& transparent);
-    status_t    setAlpha(float alpha=1.0f);
-    status_t    setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setCrop(const Rect& crop);
-    status_t    setFinalCrop(const Rect& crop);
-
-    // If the size changes in this transaction, all geometry updates specified
-    // in this transaction will not complete until a buffer of the new size
-    // arrives. As some elements normally apply immediately, this enables
-    // freezing the total geometry of a surface until a resize is completed.
-    status_t    setGeometryAppliesWithResize();
-
-    // Defers applying any changes made in this transaction until the Layer
-    // identified by handle reaches the given frameNumber. If the Layer identified
-    // by handle is removed, then we will apply this transaction regardless of
-    // what frame number has been reached.
-    status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
-
-    // A variant of deferTransactionUntil which identifies the Layer we wait for by
-    // Surface instead of Handle. Useful for clients which may not have the
-    // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
-    status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber);
-
-    // Reparents all children of this layer to the new parent handle.
-    status_t reparentChildren(const sp<IBinder>& newParentHandle);
-
-    // Detaches all child surfaces (and their children recursively)
-    // from their SurfaceControl.
-    // The child SurfaceControl's will not throw exceptions or return errors,
-    // but transactions will have no effect.
-    // The child surfaces will continue to follow their parent surfaces,
-    // and remain eligible for rendering, but their relative state will be
-    // frozen. We use this in the WindowManager, in app shutdown/relaunch
-    // scenarios, where the app would otherwise clean up its child Surfaces.
-    // Sometimes the WindowManager needs to extend their lifetime slightly
-    // in order to perform an exit animation or prevent flicker.
-    status_t detachChildren();
-
-    // Set an override scaling mode as documented in <system/window.h>
-    // the override scaling mode will take precedence over any client
-    // specified scaling mode. -1 will clear the override scaling mode.
-    status_t setOverrideScalingMode(int32_t overrideScalingMode);
-
     static status_t writeSurfaceToParcel(
             const sp<SurfaceControl>& control, Parcel* parcel);
 
@@ -141,6 +74,8 @@
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
+    sp<SurfaceComposerClient> getClient() const;
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -152,7 +87,8 @@
     SurfaceControl(
             const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& handle,
-            const sp<IGraphicBufferProducer>& gbp);
+            const sp<IGraphicBufferProducer>& gbp,
+            bool owned);
 
     ~SurfaceControl();
 
@@ -165,6 +101,7 @@
     sp<IGraphicBufferProducer>  mGraphicBufferProducer;
     mutable Mutex               mLock;
     mutable sp<Surface>         mSurfaceData;
+    bool                        mOwned;
 };
 
 }; // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index fa87f29..01e90e0 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -7,6 +7,10 @@
     test_suites: ["device-tests"],
 
     clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     srcs: [
         "BufferItemConsumer_test.cpp",
@@ -45,3 +49,35 @@
         "libnativewindow"
     ],
 }
+
+// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+cc_test {
+    name: "libgui_separate_binary_test",
+    test_suites: ["device-tests"],
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    test_per_src: true,
+    srcs: [
+        "SurfaceParcelable_test.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libui",
+        "libutils",
+        "libbufferhubqueue",  // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+        "libpdx_default_transport",
+    ],
+
+    header_libs: [
+        "libdvr_headers",
+    ],
+}
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 0982d7e..36be7d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -33,6 +33,7 @@
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 
+#include <thread>
 #include <vector>
 #define CPU_CONSUMER_TEST_FORMAT_RAW 0
 #define CPU_CONSUMER_TEST_FORMAT_Y8 0
@@ -310,8 +311,6 @@
     uint32_t h = buf.height;
     const int blockWidth = w > 16 ? w / 16 : 1;
     const int blockHeight = h > 16 ? h / 16 : 1;
-    const int blockRows = h / blockHeight;
-    const int blockCols = w / blockWidth;
 
     // Top-left square is bright
     checkPixel(buf, 0, 0, 191);
@@ -349,8 +348,6 @@
     uint32_t h = buf.height;
     const int blockWidth = w > 16 ? w / 16 : 1;
     const int blockHeight = h > 16 ? h / 16 : 1;
-    const int blockRows = h / blockHeight;
-    const int blockCols = w / blockWidth;
 
     // Top-left square is bright red
     checkPixel(buf, 0, 0, 191, 63, 63);
@@ -392,8 +389,6 @@
     uint32_t h = buf.height;
     const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
     const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
-    const int blockRows = h / blockHeight;
-    const int blockCols = w / blockWidth;
 
     // Top-left square is red
     checkPixel(buf, 0, 0, 1000, 200, 200);
@@ -687,6 +682,70 @@
     }
 }
 
+TEST_P(CpuConsumerTest, FromCpuInvalid) {
+    status_t err = mCC->lockNextBuffer(nullptr);
+    ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail";
+
+    CpuConsumer::LockedBuffer b;
+    err = mCC->unlockBuffer(b);
+    ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail";
+}
+
+TEST_P(CpuConsumerTest, FromCpuMultiThread) {
+    CpuConsumerTestParams params = GetParam();
+    ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1));
+
+    for (int i = 0; i < 10; i++) {
+        std::atomic<int> threadReadyCount(0);
+        auto lockAndUnlock = [&]() {
+            threadReadyCount++;
+            // busy wait
+            while (threadReadyCount < params.maxLockedBuffers + 1);
+
+            CpuConsumer::LockedBuffer b;
+            status_t err = mCC->lockNextBuffer(&b);
+            if (err == NO_ERROR) {
+                usleep(1000);
+                err = mCC->unlockBuffer(b);
+                ASSERT_NO_ERROR(err, "Could not unlock buffer: ");
+            } else if (err == NOT_ENOUGH_DATA) {
+                // there are params.maxLockedBuffers+1 threads so one of the
+                // threads might get this error
+            } else {
+                FAIL() << "Could not lock buffer";
+            }
+        };
+
+        // produce buffers
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            const int64_t time = 1234L;
+            uint32_t stride;
+            ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride));
+        }
+
+        // spawn threads
+        std::vector<std::thread> threads;
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            threads.push_back(std::thread(lockAndUnlock));
+        }
+
+        // join threads
+        for (auto& thread : threads) {
+            thread.join();
+        }
+
+        // we produced N+1 buffers, but the threads might only consume N
+        CpuConsumer::LockedBuffer b;
+        if (mCC->lockNextBuffer(&b) == NO_ERROR) {
+            mCC->unlockBuffer(b);
+        }
+
+        if (HasFatalFailure()) {
+            break;
+        }
+    }
+}
+
 CpuConsumerTestParams y8TestSets[] = {
     { 512,   512, 1, HAL_PIXEL_FORMAT_Y8},
     { 512,   512, 3, HAL_PIXEL_FORMAT_Y8},
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index 1739d9c..a91552f 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -22,6 +22,8 @@
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 static int abs(int value) {
     return value > 0 ? value : -value;
 }
@@ -68,10 +70,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF)
+                .show(mSurfaceControl)
+                .apply());
 
         sp<ANativeWindow> window = mSurfaceControl->getSurface();
         mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window);
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index dd23bd4..a35cf11 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -42,6 +42,10 @@
 #define TEST_CONTROLLED_BY_APP false
 #define TEST_PRODUCER_USAGE_BITS (0)
 
+#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE
+#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0
+#endif
+
 namespace android {
 
 namespace {
@@ -66,9 +70,15 @@
     const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0;
     const int QUEUE_BUFFER_INPUT_TRANSFORM = 0;
     const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
+
+    // Enums to control which IGraphicBufferProducer backend to test.
+    enum IGraphicBufferProducerTestCode {
+        USE_BUFFER_QUEUE_PRODUCER = 0,
+        USE_BUFFER_HUB_PRODUCER,
+    };
 }; // namespace anonymous
 
-class IGraphicBufferProducerTest : public ::testing::Test {
+class IGraphicBufferProducerTest : public ::testing::TestWithParam<uint32_t> {
 protected:
 
     IGraphicBufferProducerTest() {}
@@ -81,10 +91,27 @@
 
         mDC = new DummyConsumer;
 
-        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        switch (GetParam()) {
+            case USE_BUFFER_QUEUE_PRODUCER: {
+                BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+                break;
+            }
+            case USE_BUFFER_HUB_PRODUCER: {
+                BufferQueue::createBufferHubQueue(&mProducer, &mConsumer);
+                break;
+            }
+            default: {
+                // Should never reach here.
+                LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam());
+                break;
+            }
+        }
 
         // Test check: Can't connect producer if no consumer yet
-        ASSERT_EQ(NO_INIT, TryConnectProducer());
+        if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+            // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+            ASSERT_EQ(NO_INIT, TryConnectProducer());
+        }
 
         // Must connect consumer before producer connects will succeed.
         ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false));
@@ -229,7 +256,7 @@
     sp<IGraphicBufferConsumer> mConsumer;
 };
 
-TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) {
     IGraphicBufferProducer::QueueBufferOutput output;
 
     // NULL output returns BAD_VALUE
@@ -247,7 +274,7 @@
     // TODO: get a token from a dead process somehow
 }
 
-TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Can't connect when there is already a producer connected
@@ -259,20 +286,23 @@
 
     ASSERT_OK(mConsumer->consumerDisconnect());
     // Can't connect when IGBP is abandoned
-    EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN,
-                                          TEST_API,
-                                          TEST_CONTROLLED_BY_APP,
-                                          &output));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN,
+                                              TEST_API,
+                                              TEST_CONTROLLED_BY_APP,
+                                              &output));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Disconnect_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 }
 
 
-TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Disconnect_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Must disconnect with same API number
@@ -283,7 +313,7 @@
     // TODO: somehow kill mProducer so that this returns DEAD_OBJECT
 }
 
-TEST_F(IGraphicBufferProducerTest, Query_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Query_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int32_t value = -1;
@@ -308,7 +338,7 @@
 
 }
 
-TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Query_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // One past the end of the last 'query' enum value. Update this if we add more enums.
@@ -334,14 +364,17 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // BQ was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
+    }
 
     // TODO: other things in window.h that are supported by Surface::query
     // but not by BufferQueue::query
 }
 
 // TODO: queue under more complicated situations not involving just a single buffer
-TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Queue_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int dequeuedSlot = -1;
@@ -371,16 +404,21 @@
         EXPECT_EQ(DEFAULT_WIDTH, output.width);
         EXPECT_EQ(DEFAULT_HEIGHT, output.height);
         EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint);
+
         // Since queueBuffer was called exactly once
-        EXPECT_EQ(1u, output.numPendingBuffers);
-        EXPECT_EQ(2u, output.nextFrameNumber);
+        if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+            // TODO(b/70041889): BufferHubProducer need to support metadata: numPendingBuffers
+            EXPECT_EQ(1u, output.numPendingBuffers);
+            // TODO(b/70041952): BufferHubProducer need to support metadata: nextFrameNumber
+            EXPECT_EQ(2u, output.nextFrameNumber);
+        }
     }
 
     // Buffer was not in the dequeued state
     EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output));
 }
 
-TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Queue_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Invalid slot number
@@ -463,15 +501,16 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // The buffer queue has been abandoned.
-    {
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
         IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
         IGraphicBufferProducer::QueueBufferOutput output;
 
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
         EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output));
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) {
+TEST_P(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int dequeuedSlot = -1;
@@ -488,7 +527,7 @@
     mProducer->cancelBuffer(dequeuedSlot, dequeuedFence);
 }
 
-TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     int minUndequeuedBuffers;
     ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -540,7 +579,7 @@
     ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1));
 }
 
-TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
+TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     int minUndequeuedBuffers;
     ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -578,12 +617,19 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
-            << "bufferCount: " << minBuffers;
-
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
+                << "bufferCount: " << minBuffers;
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+        // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true)
+        return;
+    }
+
     ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
@@ -609,7 +655,7 @@
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
+TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     // Prerequisite to fail out a valid setBufferCount call
     {
@@ -628,11 +674,13 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: "
-            << false;
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/36724099): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false;
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_dequeueBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -642,15 +690,18 @@
                                        TEST_PRODUCER_USAGE_BITS, nullptr, nullptr));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_detachNextBuffer) {
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
 
-    ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_requestBuffer) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
@@ -674,7 +725,7 @@
 }
 
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_detachBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -684,10 +735,13 @@
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_queueBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -704,7 +758,7 @@
     ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_cancelBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -717,7 +771,7 @@
     ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_attachBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -725,11 +779,27 @@
 
     setupDequeueRequestBuffer(&slot, &fence, &buffer);
 
-    ASSERT_OK(mProducer->detachBuffer(slot));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_OK(mProducer->detachBuffer(slot));
+    }
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/69981968): Implement BufferHubProducer::attachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+    }
 }
 
+#if USE_BUFFER_HUB_AS_BUFFER_QUEUE
+INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
+                        ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER));
+#else
+// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can
+// pass all existing libgui tests.
+INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
+                        ::testing::Values(USE_BUFFER_QUEUE_PRODUCER));
+#endif
+
 } // namespace android
diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp
new file mode 100644
index 0000000..686dc82
--- /dev/null
+++ b/libs/gui/tests/SurfaceParcelable_test.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceParcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gui/BufferHubProducer.h>
+#include <gui/BufferQueue.h>
+#include <gui/view/Surface.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static const String16 kTestServiceName = String16("SurfaceParcelableTestService");
+static const String16 kSurfaceName = String16("TEST_SURFACE");
+static const uint32_t kBufferWidth = 100;
+static const uint32_t kBufferHeight = 1;
+static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+
+enum SurfaceParcelableTestServiceCode {
+    CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_BUFFER_HUB_SURFACE,
+};
+
+class SurfaceParcelableTestService : public BBinder {
+public:
+    SurfaceParcelableTestService() {
+        // BufferQueue
+        BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer);
+
+        // BufferHub
+        dvr::ProducerQueueConfigBuilder configBuilder;
+        mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth)
+                                                            .SetDefaultHeight(kBufferHeight)
+                                                            .SetDefaultFormat(kBufferFormat)
+                                                            .Build(),
+                                                    dvr::UsagePolicy{});
+        mBufferHubProducer = BufferHubProducer::Create(mProducerQueue);
+    }
+
+    ~SurfaceParcelableTestService() = default;
+
+    virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
+                                uint32_t /*flags*/ = 0) {
+        switch (code) {
+            case CREATE_BUFFER_QUEUE_SURFACE: {
+                view::Surface surfaceShim;
+                surfaceShim.name = kSurfaceName;
+                surfaceShim.graphicBufferProducer = mBufferQueueProducer;
+                return surfaceShim.writeToParcel(reply);
+            }
+            case CREATE_BUFFER_HUB_SURFACE: {
+                view::Surface surfaceShim;
+                surfaceShim.name = kSurfaceName;
+                surfaceShim.graphicBufferProducer = mBufferHubProducer;
+                return surfaceShim.writeToParcel(reply);
+            }
+            default:
+                return UNKNOWN_TRANSACTION;
+        };
+    }
+
+protected:
+    sp<IGraphicBufferProducer> mBufferQueueProducer;
+    sp<IGraphicBufferConsumer> mBufferQueueConsumer;
+
+    std::shared_ptr<dvr::ProducerQueue> mProducerQueue;
+    sp<IGraphicBufferProducer> mBufferHubProducer;
+};
+
+static int runBinderServer() {
+    ProcessState::self()->startThreadPool();
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService;
+    sm->addService(kTestServiceName, service, false);
+
+    ALOGI("Binder server running...");
+
+    while (true) {
+        int stat, retval;
+        retval = wait(&stat);
+        if (retval == -1 && errno == ECHILD) {
+            break;
+        }
+    }
+
+    ALOGI("Binder server exiting...");
+    return 0;
+}
+
+class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> {
+protected:
+    virtual void SetUp() {
+        mService = defaultServiceManager()->getService(kTestServiceName);
+        if (mService == nullptr) {
+            ALOGE("Failed to connect to the test service.");
+            return;
+        }
+
+        ALOGI("Binder service is ready for client.");
+    }
+
+    status_t GetSurface(view::Surface* surfaceShim) {
+        ALOGI("...Test: %d", GetParam());
+
+        uint32_t opCode = GetParam();
+        Parcel data;
+        Parcel reply;
+        status_t error = mService->transact(opCode, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("Failed to get surface over binder, error=%d.", error);
+            return error;
+        }
+
+        error = surfaceShim->readFromParcel(&reply);
+        if (error != NO_ERROR) {
+            ALOGE("Failed to get surface from parcel, error=%d.", error);
+            return error;
+        }
+
+        return NO_ERROR;
+    }
+
+private:
+    sp<IBinder> mService;
+};
+
+TEST_P(SurfaceParcelableTest, SendOverBinder) {
+    view::Surface surfaceShim;
+    EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR);
+    EXPECT_EQ(surfaceShim.name, kSurfaceName);
+    EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr);
+}
+
+INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest,
+                        ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE));
+
+} // namespace android
+
+int main(int argc, char** argv) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        android::ProcessState::self()->startThreadPool();
+        ::testing::InitGoogleTest(&argc, argv);
+        return RUN_ALL_TESTS();
+
+    } else {
+        ALOGI("Test process pid: %d.", pid);
+        return android::runBinderServer();
+    }
+}
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index c6745d0..5639286 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -323,7 +323,6 @@
         for (int j = 0; j < numTestPixels; j++) {
             int x = testPixels[j].x;
             int y = testPixels[j].y;
-            uint8_t value = 0;
             if (j == (i % numTestPixels)) {
                 // We must y-invert the texture coords
                 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e18af17..6e196bf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -22,6 +22,7 @@
 #include <binder/ProcessState.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
+#include <inttypes.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IProducerListener.h>
@@ -41,10 +42,16 @@
 // retrieve wide-color and hdr settings from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
+
+using Transaction = SurfaceComposerClient::Transaction;
 
 static bool hasWideColorDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
+static bool hasHdrDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
 class FakeSurfaceComposer;
 class FakeProducerFrameEventHistory;
 
@@ -52,7 +59,6 @@
 
 class SurfaceTest : public ::testing::Test {
 protected:
-
     SurfaceTest() {
         ProcessState::self()->startThreadPool();
     }
@@ -69,10 +75,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff)
+                .show(mSurfaceControl)
+                .apply());
 
         mSurface = mSurfaceControl->getSurface();
         ASSERT_TRUE(mSurface != NULL);
@@ -87,6 +93,16 @@
     sp<SurfaceControl> mSurfaceControl;
 };
 
+TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) {
+    mComposerClient->dispose();
+    ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+
+    sp<SurfaceControl> sc;
+    status_t err = mComposerClient->createSurfaceChecked(
+            String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0);
+    ASSERT_EQ(NO_INIT, err);
+}
+
 TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
     sp<ANativeWindow> anw(mSurface);
     int result = -123;
@@ -114,14 +130,11 @@
     sp<ANativeWindow> anw(mSurface);
 
     // Verify the screenshot works with no protected buffers.
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer);
-    sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     sp<IBinder> display(sf->getBuiltInDisplay(
             ISurfaceComposer::eDisplayIdMain));
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
+    sp<GraphicBuffer> outBuffer;
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
@@ -152,7 +165,7 @@
                 &buf));
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 }
 
@@ -295,6 +308,68 @@
     ASSERT_EQ(hasWideColorDisplay, supported);
 }
 
+TEST_F(SurfaceTest, GetHdrSupport) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    status_t result = surface->getHdrSupport(&supported);
+    ASSERT_EQ(NO_ERROR, result);
+
+    // NOTE: This is not a CTS test.
+    // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY
+    // is TRUE, getHdrSupport is also true.
+    // TODO: Add check for an HDR color mode on the primary display.
+    ASSERT_EQ(hasHdrDisplay, supported);
+}
+
+TEST_F(SurfaceTest, SetHdrMetadata) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    status_t result = surface->getHdrSupport(&supported);
+    ASSERT_EQ(NO_ERROR, result);
+
+    if (!hasHdrDisplay || !supported) {
+        return;
+    }
+    const android_smpte2086_metadata smpte2086 = {
+        {0.680, 0.320},
+        {0.265, 0.690},
+        {0.150, 0.060},
+        {0.3127, 0.3290},
+        100.0,
+        0.1,
+    };
+    const android_cta861_3_metadata cta861_3 = {
+        78.0,
+        62.0,
+    };
+    int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086);
+    ASSERT_EQ(error, NO_ERROR);
+    error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3);
+    ASSERT_EQ(error, NO_ERROR);
+}
+
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
@@ -506,27 +581,35 @@
             Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
+    status_t getDisplayViewport(const sp<IBinder>& /*display*/, Rect* /*outViewport*/) override {
+        return NO_ERROR;
+    }
     int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
     status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
             override {
         return NO_ERROR;
     }
     status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
-            Vector<android_color_mode_t>* /*outColorModes*/) override {
+            Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
     }
-    android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+    ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
             override {
-        return HAL_COLOR_MODE_NATIVE;
+        return ColorMode::NATIVE;
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
-            android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+        ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureScreen(const sp<IBinder>& /*display*/,
-            const sp<IGraphicBufferProducer>& /*producer*/,
+            sp<GraphicBuffer>* /*outBuffer*/,
             Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
             int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
             bool /*useIdentityTransform*/,
             Rotation /*rotation*/) override { return NO_ERROR; }
+    virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
+                                   sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
+                                   float /*frameScale*/, bool /*childrenOnly*/) override {
+        return NO_ERROR;
+    }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
@@ -539,6 +622,9 @@
         return NO_ERROR;
     }
     status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
+        return NO_ERROR;
+    }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
@@ -797,7 +883,7 @@
                 (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
         FrameEvents* newFrame = &mFrames[iNewFrame];
 
-        uint64_t nOldFrame = iOldFrame + 1;
+        uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1;
         uint64_t nNewFrame = iNewFrame + 1;
 
         // Latch, Composite, and Release the frames in a plausible order.
@@ -1075,7 +1161,6 @@
     EXPECT_EQ(initialCompositorTiming.presentLatency,
               compositeToPresentLatency);
 
-    const uint64_t fId1 = getNextFrameId();
     dequeueAndQueue(0);
     addFrameEvents(true, NO_FRAME_INDEX, 0);
 
@@ -1089,7 +1174,6 @@
     EXPECT_EQ(initialCompositorTiming.presentLatency,
               compositeToPresentLatency);
 
-    const uint64_t fId2 = getNextFrameId();
     dequeueAndQueue(1);
     addFrameEvents(true, 0, 1);
 
@@ -1162,7 +1246,6 @@
     nsecs_t expectedDeadline = initialCompositorTiming.deadline;
     EXPECT_EQ(expectedDeadline, compositeDeadline);
 
-    const uint64_t fId1 = getNextFrameId();
     dequeueAndQueue(0);
     addFrameEvents(true, NO_FRAME_INDEX, 0);
 
@@ -1175,7 +1258,6 @@
             initialCompositorTiming.deadline +initialCompositorTiming.interval;
     EXPECT_EQ(expectedDeadline, compositeDeadline);
 
-    const uint64_t fId2 = getNextFrameId();
     dequeueAndQueue(1);
     addFrameEvents(true, 0, 1);
 
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 5ed3d3b..d64dfd5 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -45,10 +45,7 @@
         if (res != OK) return res;
     }
 
-    res = parcel->writeStrongBinder(
-            IGraphicBufferProducer::asBinder(graphicBufferProducer));
-
-    return res;
+    return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
 }
 
 status_t Surface::readFromParcel(const Parcel* parcel) {
@@ -70,16 +67,7 @@
         }
     }
 
-    sp<IBinder> binder;
-
-    res = parcel->readNullableStrongBinder(&binder);
-    if (res != OK) {
-        ALOGE("%s: Can't read strong binder", __FUNCTION__);
-        return res;
-    }
-
-    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
-
+    graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel);
     return OK;
 }
 
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
deleted file mode 100644
index ec9cbf8..0000000
--- a/libs/hwc2on1adapter/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_library_shared {
-    name: "libhwc2on1adapter",
-    vendor: true,
-
-    clang: true,
-    cppflags: [
-        "-Weverything",
-        "-Wall",
-        "-Wunused",
-        "-Wunreachable-code",
-
-        // The static constructors and destructors in this library have not been noted to
-        // introduce significant overheads
-        "-Wno-exit-time-destructors",
-        "-Wno-global-constructors",
-
-        // We only care about compiling as C++14
-        "-Wno-c++98-compat-pedantic",
-
-        // android/sensors.h uses nested anonymous unions and anonymous structs
-        "-Wno-nested-anon-types",
-        "-Wno-gnu-anonymous-struct",
-
-        // Don't warn about struct padding
-        "-Wno-padded",
-
-        // hwcomposer2.h features switch covering all cases.
-        "-Wno-covered-switch-default",
-
-        // hwcomposer.h features zero size array.
-        "-Wno-zero-length-array",
-
-        // Disabling warning specific to hwc2on1adapter code
-        "-Wno-double-promotion",
-        "-Wno-sign-conversion",
-        "-Wno-switch-enum",
-        "-Wno-float-equal",
-        "-Wno-shorten-64-to-32",
-        "-Wno-sign-compare",
-        "-Wno-missing-prototypes",
-    ],
-
-    srcs: [
-        "HWC2On1Adapter.cpp",
-        "MiniFence.cpp",
-    ],
-
-    shared_libs: [
-        "libutils",
-        "libcutils",
-        "liblog",
-        "libhardware",
-    ],
-
-    export_include_dirs: ["include"],
-
-    export_shared_lib_headers: ["libutils"],
-}
diff --git a/libs/hwc2on1adapter/CleanSpec.mk b/libs/hwc2on1adapter/CleanSpec.mk
deleted file mode 100644
index 7fc2216..0000000
--- a/libs/hwc2on1adapter/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2017 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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list.  These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list.  E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
deleted file mode 100644
index 77f06bb..0000000
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ /dev/null
@@ -1,2637 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "hwc2on1adapter/HWC2On1Adapter.h"
-
-//#define LOG_NDEBUG 0
-
-#undef LOG_TAG
-#define LOG_TAG "HWC2On1Adapter"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-
-#include <inttypes.h>
-
-#include <chrono>
-#include <cstdlib>
-#include <sstream>
-
-#include <hardware/hwcomposer.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-using namespace std::chrono_literals;
-
-static uint8_t getMinorVersion(struct hwc_composer_device_1* device)
-{
-    auto version = device->common.version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
-    return (version >> 16) & 0xF;
-}
-
-template <typename PFN, typename T>
-static hwc2_function_pointer_t asFP(T function)
-{
-    static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
-    return reinterpret_cast<hwc2_function_pointer_t>(function);
-}
-
-using namespace HWC2;
-
-static constexpr Attribute ColorMode = static_cast<Attribute>(6);
-
-namespace android {
-
-class HWC2On1Adapter::Callbacks : public hwc_procs_t {
-    public:
-        explicit Callbacks(HWC2On1Adapter& adapter) : mAdapter(adapter) {
-            invalidate = &invalidateHook;
-            vsync = &vsyncHook;
-            hotplug = &hotplugHook;
-        }
-
-        static void invalidateHook(const hwc_procs_t* procs) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Invalidate();
-        }
-
-        static void vsyncHook(const hwc_procs_t* procs, int display,
-                int64_t timestamp) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Vsync(display, timestamp);
-        }
-
-        static void hotplugHook(const hwc_procs_t* procs, int display,
-                int connected) {
-            auto callbacks = static_cast<const Callbacks*>(procs);
-            callbacks->mAdapter.hwc1Hotplug(display, connected);
-        }
-
-    private:
-        HWC2On1Adapter& mAdapter;
-};
-
-static int closeHook(hw_device_t* /*device*/)
-{
-    // Do nothing, since the real work is done in the class destructor, but we
-    // need to provide a valid function pointer for hwc2_close to call
-    return 0;
-}
-
-HWC2On1Adapter::HWC2On1Adapter(hwc_composer_device_1_t* hwc1Device)
-  : mDumpString(),
-    mHwc1Device(hwc1Device),
-    mHwc1MinorVersion(getMinorVersion(hwc1Device)),
-    mHwc1SupportsVirtualDisplays(false),
-    mHwc1SupportsBackgroundColor(false),
-    mHwc1Callbacks(std::make_unique<Callbacks>(*this)),
-    mCapabilities(),
-    mLayers(),
-    mHwc1VirtualDisplay(),
-    mStateMutex(),
-    mCallbacks(),
-    mHasPendingInvalidate(false),
-    mPendingVsyncs(),
-    mPendingHotplugs(),
-    mDisplays(),
-    mHwc1DisplayMap()
-{
-    common.close = closeHook;
-    getCapabilities = getCapabilitiesHook;
-    getFunction = getFunctionHook;
-    populateCapabilities();
-    populatePrimary();
-    mHwc1Device->registerProcs(mHwc1Device,
-            static_cast<const hwc_procs_t*>(mHwc1Callbacks.get()));
-}
-
-HWC2On1Adapter::~HWC2On1Adapter() {
-    hwc_close_1(mHwc1Device);
-}
-
-void HWC2On1Adapter::doGetCapabilities(uint32_t* outCount,
-        int32_t* outCapabilities) {
-    if (outCapabilities == nullptr) {
-        *outCount = mCapabilities.size();
-        return;
-    }
-
-    auto capabilityIter = mCapabilities.cbegin();
-    for (size_t written = 0; written < *outCount; ++written) {
-        if (capabilityIter == mCapabilities.cend()) {
-            return;
-        }
-        outCapabilities[written] = static_cast<int32_t>(*capabilityIter);
-        ++capabilityIter;
-    }
-}
-
-hwc2_function_pointer_t HWC2On1Adapter::doGetFunction(
-        FunctionDescriptor descriptor) {
-    switch (descriptor) {
-        // Device functions
-        case FunctionDescriptor::CreateVirtualDisplay:
-            return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
-                    createVirtualDisplayHook);
-        case FunctionDescriptor::DestroyVirtualDisplay:
-            return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
-                    destroyVirtualDisplayHook);
-        case FunctionDescriptor::Dump:
-            return asFP<HWC2_PFN_DUMP>(dumpHook);
-        case FunctionDescriptor::GetMaxVirtualDisplayCount:
-            return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
-                    getMaxVirtualDisplayCountHook);
-        case FunctionDescriptor::RegisterCallback:
-            return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
-
-        // Display functions
-        case FunctionDescriptor::AcceptDisplayChanges:
-            return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
-                    displayHook<decltype(&Display::acceptChanges),
-                    &Display::acceptChanges>);
-        case FunctionDescriptor::CreateLayer:
-            return asFP<HWC2_PFN_CREATE_LAYER>(
-                    displayHook<decltype(&Display::createLayer),
-                    &Display::createLayer, hwc2_layer_t*>);
-        case FunctionDescriptor::DestroyLayer:
-            return asFP<HWC2_PFN_DESTROY_LAYER>(
-                    displayHook<decltype(&Display::destroyLayer),
-                    &Display::destroyLayer, hwc2_layer_t>);
-        case FunctionDescriptor::GetActiveConfig:
-            return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
-                    displayHook<decltype(&Display::getActiveConfig),
-                    &Display::getActiveConfig, hwc2_config_t*>);
-        case FunctionDescriptor::GetChangedCompositionTypes:
-            return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
-                    displayHook<decltype(&Display::getChangedCompositionTypes),
-                    &Display::getChangedCompositionTypes, uint32_t*,
-                    hwc2_layer_t*, int32_t*>);
-        case FunctionDescriptor::GetColorModes:
-            return asFP<HWC2_PFN_GET_COLOR_MODES>(
-                    displayHook<decltype(&Display::getColorModes),
-                    &Display::getColorModes, uint32_t*, int32_t*>);
-        case FunctionDescriptor::GetDisplayAttribute:
-            return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
-                    getDisplayAttributeHook);
-        case FunctionDescriptor::GetDisplayConfigs:
-            return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
-                    displayHook<decltype(&Display::getConfigs),
-                    &Display::getConfigs, uint32_t*, hwc2_config_t*>);
-        case FunctionDescriptor::GetDisplayName:
-            return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
-                    displayHook<decltype(&Display::getName),
-                    &Display::getName, uint32_t*, char*>);
-        case FunctionDescriptor::GetDisplayRequests:
-            return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
-                    displayHook<decltype(&Display::getRequests),
-                    &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
-                    int32_t*>);
-        case FunctionDescriptor::GetDisplayType:
-            return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
-                    displayHook<decltype(&Display::getType),
-                    &Display::getType, int32_t*>);
-        case FunctionDescriptor::GetDozeSupport:
-            return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
-                    displayHook<decltype(&Display::getDozeSupport),
-                    &Display::getDozeSupport, int32_t*>);
-        case FunctionDescriptor::GetHdrCapabilities:
-            return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
-                    displayHook<decltype(&Display::getHdrCapabilities),
-                    &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
-                    float*, float*>);
-        case FunctionDescriptor::GetReleaseFences:
-            return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
-                    displayHook<decltype(&Display::getReleaseFences),
-                    &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
-                    int32_t*>);
-        case FunctionDescriptor::PresentDisplay:
-            return asFP<HWC2_PFN_PRESENT_DISPLAY>(
-                    displayHook<decltype(&Display::present),
-                    &Display::present, int32_t*>);
-        case FunctionDescriptor::SetActiveConfig:
-            return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
-                    displayHook<decltype(&Display::setActiveConfig),
-                    &Display::setActiveConfig, hwc2_config_t>);
-        case FunctionDescriptor::SetClientTarget:
-            return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
-                    displayHook<decltype(&Display::setClientTarget),
-                    &Display::setClientTarget, buffer_handle_t, int32_t,
-                    int32_t, hwc_region_t>);
-        case FunctionDescriptor::SetColorMode:
-            return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook);
-        case FunctionDescriptor::SetColorTransform:
-            return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook);
-        case FunctionDescriptor::SetOutputBuffer:
-            return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
-                    displayHook<decltype(&Display::setOutputBuffer),
-                    &Display::setOutputBuffer, buffer_handle_t, int32_t>);
-        case FunctionDescriptor::SetPowerMode:
-            return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook);
-        case FunctionDescriptor::SetVsyncEnabled:
-            return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook);
-        case FunctionDescriptor::ValidateDisplay:
-            return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
-                    displayHook<decltype(&Display::validate),
-                    &Display::validate, uint32_t*, uint32_t*>);
-        case FunctionDescriptor::GetClientTargetSupport:
-            return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
-                    displayHook<decltype(&Display::getClientTargetSupport),
-                    &Display::getClientTargetSupport, uint32_t, uint32_t,
-                                                      int32_t, int32_t>);
-
-        // Layer functions
-        case FunctionDescriptor::SetCursorPosition:
-            return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
-                    layerHook<decltype(&Layer::setCursorPosition),
-                    &Layer::setCursorPosition, int32_t, int32_t>);
-        case FunctionDescriptor::SetLayerBuffer:
-            return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
-                    layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
-                    buffer_handle_t, int32_t>);
-        case FunctionDescriptor::SetLayerSurfaceDamage:
-            return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
-                    layerHook<decltype(&Layer::setSurfaceDamage),
-                    &Layer::setSurfaceDamage, hwc_region_t>);
-
-        // Layer state functions
-        case FunctionDescriptor::SetLayerBlendMode:
-            return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
-                    setLayerBlendModeHook);
-        case FunctionDescriptor::SetLayerColor:
-            return asFP<HWC2_PFN_SET_LAYER_COLOR>(
-                    layerHook<decltype(&Layer::setColor), &Layer::setColor,
-                    hwc_color_t>);
-        case FunctionDescriptor::SetLayerCompositionType:
-            return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
-                    setLayerCompositionTypeHook);
-        case FunctionDescriptor::SetLayerDataspace:
-            return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerDataspaceHook);
-        case FunctionDescriptor::SetLayerDisplayFrame:
-            return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
-                    layerHook<decltype(&Layer::setDisplayFrame),
-                    &Layer::setDisplayFrame, hwc_rect_t>);
-        case FunctionDescriptor::SetLayerPlaneAlpha:
-            return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
-                    layerHook<decltype(&Layer::setPlaneAlpha),
-                    &Layer::setPlaneAlpha, float>);
-        case FunctionDescriptor::SetLayerSidebandStream:
-            return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
-                    layerHook<decltype(&Layer::setSidebandStream),
-                    &Layer::setSidebandStream, const native_handle_t*>);
-        case FunctionDescriptor::SetLayerSourceCrop:
-            return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
-                    layerHook<decltype(&Layer::setSourceCrop),
-                    &Layer::setSourceCrop, hwc_frect_t>);
-        case FunctionDescriptor::SetLayerTransform:
-            return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerTransformHook);
-        case FunctionDescriptor::SetLayerVisibleRegion:
-            return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
-                    layerHook<decltype(&Layer::setVisibleRegion),
-                    &Layer::setVisibleRegion, hwc_region_t>);
-        case FunctionDescriptor::SetLayerZOrder:
-            return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerZOrderHook);
-
-        default:
-            ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
-                    static_cast<int32_t>(descriptor),
-                    to_string(descriptor).c_str());
-            return nullptr;
-    }
-}
-
-// Device functions
-
-Error HWC2On1Adapter::createVirtualDisplay(uint32_t width,
-        uint32_t height, hwc2_display_t* outDisplay) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (mHwc1VirtualDisplay) {
-        // We have already allocated our only HWC1 virtual display
-        ALOGE("createVirtualDisplay: HWC1 virtual display already allocated");
-        return Error::NoResources;
-    }
-
-    mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
-            HWC2::DisplayType::Virtual);
-    mHwc1VirtualDisplay->populateConfigs(width, height);
-    const auto displayId = mHwc1VirtualDisplay->getId();
-    mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL] = displayId;
-    mHwc1VirtualDisplay->setHwc1Id(HWC_DISPLAY_VIRTUAL);
-    mDisplays.emplace(displayId, mHwc1VirtualDisplay);
-    *outDisplay = displayId;
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::destroyVirtualDisplay(hwc2_display_t displayId) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (!mHwc1VirtualDisplay || (mHwc1VirtualDisplay->getId() != displayId)) {
-        return Error::BadDisplay;
-    }
-
-    mHwc1VirtualDisplay.reset();
-    mHwc1DisplayMap.erase(HWC_DISPLAY_VIRTUAL);
-    mDisplays.erase(displayId);
-
-    return Error::None;
-}
-
-void HWC2On1Adapter::dump(uint32_t* outSize, char* outBuffer) {
-    if (outBuffer != nullptr) {
-        auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
-        *outSize = static_cast<uint32_t>(copiedBytes);
-        return;
-    }
-
-    std::stringstream output;
-
-    output << "-- HWC2On1Adapter --\n";
-
-    output << "Adapting to a HWC 1." << static_cast<int>(mHwc1MinorVersion) <<
-            " device\n";
-
-    // Attempt to acquire the lock for 1 second, but proceed without the lock
-    // after that, so we can still get some information if we're deadlocked
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex,
-            std::defer_lock);
-    lock.try_lock_for(1s);
-
-    if (mCapabilities.empty()) {
-        output << "Capabilities: None\n";
-    } else {
-        output << "Capabilities:\n";
-        for (auto capability : mCapabilities) {
-            output << "  " << to_string(capability) << '\n';
-        }
-    }
-
-    output << "Displays:\n";
-    for (const auto& element : mDisplays) {
-        const auto& display = element.second;
-        output << display->dump();
-    }
-    output << '\n';
-
-    // Release the lock before calling into HWC1, and since we no longer require
-    // mutual exclusion to access mCapabilities or mDisplays
-    lock.unlock();
-
-    if (mHwc1Device->dump) {
-        output << "HWC1 dump:\n";
-        std::vector<char> hwc1Dump(4096);
-        // Call with size - 1 to preserve a null character at the end
-        mHwc1Device->dump(mHwc1Device, hwc1Dump.data(),
-                static_cast<int>(hwc1Dump.size() - 1));
-        output << hwc1Dump.data();
-    }
-
-    mDumpString = output.str();
-    *outSize = static_cast<uint32_t>(mDumpString.size());
-}
-
-uint32_t HWC2On1Adapter::getMaxVirtualDisplayCount() {
-    return mHwc1SupportsVirtualDisplays ? 1 : 0;
-}
-
-static bool isValid(Callback descriptor) {
-    switch (descriptor) {
-        case Callback::Hotplug: // Fall-through
-        case Callback::Refresh: // Fall-through
-        case Callback::Vsync: return true;
-        default: return false;
-    }
-}
-
-Error HWC2On1Adapter::registerCallback(Callback descriptor,
-        hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
-    if (!isValid(descriptor)) {
-        return Error::BadParameter;
-    }
-
-    ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
-            callbackData, pointer);
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    if (pointer != nullptr) {
-        mCallbacks[descriptor] = {callbackData, pointer};
-    } else {
-        ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
-        mCallbacks.erase(descriptor);
-        return Error::None;
-    }
-
-    bool hasPendingInvalidate = false;
-    std::vector<hwc2_display_t> displayIds;
-    std::vector<std::pair<hwc2_display_t, int64_t>> pendingVsyncs;
-    std::vector<std::pair<hwc2_display_t, int>> pendingHotplugs;
-
-    if (descriptor == Callback::Refresh) {
-        hasPendingInvalidate = mHasPendingInvalidate;
-        if (hasPendingInvalidate) {
-            for (auto& displayPair : mDisplays) {
-                displayIds.emplace_back(displayPair.first);
-            }
-        }
-        mHasPendingInvalidate = false;
-    } else if (descriptor == Callback::Vsync) {
-        for (auto pending : mPendingVsyncs) {
-            auto hwc1DisplayId = pending.first;
-            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-                ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d",
-                        hwc1DisplayId);
-                continue;
-            }
-            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-            auto timestamp = pending.second;
-            pendingVsyncs.emplace_back(displayId, timestamp);
-        }
-        mPendingVsyncs.clear();
-    } else if (descriptor == Callback::Hotplug) {
-        // Hotplug the primary display
-        pendingHotplugs.emplace_back(mHwc1DisplayMap[HWC_DISPLAY_PRIMARY],
-                static_cast<int32_t>(Connection::Connected));
-
-        for (auto pending : mPendingHotplugs) {
-            auto hwc1DisplayId = pending.first;
-            if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-                ALOGE("hwc1Hotplug: Couldn't find display for HWC1 id %d",
-                        hwc1DisplayId);
-                continue;
-            }
-            auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-            auto connected = pending.second;
-            pendingHotplugs.emplace_back(displayId, connected);
-        }
-    }
-
-    // Call pending callbacks without the state lock held
-    lock.unlock();
-
-    if (hasPendingInvalidate) {
-        auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
-        for (auto displayId : displayIds) {
-            refresh(callbackData, displayId);
-        }
-    }
-    if (!pendingVsyncs.empty()) {
-        auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
-        for (auto& pendingVsync : pendingVsyncs) {
-            vsync(callbackData, pendingVsync.first, pendingVsync.second);
-        }
-    }
-    if (!pendingHotplugs.empty()) {
-        auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
-        for (auto& pendingHotplug : pendingHotplugs) {
-            hotplug(callbackData, pendingHotplug.first, pendingHotplug.second);
-        }
-    }
-    return Error::None;
-}
-
-// Display functions
-
-std::atomic<hwc2_display_t> HWC2On1Adapter::Display::sNextId(1);
-
-HWC2On1Adapter::Display::Display(HWC2On1Adapter& device, HWC2::DisplayType type)
-  : mId(sNextId++),
-    mDevice(device),
-    mStateMutex(),
-    mHwc1RequestedContents(nullptr),
-    mRetireFence(),
-    mChanges(),
-    mHwc1Id(-1),
-    mConfigs(),
-    mActiveConfig(nullptr),
-    mActiveColorMode(static_cast<android_color_mode_t>(-1)),
-    mName(),
-    mType(type),
-    mPowerMode(PowerMode::Off),
-    mVsyncEnabled(Vsync::Invalid),
-    mClientTarget(),
-    mOutputBuffer(),
-    mHasColorTransform(false),
-    mLayers(),
-    mHwc1LayerMap(),
-    mNumAvailableRects(0),
-    mNextAvailableRect(nullptr),
-    mGeometryChanged(false)
-    {}
-
-Error HWC2On1Adapter::Display::acceptChanges() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        ALOGV("[%" PRIu64 "] acceptChanges failed, not validated", mId);
-        return Error::NotValidated;
-    }
-
-    ALOGV("[%" PRIu64 "] acceptChanges", mId);
-
-    for (auto& change : mChanges->getTypeChanges()) {
-        auto layerId = change.first;
-        auto type = change.second;
-        if (mDevice.mLayers.count(layerId) == 0) {
-            // This should never happen but somehow does.
-            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
-                  layerId);
-            continue;
-        }
-        auto layer = mDevice.mLayers[layerId];
-        layer->setCompositionType(type);
-    }
-
-    mChanges->clearTypeChanges();
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::createLayer(hwc2_layer_t* outLayerId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
-    mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
-    *outLayerId = layer->getId();
-    ALOGV("[%" PRIu64 "] created layer %" PRIu64, mId, *outLayerId);
-    markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::destroyLayer(hwc2_layer_t layerId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    const auto mapLayer = mDevice.mLayers.find(layerId);
-    if (mapLayer == mDevice.mLayers.end()) {
-        ALOGV("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer",
-                mId, layerId);
-        return Error::BadLayer;
-    }
-    const auto layer = mapLayer->second;
-    mDevice.mLayers.erase(mapLayer);
-    const auto zRange = mLayers.equal_range(layer);
-    for (auto current = zRange.first; current != zRange.second; ++current) {
-        if (**current == *layer) {
-            current = mLayers.erase(current);
-            break;
-        }
-    }
-    ALOGV("[%" PRIu64 "] destroyed layer %" PRIu64, mId, layerId);
-    markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getActiveConfig(hwc2_config_t* outConfig) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mActiveConfig) {
-        ALOGV("[%" PRIu64 "] getActiveConfig --> %s", mId,
-                to_string(Error::BadConfig).c_str());
-        return Error::BadConfig;
-    }
-    auto configId = mActiveConfig->getId();
-    ALOGV("[%" PRIu64 "] getActiveConfig --> %u", mId, configId);
-    *outConfig = configId;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getAttribute(hwc2_config_t configId,
-        Attribute attribute, int32_t* outValue) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
-        ALOGV("[%" PRIu64 "] getAttribute failed: bad config (%u)", mId,
-                configId);
-        return Error::BadConfig;
-    }
-    *outValue = mConfigs[configId]->getAttribute(attribute);
-    ALOGV("[%" PRIu64 "] getAttribute(%u, %s) --> %d", mId, configId,
-            to_string(attribute).c_str(), *outValue);
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getChangedCompositionTypes(
-        uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        ALOGE("[%" PRIu64 "] getChangedCompositionTypes failed: not validated",
-                mId);
-        return Error::NotValidated;
-    }
-
-    if ((outLayers == nullptr) || (outTypes == nullptr)) {
-        *outNumElements = mChanges->getTypeChanges().size();
-        return Error::None;
-    }
-
-    uint32_t numWritten = 0;
-    for (const auto& element : mChanges->getTypeChanges()) {
-        if (numWritten == *outNumElements) {
-            break;
-        }
-        auto layerId = element.first;
-        auto intType = static_cast<int32_t>(element.second);
-        ALOGV("Adding %" PRIu64 " %s", layerId,
-                to_string(element.second).c_str());
-        outLayers[numWritten] = layerId;
-        outTypes[numWritten] = intType;
-        ++numWritten;
-    }
-    *outNumElements = numWritten;
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getColorModes(uint32_t* outNumModes,
-        int32_t* outModes) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outModes) {
-        *outNumModes = mColorModes.size();
-        return Error::None;
-    }
-    uint32_t numModes = std::min(*outNumModes,
-            static_cast<uint32_t>(mColorModes.size()));
-    std::copy_n(mColorModes.cbegin(), numModes, outModes);
-    *outNumModes = numModes;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getConfigs(uint32_t* outNumConfigs,
-        hwc2_config_t* outConfigs) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outConfigs) {
-        *outNumConfigs = mConfigs.size();
-        return Error::None;
-    }
-    uint32_t numWritten = 0;
-    for (const auto& config : mConfigs) {
-        if (numWritten == *outNumConfigs) {
-            break;
-        }
-        outConfigs[numWritten] = config->getId();
-        ++numWritten;
-    }
-    *outNumConfigs = numWritten;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getDozeSupport(int32_t* outSupport) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (mDevice.mHwc1MinorVersion < 4 || mHwc1Id != 0) {
-        *outSupport = 0;
-    } else {
-        *outSupport = 1;
-    }
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
-        int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
-        float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
-    // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
-    *outNumTypes = 0;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!outName) {
-        *outSize = mName.size();
-        return Error::None;
-    }
-    auto numCopied = mName.copy(outName, *outSize);
-    *outSize = numCopied;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getReleaseFences(uint32_t* outNumElements,
-        hwc2_layer_t* outLayers, int32_t* outFences) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    uint32_t numWritten = 0;
-    bool outputsNonNull = (outLayers != nullptr) && (outFences != nullptr);
-    for (const auto& layer : mLayers) {
-        if (outputsNonNull && (numWritten == *outNumElements)) {
-            break;
-        }
-
-        auto releaseFence = layer->getReleaseFence();
-        if (releaseFence != MiniFence::NO_FENCE) {
-            if (outputsNonNull) {
-                outLayers[numWritten] = layer->getId();
-                outFences[numWritten] = releaseFence->dup();
-            }
-            ++numWritten;
-        }
-    }
-    *outNumElements = numWritten;
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getRequests(int32_t* outDisplayRequests,
-        uint32_t* outNumElements, hwc2_layer_t* outLayers,
-        int32_t* outLayerRequests) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        return Error::NotValidated;
-    }
-
-    if (outLayers == nullptr || outLayerRequests == nullptr) {
-        *outNumElements = mChanges->getNumLayerRequests();
-        return Error::None;
-    }
-
-    // Display requests (HWC2::DisplayRequest) are not supported by hwc1:
-    // A hwc1 has always zero requests for the client.
-    *outDisplayRequests = 0;
-
-    uint32_t numWritten = 0;
-    for (const auto& request : mChanges->getLayerRequests()) {
-        if (numWritten == *outNumElements) {
-            break;
-        }
-        outLayers[numWritten] = request.first;
-        outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
-        ++numWritten;
-    }
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getType(int32_t* outType) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    *outType = static_cast<int32_t>(mType);
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::present(int32_t* outRetireFence) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (mChanges) {
-        Error error = mDevice.setAllDisplays();
-        if (error != Error::None) {
-            ALOGE("[%" PRIu64 "] present: setAllDisplaysFailed (%s)", mId,
-                    to_string(error).c_str());
-            return error;
-        }
-    }
-
-    *outRetireFence = mRetireFence.get()->dup();
-    ALOGV("[%" PRIu64 "] present returning retire fence %d", mId,
-            *outRetireFence);
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::setActiveConfig(hwc2_config_t configId) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    auto config = getConfig(configId);
-    if (!config) {
-        return Error::BadConfig;
-    }
-    if (config == mActiveConfig) {
-        return Error::None;
-    }
-
-    if (mDevice.mHwc1MinorVersion >= 4) {
-        uint32_t hwc1Id = 0;
-        auto error = config->getHwc1IdForColorMode(mActiveColorMode, &hwc1Id);
-        if (error != Error::None) {
-            return error;
-        }
-
-        int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
-                mHwc1Id, static_cast<int>(hwc1Id));
-        if (intError != 0) {
-            ALOGE("setActiveConfig: Failed to set active config on HWC1 (%d)",
-                intError);
-            return Error::BadConfig;
-        }
-        mActiveConfig = config;
-    }
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::setClientTarget(buffer_handle_t target,
-        int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setClientTarget(%p, %d)", mId, target, acquireFence);
-    mClientTarget.setBuffer(target);
-    mClientTarget.setFence(acquireFence);
-    // dataspace and damage can't be used by HWC1, so ignore them
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::setColorMode(android_color_mode_t mode) {
-    std::unique_lock<std::recursive_mutex> lock (mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setColorMode(%d)", mId, mode);
-
-    if (mode == mActiveColorMode) {
-        return Error::None;
-    }
-    if (mColorModes.count(mode) == 0) {
-        ALOGE("[%" PRIu64 "] Mode %d not found in mColorModes", mId, mode);
-        return Error::Unsupported;
-    }
-
-    uint32_t hwc1Config = 0;
-    auto error = mActiveConfig->getHwc1IdForColorMode(mode, &hwc1Config);
-    if (error != Error::None) {
-        return error;
-    }
-
-    ALOGV("[%" PRIu64 "] Setting HWC1 config %u", mId, hwc1Config);
-    int intError = mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device,
-            mHwc1Id, hwc1Config);
-    if (intError != 0) {
-        ALOGE("[%" PRIu64 "] Failed to set HWC1 config (%d)", mId, intError);
-        return Error::Unsupported;
-    }
-
-    mActiveColorMode = mode;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::setColorTransform(android_color_transform_t hint) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("%" PRIu64 "] setColorTransform(%d)", mId,
-            static_cast<int32_t>(hint));
-    mHasColorTransform = (hint != HAL_COLOR_TRANSFORM_IDENTITY);
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::setOutputBuffer(buffer_handle_t buffer,
-        int32_t releaseFence) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] setOutputBuffer(%p, %d)", mId, buffer, releaseFence);
-    mOutputBuffer.setBuffer(buffer);
-    mOutputBuffer.setFence(releaseFence);
-    return Error::None;
-}
-
-static bool isValid(PowerMode mode) {
-    switch (mode) {
-        case PowerMode::Off: // Fall-through
-        case PowerMode::DozeSuspend: // Fall-through
-        case PowerMode::Doze: // Fall-through
-        case PowerMode::On: return true;
-    }
-}
-
-static int getHwc1PowerMode(PowerMode mode) {
-    switch (mode) {
-        case PowerMode::Off: return HWC_POWER_MODE_OFF;
-        case PowerMode::DozeSuspend: return HWC_POWER_MODE_DOZE_SUSPEND;
-        case PowerMode::Doze: return HWC_POWER_MODE_DOZE;
-        case PowerMode::On: return HWC_POWER_MODE_NORMAL;
-    }
-}
-
-Error HWC2On1Adapter::Display::setPowerMode(PowerMode mode) {
-    if (!isValid(mode)) {
-        return Error::BadParameter;
-    }
-    if (mode == mPowerMode) {
-        return Error::None;
-    }
-
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    int error = 0;
-    if (mDevice.mHwc1MinorVersion < 4) {
-        error = mDevice.mHwc1Device->blank(mDevice.mHwc1Device, mHwc1Id,
-                mode == PowerMode::Off);
-    } else {
-        error = mDevice.mHwc1Device->setPowerMode(mDevice.mHwc1Device,
-                mHwc1Id, getHwc1PowerMode(mode));
-    }
-    ALOGE_IF(error != 0, "setPowerMode: Failed to set power mode on HWC1 (%d)",
-            error);
-
-    ALOGV("[%" PRIu64 "] setPowerMode(%s)", mId, to_string(mode).c_str());
-    mPowerMode = mode;
-    return Error::None;
-}
-
-static bool isValid(Vsync enable) {
-    switch (enable) {
-        case Vsync::Enable: // Fall-through
-        case Vsync::Disable: return true;
-        case Vsync::Invalid: return false;
-    }
-}
-
-Error HWC2On1Adapter::Display::setVsyncEnabled(Vsync enable) {
-    if (!isValid(enable)) {
-        return Error::BadParameter;
-    }
-    if (enable == mVsyncEnabled) {
-        return Error::None;
-    }
-
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    int error = mDevice.mHwc1Device->eventControl(mDevice.mHwc1Device,
-            mHwc1Id, HWC_EVENT_VSYNC, enable == Vsync::Enable);
-    ALOGE_IF(error != 0, "setVsyncEnabled: Failed to set vsync on HWC1 (%d)",
-            error);
-
-    mVsyncEnabled = enable;
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::validate(uint32_t* outNumTypes,
-        uint32_t* outNumRequests) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges) {
-        if (!mDevice.prepareAllDisplays()) {
-            return Error::BadDisplay;
-        }
-    } else {
-        ALOGE("Validate was called more than once!");
-    }
-
-    *outNumTypes = mChanges->getNumTypes();
-    *outNumRequests = mChanges->getNumLayerRequests();
-    ALOGV("[%" PRIu64 "] validate --> %u types, %u requests", mId, *outNumTypes,
-            *outNumRequests);
-    for (auto request : mChanges->getTypeChanges()) {
-        ALOGV("Layer %" PRIu64 " --> %s", request.first,
-                to_string(request.second).c_str());
-    }
-    return *outNumTypes > 0 ? Error::HasChanges : Error::None;
-}
-
-Error HWC2On1Adapter::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    const auto mapLayer = mDevice.mLayers.find(layerId);
-    if (mapLayer == mDevice.mLayers.end()) {
-        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer", mId);
-        return Error::BadLayer;
-    }
-
-    const auto layer = mapLayer->second;
-    const auto zRange = mLayers.equal_range(layer);
-    bool layerOnDisplay = false;
-    for (auto current = zRange.first; current != zRange.second; ++current) {
-        if (**current == *layer) {
-            if ((*current)->getZ() == z) {
-                // Don't change anything if the Z hasn't changed
-                return Error::None;
-            }
-            current = mLayers.erase(current);
-            layerOnDisplay = true;
-            break;
-        }
-    }
-
-    if (!layerOnDisplay) {
-        ALOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display",
-                mId);
-        return Error::BadLayer;
-    }
-
-    layer->setZ(z);
-    mLayers.emplace(std::move(layer));
-    markGeometryChanged();
-
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Display::getClientTargetSupport(uint32_t width, uint32_t height,
-                                      int32_t format, int32_t dataspace){
-    if (mActiveConfig == nullptr) {
-        return Error::Unsupported;
-    }
-
-    if (width == mActiveConfig->getAttribute(Attribute::Width) &&
-            height == mActiveConfig->getAttribute(Attribute::Height) &&
-            format == HAL_PIXEL_FORMAT_RGBA_8888 &&
-            dataspace == HAL_DATASPACE_UNKNOWN) {
-        return Error::None;
-    }
-
-    return Error::Unsupported;
-}
-
-static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_COLOR_TRANSFORM,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-static constexpr uint32_t ATTRIBUTES_WITHOUT_COLOR[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-static constexpr size_t NUM_ATTRIBUTES_WITH_COLOR =
-        sizeof(ATTRIBUTES_WITH_COLOR) / sizeof(uint32_t);
-static_assert(sizeof(ATTRIBUTES_WITH_COLOR) > sizeof(ATTRIBUTES_WITHOUT_COLOR),
-        "Attribute tables have unexpected sizes");
-
-static constexpr uint32_t ATTRIBUTE_MAP_WITH_COLOR[] = {
-    6, // HWC_DISPLAY_NO_ATTRIBUTE = 0
-    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
-    1, // HWC_DISPLAY_WIDTH = 2,
-    2, // HWC_DISPLAY_HEIGHT = 3,
-    3, // HWC_DISPLAY_DPI_X = 4,
-    4, // HWC_DISPLAY_DPI_Y = 5,
-    5, // HWC_DISPLAY_COLOR_TRANSFORM = 6,
-};
-
-static constexpr uint32_t ATTRIBUTE_MAP_WITHOUT_COLOR[] = {
-    5, // HWC_DISPLAY_NO_ATTRIBUTE = 0
-    0, // HWC_DISPLAY_VSYNC_PERIOD = 1,
-    1, // HWC_DISPLAY_WIDTH = 2,
-    2, // HWC_DISPLAY_HEIGHT = 3,
-    3, // HWC_DISPLAY_DPI_X = 4,
-    4, // HWC_DISPLAY_DPI_Y = 5,
-};
-
-template <uint32_t attribute>
-static constexpr bool attributesMatch()
-{
-    bool match = (attribute ==
-            ATTRIBUTES_WITH_COLOR[ATTRIBUTE_MAP_WITH_COLOR[attribute]]);
-    if (attribute == HWC_DISPLAY_COLOR_TRANSFORM) {
-        return match;
-    }
-
-    return match && (attribute ==
-            ATTRIBUTES_WITHOUT_COLOR[ATTRIBUTE_MAP_WITHOUT_COLOR[attribute]]);
-}
-static_assert(attributesMatch<HWC_DISPLAY_VSYNC_PERIOD>(),
-        "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_WIDTH>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_HEIGHT>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_DPI_X>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_DPI_Y>(), "Tables out of sync");
-static_assert(attributesMatch<HWC_DISPLAY_COLOR_TRANSFORM>(),
-        "Tables out of sync");
-
-void HWC2On1Adapter::Display::populateConfigs() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    ALOGV("[%" PRIu64 "] populateConfigs", mId);
-
-    if (mHwc1Id == -1) {
-        ALOGE("populateConfigs: HWC1 ID not set");
-        return;
-    }
-
-    const size_t MAX_NUM_CONFIGS = 128;
-    uint32_t configs[MAX_NUM_CONFIGS] = {};
-    size_t numConfigs = MAX_NUM_CONFIGS;
-    mDevice.mHwc1Device->getDisplayConfigs(mDevice.mHwc1Device, mHwc1Id,
-            configs, &numConfigs);
-
-    for (size_t c = 0; c < numConfigs; ++c) {
-        uint32_t hwc1ConfigId = configs[c];
-        auto newConfig = std::make_shared<Config>(*this);
-
-        int32_t values[NUM_ATTRIBUTES_WITH_COLOR] = {};
-        bool hasColor = true;
-        auto result = mDevice.mHwc1Device->getDisplayAttributes(
-                mDevice.mHwc1Device, mHwc1Id, hwc1ConfigId,
-                ATTRIBUTES_WITH_COLOR, values);
-        if (result != 0) {
-            mDevice.mHwc1Device->getDisplayAttributes(mDevice.mHwc1Device,
-                    mHwc1Id, hwc1ConfigId, ATTRIBUTES_WITHOUT_COLOR, values);
-            hasColor = false;
-        }
-
-        auto attributeMap = hasColor ?
-                ATTRIBUTE_MAP_WITH_COLOR : ATTRIBUTE_MAP_WITHOUT_COLOR;
-
-        newConfig->setAttribute(Attribute::VsyncPeriod,
-                values[attributeMap[HWC_DISPLAY_VSYNC_PERIOD]]);
-        newConfig->setAttribute(Attribute::Width,
-                values[attributeMap[HWC_DISPLAY_WIDTH]]);
-        newConfig->setAttribute(Attribute::Height,
-                values[attributeMap[HWC_DISPLAY_HEIGHT]]);
-        newConfig->setAttribute(Attribute::DpiX,
-                values[attributeMap[HWC_DISPLAY_DPI_X]]);
-        newConfig->setAttribute(Attribute::DpiY,
-                values[attributeMap[HWC_DISPLAY_DPI_Y]]);
-        if (hasColor) {
-            // In HWC1, color modes are referred to as color transforms. To avoid confusion with
-            // the HWC2 concept of color transforms, we internally refer to them as color modes for
-            // both HWC1 and 2.
-            newConfig->setAttribute(ColorMode,
-                    values[attributeMap[HWC_DISPLAY_COLOR_TRANSFORM]]);
-        }
-
-        // We can only do this after attempting to read the color mode
-        newConfig->setHwc1Id(hwc1ConfigId);
-
-        for (auto& existingConfig : mConfigs) {
-            if (existingConfig->merge(*newConfig)) {
-                ALOGV("Merged config %d with existing config %u: %s",
-                        hwc1ConfigId, existingConfig->getId(),
-                        existingConfig->toString().c_str());
-                newConfig.reset();
-                break;
-            }
-        }
-
-        // If it wasn't merged with any existing config, add it to the end
-        if (newConfig) {
-            newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
-            ALOGV("Found new config %u: %s", newConfig->getId(),
-                    newConfig->toString().c_str());
-            mConfigs.emplace_back(std::move(newConfig));
-        }
-    }
-
-    initializeActiveConfig();
-    populateColorModes();
-}
-
-void HWC2On1Adapter::Display::populateConfigs(uint32_t width, uint32_t height) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    mConfigs.emplace_back(std::make_shared<Config>(*this));
-    auto& config = mConfigs[0];
-
-    config->setAttribute(Attribute::Width, static_cast<int32_t>(width));
-    config->setAttribute(Attribute::Height, static_cast<int32_t>(height));
-    config->setHwc1Id(0);
-    config->setId(0);
-    mActiveConfig = config;
-}
-
-bool HWC2On1Adapter::Display::prepare() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    // Only prepare display contents for displays HWC1 knows about
-    if (mHwc1Id == -1) {
-        return true;
-    }
-
-    // It doesn't make sense to prepare a display for which there is no active
-    // config, so return early
-    if (!mActiveConfig) {
-        ALOGE("[%" PRIu64 "] Attempted to prepare, but no config active", mId);
-        return false;
-    }
-
-    allocateRequestedContents();
-    assignHwc1LayerIds();
-
-    mHwc1RequestedContents->retireFenceFd = -1;
-    mHwc1RequestedContents->flags = 0;
-    if (mGeometryChanged) {
-        mHwc1RequestedContents->flags |= HWC_GEOMETRY_CHANGED;
-    }
-    mHwc1RequestedContents->outbuf = mOutputBuffer.getBuffer();
-    mHwc1RequestedContents->outbufAcquireFenceFd = mOutputBuffer.getFence();
-
-    // +1 is for framebuffer target layer.
-    mHwc1RequestedContents->numHwLayers = mLayers.size() + 1;
-    for (auto& layer : mLayers) {
-        auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
-        hwc1Layer.releaseFenceFd = -1;
-        hwc1Layer.acquireFenceFd = -1;
-        ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
-        layer->applyState(hwc1Layer);
-    }
-
-    prepareFramebufferTarget();
-
-    resetGeometryMarker();
-
-    return true;
-}
-
-void HWC2On1Adapter::Display::generateChanges() {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    mChanges.reset(new Changes);
-
-    size_t numLayers = mHwc1RequestedContents->numHwLayers;
-    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
-        const auto& receivedLayer = mHwc1RequestedContents->hwLayers[hwc1Id];
-        if (mHwc1LayerMap.count(hwc1Id) == 0) {
-            ALOGE_IF(receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET,
-                    "generateChanges: HWC1 layer %zd doesn't have a"
-                    " matching HWC2 layer, and isn't the framebuffer target",
-                    hwc1Id);
-            continue;
-        }
-
-        Layer& layer = *mHwc1LayerMap[hwc1Id];
-        updateTypeChanges(receivedLayer, layer);
-        updateLayerRequests(receivedLayer, layer);
-    }
-}
-
-bool HWC2On1Adapter::Display::hasChanges() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    return mChanges != nullptr;
-}
-
-Error HWC2On1Adapter::Display::set(hwc_display_contents_1& hwcContents) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    if (!mChanges || (mChanges->getNumTypes() > 0)) {
-        ALOGE("[%" PRIu64 "] set failed: not validated", mId);
-        return Error::NotValidated;
-    }
-
-    // Set up the client/framebuffer target
-    auto numLayers = hwcContents.numHwLayers;
-
-    // Close acquire fences on FRAMEBUFFER layers, since they will not be used
-    // by HWC
-    for (size_t l = 0; l < numLayers - 1; ++l) {
-        auto& layer = hwcContents.hwLayers[l];
-        if (layer.compositionType == HWC_FRAMEBUFFER) {
-            ALOGV("Closing fence %d for layer %zd", layer.acquireFenceFd, l);
-            close(layer.acquireFenceFd);
-            layer.acquireFenceFd = -1;
-        }
-    }
-
-    auto& clientTargetLayer = hwcContents.hwLayers[numLayers - 1];
-    if (clientTargetLayer.compositionType == HWC_FRAMEBUFFER_TARGET) {
-        clientTargetLayer.handle = mClientTarget.getBuffer();
-        clientTargetLayer.acquireFenceFd = mClientTarget.getFence();
-    } else {
-        ALOGE("[%" PRIu64 "] set: last HWC layer wasn't FRAMEBUFFER_TARGET",
-                mId);
-    }
-
-    mChanges.reset();
-
-    return Error::None;
-}
-
-void HWC2On1Adapter::Display::addRetireFence(int fenceFd) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    mRetireFence.add(fenceFd);
-}
-
-void HWC2On1Adapter::Display::addReleaseFences(
-        const hwc_display_contents_1_t& hwcContents) {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    size_t numLayers = hwcContents.numHwLayers;
-    for (size_t hwc1Id = 0; hwc1Id < numLayers; ++hwc1Id) {
-        const auto& receivedLayer = hwcContents.hwLayers[hwc1Id];
-        if (mHwc1LayerMap.count(hwc1Id) == 0) {
-            if (receivedLayer.compositionType != HWC_FRAMEBUFFER_TARGET) {
-                ALOGE("addReleaseFences: HWC1 layer %zd doesn't have a"
-                        " matching HWC2 layer, and isn't the framebuffer"
-                        " target", hwc1Id);
-            }
-            // Close the framebuffer target release fence since we will use the
-            // display retire fence instead
-            if (receivedLayer.releaseFenceFd != -1) {
-                close(receivedLayer.releaseFenceFd);
-            }
-            continue;
-        }
-
-        Layer& layer = *mHwc1LayerMap[hwc1Id];
-        ALOGV("Adding release fence %d to layer %" PRIu64,
-                receivedLayer.releaseFenceFd, layer.getId());
-        layer.addReleaseFence(receivedLayer.releaseFenceFd);
-    }
-}
-
-bool HWC2On1Adapter::Display::hasColorTransform() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-    return mHasColorTransform;
-}
-
-static std::string hwc1CompositionString(int32_t type) {
-    switch (type) {
-        case HWC_FRAMEBUFFER: return "Framebuffer";
-        case HWC_OVERLAY: return "Overlay";
-        case HWC_BACKGROUND: return "Background";
-        case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget";
-        case HWC_SIDEBAND: return "Sideband";
-        case HWC_CURSOR_OVERLAY: return "CursorOverlay";
-        default:
-            return std::string("Unknown (") + std::to_string(type) + ")";
-    }
-}
-
-static std::string hwc1TransformString(int32_t transform) {
-    switch (transform) {
-        case 0: return "None";
-        case HWC_TRANSFORM_FLIP_H: return "FlipH";
-        case HWC_TRANSFORM_FLIP_V: return "FlipV";
-        case HWC_TRANSFORM_ROT_90: return "Rotate90";
-        case HWC_TRANSFORM_ROT_180: return "Rotate180";
-        case HWC_TRANSFORM_ROT_270: return "Rotate270";
-        case HWC_TRANSFORM_FLIP_H_ROT_90: return "FlipHRotate90";
-        case HWC_TRANSFORM_FLIP_V_ROT_90: return "FlipVRotate90";
-        default:
-            return std::string("Unknown (") + std::to_string(transform) + ")";
-    }
-}
-
-static std::string hwc1BlendModeString(int32_t mode) {
-    switch (mode) {
-        case HWC_BLENDING_NONE: return "None";
-        case HWC_BLENDING_PREMULT: return "Premultiplied";
-        case HWC_BLENDING_COVERAGE: return "Coverage";
-        default:
-            return std::string("Unknown (") + std::to_string(mode) + ")";
-    }
-}
-
-static std::string rectString(hwc_rect_t rect) {
-    std::stringstream output;
-    output << "[" << rect.left << ", " << rect.top << ", ";
-    output << rect.right << ", " << rect.bottom << "]";
-    return output.str();
-}
-
-static std::string approximateFloatString(float f) {
-    if (static_cast<int32_t>(f) == f) {
-        return std::to_string(static_cast<int32_t>(f));
-    }
-    int32_t truncated = static_cast<int32_t>(f * 10);
-    bool approximate = (static_cast<float>(truncated) != f * 10);
-    const size_t BUFFER_SIZE = 32;
-    char buffer[BUFFER_SIZE] = {};
-    auto bytesWritten = snprintf(buffer, BUFFER_SIZE,
-            "%s%.1f", approximate ? "~" : "", f);
-    return std::string(buffer, bytesWritten);
-}
-
-static std::string frectString(hwc_frect_t frect) {
-    std::stringstream output;
-    output << "[" << approximateFloatString(frect.left) << ", ";
-    output << approximateFloatString(frect.top) << ", ";
-    output << approximateFloatString(frect.right) << ", ";
-    output << approximateFloatString(frect.bottom) << "]";
-    return output.str();
-}
-
-static std::string colorString(hwc_color_t color) {
-    std::stringstream output;
-    output << "RGBA [";
-    output << static_cast<int32_t>(color.r) << ", ";
-    output << static_cast<int32_t>(color.g) << ", ";
-    output << static_cast<int32_t>(color.b) << ", ";
-    output << static_cast<int32_t>(color.a) << "]";
-    return output.str();
-}
-
-static std::string alphaString(float f) {
-    const size_t BUFFER_SIZE = 8;
-    char buffer[BUFFER_SIZE] = {};
-    auto bytesWritten = snprintf(buffer, BUFFER_SIZE, "%.3f", f);
-    return std::string(buffer, bytesWritten);
-}
-
-static std::string to_string(const hwc_layer_1_t& hwcLayer,
-        int32_t hwc1MinorVersion) {
-    const char* fill = "          ";
-
-    std::stringstream output;
-
-    output << "  Composition: " <<
-            hwc1CompositionString(hwcLayer.compositionType);
-
-    if (hwcLayer.compositionType == HWC_BACKGROUND) {
-        output << "  Color: " << colorString(hwcLayer.backgroundColor) << '\n';
-    } else if (hwcLayer.compositionType == HWC_SIDEBAND) {
-        output << "  Stream: " << hwcLayer.sidebandStream << '\n';
-    } else {
-        output << "  Buffer: " << hwcLayer.handle << "/" <<
-                hwcLayer.acquireFenceFd << '\n';
-    }
-
-    output << fill << "Display frame: " << rectString(hwcLayer.displayFrame) <<
-            '\n';
-
-    output << fill << "Source crop: ";
-    if (hwc1MinorVersion >= 3) {
-        output << frectString(hwcLayer.sourceCropf) << '\n';
-    } else {
-        output << rectString(hwcLayer.sourceCropi) << '\n';
-    }
-
-    output << fill << "Transform: " << hwc1TransformString(hwcLayer.transform);
-    output << "  Blend mode: " << hwc1BlendModeString(hwcLayer.blending);
-    if (hwcLayer.planeAlpha != 0xFF) {
-        output << "  Alpha: " << alphaString(hwcLayer.planeAlpha / 255.0f);
-    }
-    output << '\n';
-
-    if (hwcLayer.hints != 0) {
-        output << fill << "Hints:";
-        if ((hwcLayer.hints & HWC_HINT_TRIPLE_BUFFER) != 0) {
-            output << " TripleBuffer";
-        }
-        if ((hwcLayer.hints & HWC_HINT_CLEAR_FB) != 0) {
-            output << " ClearFB";
-        }
-        output << '\n';
-    }
-
-    if (hwcLayer.flags != 0) {
-        output << fill << "Flags:";
-        if ((hwcLayer.flags & HWC_SKIP_LAYER) != 0) {
-            output << " SkipLayer";
-        }
-        if ((hwcLayer.flags & HWC_IS_CURSOR_LAYER) != 0) {
-            output << " IsCursorLayer";
-        }
-        output << '\n';
-    }
-
-    return output.str();
-}
-
-static std::string to_string(const hwc_display_contents_1_t& hwcContents,
-        int32_t hwc1MinorVersion) {
-    const char* fill = "      ";
-
-    std::stringstream output;
-    output << fill << "Geometry changed: " <<
-            ((hwcContents.flags & HWC_GEOMETRY_CHANGED) != 0 ? "Y\n" : "N\n");
-
-    output << fill << hwcContents.numHwLayers << " Layer" <<
-            ((hwcContents.numHwLayers == 1) ? "\n" : "s\n");
-    for (size_t layer = 0; layer < hwcContents.numHwLayers; ++layer) {
-        output << fill << "  Layer " << layer;
-        output << to_string(hwcContents.hwLayers[layer], hwc1MinorVersion);
-    }
-
-    if (hwcContents.outbuf != nullptr) {
-        output << fill << "Output buffer: " << hwcContents.outbuf << "/" <<
-                hwcContents.outbufAcquireFenceFd << '\n';
-    }
-
-    return output.str();
-}
-
-std::string HWC2On1Adapter::Display::dump() const {
-    std::unique_lock<std::recursive_mutex> lock(mStateMutex);
-
-    std::stringstream output;
-
-    output << "  Display " << mId << ": ";
-    output << to_string(mType) << "  ";
-    output << "HWC1 ID: " << mHwc1Id << "  ";
-    output << "Power mode: " << to_string(mPowerMode) << "  ";
-    output << "Vsync: " << to_string(mVsyncEnabled) << '\n';
-
-    output << "    Color modes [active]:";
-    for (const auto& mode : mColorModes) {
-        if (mode == mActiveColorMode) {
-            output << " [" << mode << ']';
-        } else {
-            output << " " << mode;
-        }
-    }
-    output << '\n';
-
-    output << "    " << mConfigs.size() << " Config" <<
-            (mConfigs.size() == 1 ? "" : "s") << " (* active)\n";
-    for (const auto& config : mConfigs) {
-        output << (config == mActiveConfig ? "    * " : "      ");
-        output << config->toString(true) << '\n';
-    }
-
-    output << "    " << mLayers.size() << " Layer" <<
-            (mLayers.size() == 1 ? "" : "s") << '\n';
-    for (const auto& layer : mLayers) {
-        output << layer->dump();
-    }
-
-    output << "    Client target: " << mClientTarget.getBuffer() << '\n';
-
-    if (mOutputBuffer.getBuffer() != nullptr) {
-        output << "    Output buffer: " << mOutputBuffer.getBuffer() << '\n';
-    }
-
-    if (mHwc1RequestedContents) {
-        output << "    Last requested HWC1 state\n";
-        output << to_string(*mHwc1RequestedContents, mDevice.mHwc1MinorVersion);
-    }
-
-    return output.str();
-}
-
-hwc_rect_t* HWC2On1Adapter::Display::GetRects(size_t numRects) {
-    if (numRects == 0) {
-        return nullptr;
-    }
-
-    if (numRects > mNumAvailableRects) {
-        // This should NEVER happen since we calculated how many rects the
-        // display would need.
-        ALOGE("Rect allocation failure! SF is likely to crash soon!");
-        return nullptr;
-
-    }
-    hwc_rect_t* rects = mNextAvailableRect;
-    mNextAvailableRect += numRects;
-    mNumAvailableRects -= numRects;
-    return rects;
-}
-
-hwc_display_contents_1* HWC2On1Adapter::Display::getDisplayContents() {
-    return mHwc1RequestedContents.get();
-}
-
-void HWC2On1Adapter::Display::Config::setAttribute(HWC2::Attribute attribute,
-        int32_t value) {
-    mAttributes[attribute] = value;
-}
-
-int32_t HWC2On1Adapter::Display::Config::getAttribute(Attribute attribute) const {
-    if (mAttributes.count(attribute) == 0) {
-        return -1;
-    }
-    return mAttributes.at(attribute);
-}
-
-void HWC2On1Adapter::Display::Config::setHwc1Id(uint32_t id) {
-    android_color_mode_t colorMode = static_cast<android_color_mode_t>(getAttribute(ColorMode));
-    mHwc1Ids.emplace(colorMode, id);
-}
-
-bool HWC2On1Adapter::Display::Config::hasHwc1Id(uint32_t id) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (id == idPair.second) {
-            return true;
-        }
-    }
-    return false;
-}
-
-Error HWC2On1Adapter::Display::Config::getColorModeForHwc1Id(
-        uint32_t id, android_color_mode_t* outMode) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (id == idPair.second) {
-            *outMode = idPair.first;
-            return Error::None;
-        }
-    }
-    ALOGE("Unable to find color mode for HWC ID %" PRIu32 " on config %u", id, mId);
-    return Error::BadParameter;
-}
-
-Error HWC2On1Adapter::Display::Config::getHwc1IdForColorMode(android_color_mode_t mode,
-        uint32_t* outId) const {
-    for (const auto& idPair : mHwc1Ids) {
-        if (mode == idPair.first) {
-            *outId = idPair.second;
-            return Error::None;
-        }
-    }
-    ALOGE("Unable to find HWC1 ID for color mode %d on config %u", mode, mId);
-    return Error::BadParameter;
-}
-
-bool HWC2On1Adapter::Display::Config::merge(const Config& other) {
-    auto attributes = {HWC2::Attribute::Width, HWC2::Attribute::Height,
-            HWC2::Attribute::VsyncPeriod, HWC2::Attribute::DpiX,
-            HWC2::Attribute::DpiY};
-    for (auto attribute : attributes) {
-        if (getAttribute(attribute) != other.getAttribute(attribute)) {
-            return false;
-        }
-    }
-    android_color_mode_t otherColorMode =
-            static_cast<android_color_mode_t>(other.getAttribute(ColorMode));
-    if (mHwc1Ids.count(otherColorMode) != 0) {
-        ALOGE("Attempted to merge two configs (%u and %u) which appear to be "
-                "identical", mHwc1Ids.at(otherColorMode),
-                other.mHwc1Ids.at(otherColorMode));
-        return false;
-    }
-    mHwc1Ids.emplace(otherColorMode,
-            other.mHwc1Ids.at(otherColorMode));
-    return true;
-}
-
-std::set<android_color_mode_t> HWC2On1Adapter::Display::Config::getColorModes() const {
-    std::set<android_color_mode_t> colorModes;
-    for (const auto& idPair : mHwc1Ids) {
-        colorModes.emplace(idPair.first);
-    }
-    return colorModes;
-}
-
-std::string HWC2On1Adapter::Display::Config::toString(bool splitLine) const {
-    std::string output;
-
-    const size_t BUFFER_SIZE = 100;
-    char buffer[BUFFER_SIZE] = {};
-    auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
-            "%u x %u", mAttributes.at(HWC2::Attribute::Width),
-            mAttributes.at(HWC2::Attribute::Height));
-    output.append(buffer, writtenBytes);
-
-    if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
-        std::memset(buffer, 0, BUFFER_SIZE);
-        writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
-                1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
-        output.append(buffer, writtenBytes);
-    }
-
-    if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
-            mAttributes.at(HWC2::Attribute::DpiX) != -1) {
-        std::memset(buffer, 0, BUFFER_SIZE);
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                ", DPI: %.1f x %.1f",
-                mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
-                mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
-        output.append(buffer, writtenBytes);
-    }
-
-    std::memset(buffer, 0, BUFFER_SIZE);
-    if (splitLine) {
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                "\n        HWC1 ID/Color transform:");
-    } else {
-        writtenBytes = snprintf(buffer, BUFFER_SIZE,
-                ", HWC1 ID/Color transform:");
-    }
-    output.append(buffer, writtenBytes);
-
-
-    for (const auto& id : mHwc1Ids) {
-        android_color_mode_t colorMode = id.first;
-        uint32_t hwc1Id = id.second;
-        std::memset(buffer, 0, BUFFER_SIZE);
-        if (colorMode == mDisplay.mActiveColorMode) {
-            writtenBytes = snprintf(buffer, BUFFER_SIZE, " [%u/%d]", hwc1Id,
-                    colorMode);
-        } else {
-            writtenBytes = snprintf(buffer, BUFFER_SIZE, " %u/%d", hwc1Id,
-                    colorMode);
-        }
-        output.append(buffer, writtenBytes);
-    }
-
-    return output;
-}
-
-std::shared_ptr<const HWC2On1Adapter::Display::Config>
-        HWC2On1Adapter::Display::getConfig(hwc2_config_t configId) const {
-    if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
-        return nullptr;
-    }
-    return mConfigs[configId];
-}
-
-void HWC2On1Adapter::Display::populateColorModes() {
-    mColorModes = mConfigs[0]->getColorModes();
-    for (const auto& config : mConfigs) {
-        std::set<android_color_mode_t> intersection;
-        auto configModes = config->getColorModes();
-        std::set_intersection(mColorModes.cbegin(), mColorModes.cend(),
-                configModes.cbegin(), configModes.cend(),
-                std::inserter(intersection, intersection.begin()));
-        std::swap(intersection, mColorModes);
-    }
-}
-
-void HWC2On1Adapter::Display::initializeActiveConfig() {
-    if (mDevice.mHwc1Device->getActiveConfig == nullptr) {
-        ALOGV("getActiveConfig is null, choosing config 0");
-        mActiveConfig = mConfigs[0];
-        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-        return;
-    }
-
-    auto activeConfig = mDevice.mHwc1Device->getActiveConfig(
-            mDevice.mHwc1Device, mHwc1Id);
-
-    // Some devices startup without an activeConfig:
-    // We need to set one ourselves.
-    if (activeConfig == HWC_ERROR) {
-        ALOGV("There is no active configuration: Picking the first one: 0.");
-        const int defaultIndex = 0;
-        mDevice.mHwc1Device->setActiveConfig(mDevice.mHwc1Device, mHwc1Id, defaultIndex);
-        activeConfig = defaultIndex;
-    }
-
-    for (const auto& config : mConfigs) {
-        if (config->hasHwc1Id(activeConfig)) {
-            ALOGE("Setting active config to %d for HWC1 config %u", config->getId(), activeConfig);
-            mActiveConfig = config;
-            if (config->getColorModeForHwc1Id(activeConfig, &mActiveColorMode) != Error::None) {
-                // This should never happen since we checked for the config's presence before
-                // setting it as active.
-                ALOGE("Unable to find color mode for active HWC1 config %d", config->getId());
-                mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-            }
-            break;
-        }
-    }
-    if (!mActiveConfig) {
-        ALOGV("Unable to find active HWC1 config %u, defaulting to "
-                "config 0", activeConfig);
-        mActiveConfig = mConfigs[0];
-        mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-    }
-
-
-
-
-}
-
-void HWC2On1Adapter::Display::allocateRequestedContents() {
-    // What needs to be allocated:
-    // 1 hwc_display_contents_1_t
-    // 1 hwc_layer_1_t for each layer
-    // 1 hwc_rect_t for each layer's surfaceDamage
-    // 1 hwc_rect_t for each layer's visibleRegion
-    // 1 hwc_layer_1_t for the framebuffer
-    // 1 hwc_rect_t for the framebuffer's visibleRegion
-
-    // Count # of surfaceDamage
-    size_t numSurfaceDamages = 0;
-    for (const auto& layer : mLayers) {
-        numSurfaceDamages += layer->getNumSurfaceDamages();
-    }
-
-    // Count # of visibleRegions (start at 1 for mandatory framebuffer target
-    // region)
-    size_t numVisibleRegion = 1;
-    for (const auto& layer : mLayers) {
-        numVisibleRegion += layer->getNumVisibleRegions();
-    }
-
-    size_t numRects = numVisibleRegion + numSurfaceDamages;
-    auto numLayers = mLayers.size() + 1;
-    size_t size = sizeof(hwc_display_contents_1_t) +
-            sizeof(hwc_layer_1_t) * numLayers +
-            sizeof(hwc_rect_t) * numRects;
-    auto contents = static_cast<hwc_display_contents_1_t*>(std::calloc(size, 1));
-    mHwc1RequestedContents.reset(contents);
-    mNextAvailableRect = reinterpret_cast<hwc_rect_t*>(&contents->hwLayers[numLayers]);
-    mNumAvailableRects = numRects;
-}
-
-void HWC2On1Adapter::Display::assignHwc1LayerIds() {
-    mHwc1LayerMap.clear();
-    size_t nextHwc1Id = 0;
-    for (auto& layer : mLayers) {
-        mHwc1LayerMap[nextHwc1Id] = layer;
-        layer->setHwc1Id(nextHwc1Id++);
-    }
-}
-
-void HWC2On1Adapter::Display::updateTypeChanges(const hwc_layer_1_t& hwc1Layer,
-        const Layer& layer) {
-    auto layerId = layer.getId();
-    switch (hwc1Layer.compositionType) {
-        case HWC_FRAMEBUFFER:
-            if (layer.getCompositionType() != Composition::Client) {
-                mChanges->addTypeChange(layerId, Composition::Client);
-            }
-            break;
-        case HWC_OVERLAY:
-            if (layer.getCompositionType() != Composition::Device) {
-                mChanges->addTypeChange(layerId, Composition::Device);
-            }
-            break;
-        case HWC_BACKGROUND:
-            ALOGE_IF(layer.getCompositionType() != Composition::SolidColor,
-                    "updateTypeChanges: HWC1 requested BACKGROUND, but HWC2"
-                    " wasn't expecting SolidColor");
-            break;
-        case HWC_FRAMEBUFFER_TARGET:
-            // Do nothing, since it shouldn't be modified by HWC1
-            break;
-        case HWC_SIDEBAND:
-            ALOGE_IF(layer.getCompositionType() != Composition::Sideband,
-                    "updateTypeChanges: HWC1 requested SIDEBAND, but HWC2"
-                    " wasn't expecting Sideband");
-            break;
-        case HWC_CURSOR_OVERLAY:
-            ALOGE_IF(layer.getCompositionType() != Composition::Cursor,
-                    "updateTypeChanges: HWC1 requested CURSOR_OVERLAY, but"
-                    " HWC2 wasn't expecting Cursor");
-            break;
-    }
-}
-
-void HWC2On1Adapter::Display::updateLayerRequests(
-        const hwc_layer_1_t& hwc1Layer, const Layer& layer) {
-    if ((hwc1Layer.hints & HWC_HINT_CLEAR_FB) != 0) {
-        mChanges->addLayerRequest(layer.getId(),
-                LayerRequest::ClearClientTarget);
-    }
-}
-
-void HWC2On1Adapter::Display::prepareFramebufferTarget() {
-    // We check that mActiveConfig is valid in Display::prepare
-    int32_t width = mActiveConfig->getAttribute(Attribute::Width);
-    int32_t height = mActiveConfig->getAttribute(Attribute::Height);
-
-    auto& hwc1Target = mHwc1RequestedContents->hwLayers[mLayers.size()];
-    hwc1Target.compositionType = HWC_FRAMEBUFFER_TARGET;
-    hwc1Target.releaseFenceFd = -1;
-    hwc1Target.hints = 0;
-    hwc1Target.flags = 0;
-    hwc1Target.transform = 0;
-    hwc1Target.blending = HWC_BLENDING_PREMULT;
-    if (mDevice.getHwc1MinorVersion() < 3) {
-        hwc1Target.sourceCropi = {0, 0, width, height};
-    } else {
-        hwc1Target.sourceCropf = {0.0f, 0.0f, static_cast<float>(width),
-                static_cast<float>(height)};
-    }
-    hwc1Target.displayFrame = {0, 0, width, height};
-    hwc1Target.planeAlpha = 255;
-
-    hwc1Target.visibleRegionScreen.numRects = 1;
-    hwc_rect_t* rects = GetRects(1);
-    rects[0].left = 0;
-    rects[0].top = 0;
-    rects[0].right = width;
-    rects[0].bottom = height;
-    hwc1Target.visibleRegionScreen.rects = rects;
-
-    // We will set this to the correct value in set
-    hwc1Target.acquireFenceFd = -1;
-}
-
-// Layer functions
-
-std::atomic<hwc2_layer_t> HWC2On1Adapter::Layer::sNextId(1);
-
-HWC2On1Adapter::Layer::Layer(Display& display)
-  : mId(sNextId++),
-    mDisplay(display),
-    mBuffer(),
-    mSurfaceDamage(),
-    mBlendMode(BlendMode::None),
-    mColor({0, 0, 0, 0}),
-    mCompositionType(Composition::Invalid),
-    mDisplayFrame({0, 0, -1, -1}),
-    mPlaneAlpha(0.0f),
-    mSidebandStream(nullptr),
-    mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
-    mTransform(Transform::None),
-    mVisibleRegion(),
-    mZ(0),
-    mReleaseFence(),
-    mHwc1Id(0),
-    mHasUnsupportedPlaneAlpha(false) {}
-
-bool HWC2On1Adapter::SortLayersByZ::operator()(
-        const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
-    return lhs->getZ() < rhs->getZ();
-}
-
-Error HWC2On1Adapter::Layer::setBuffer(buffer_handle_t buffer,
-        int32_t acquireFence) {
-    ALOGV("Setting acquireFence to %d for layer %" PRIu64, acquireFence, mId);
-    mBuffer.setBuffer(buffer);
-    mBuffer.setFence(acquireFence);
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setCursorPosition(int32_t x, int32_t y) {
-    if (mCompositionType != Composition::Cursor) {
-        return Error::BadLayer;
-    }
-
-    if (mDisplay.hasChanges()) {
-        return Error::NotValidated;
-    }
-
-    auto displayId = mDisplay.getHwc1Id();
-    auto hwc1Device = mDisplay.getDevice().getHwc1Device();
-    hwc1Device->setCursorPositionAsync(hwc1Device, displayId, x, y);
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setSurfaceDamage(hwc_region_t damage) {
-    // HWC1 supports surface damage starting only with version 1.5.
-    if (mDisplay.getDevice().mHwc1MinorVersion < 5) {
-        return Error::None;
-    }
-    mSurfaceDamage.resize(damage.numRects);
-    std::copy_n(damage.rects, damage.numRects, mSurfaceDamage.begin());
-    return Error::None;
-}
-
-// Layer state functions
-
-Error HWC2On1Adapter::Layer::setBlendMode(BlendMode mode) {
-    mBlendMode = mode;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setColor(hwc_color_t color) {
-    mColor = color;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setCompositionType(Composition type) {
-    mCompositionType = type;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t) {
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setDisplayFrame(hwc_rect_t frame) {
-    mDisplayFrame = frame;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setPlaneAlpha(float alpha) {
-    mPlaneAlpha = alpha;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setSidebandStream(const native_handle_t* stream) {
-    mSidebandStream = stream;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setSourceCrop(hwc_frect_t crop) {
-    mSourceCrop = crop;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setTransform(Transform transform) {
-    mTransform = transform;
-    mDisplay.markGeometryChanged();
-    return Error::None;
-}
-
-static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
-    return rect1.left == rect2.left &&
-            rect1.right == rect2.right &&
-            rect1.top == rect2.top &&
-            rect1.bottom == rect2.bottom;
-}
-
-Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
-    if ((getNumVisibleRegions() != visible.numRects) ||
-        !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
-                    compareRects)) {
-        mVisibleRegion.resize(visible.numRects);
-        std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
-        mDisplay.markGeometryChanged();
-    }
-    return Error::None;
-}
-
-Error HWC2On1Adapter::Layer::setZ(uint32_t z) {
-    mZ = z;
-    return Error::None;
-}
-
-void HWC2On1Adapter::Layer::addReleaseFence(int fenceFd) {
-    ALOGV("addReleaseFence %d to layer %" PRIu64, fenceFd, mId);
-    mReleaseFence.add(fenceFd);
-}
-
-const sp<MiniFence>& HWC2On1Adapter::Layer::getReleaseFence() const {
-    return mReleaseFence.get();
-}
-
-void HWC2On1Adapter::Layer::applyState(hwc_layer_1_t& hwc1Layer) {
-    applyCommonState(hwc1Layer);
-    applyCompositionType(hwc1Layer);
-    switch (mCompositionType) {
-        case Composition::SolidColor : applySolidColorState(hwc1Layer); break;
-        case Composition::Sideband : applySidebandState(hwc1Layer); break;
-        default: applyBufferState(hwc1Layer); break;
-    }
-}
-
-static std::string regionStrings(const std::vector<hwc_rect_t>& visibleRegion,
-        const std::vector<hwc_rect_t>& surfaceDamage) {
-    std::string regions;
-    regions += "        Visible Region";
-    regions.resize(40, ' ');
-    regions += "Surface Damage\n";
-
-    size_t numPrinted = 0;
-    size_t maxSize = std::max(visibleRegion.size(), surfaceDamage.size());
-    while (numPrinted < maxSize) {
-        std::string line("        ");
-        if (visibleRegion.empty() && numPrinted == 0) {
-            line += "None";
-        } else if (numPrinted < visibleRegion.size()) {
-            line += rectString(visibleRegion[numPrinted]);
-        }
-        line.resize(40, ' ');
-        if (surfaceDamage.empty() && numPrinted == 0) {
-            line += "None";
-        } else if (numPrinted < surfaceDamage.size()) {
-            line += rectString(surfaceDamage[numPrinted]);
-        }
-        line += '\n';
-        regions += line;
-        ++numPrinted;
-    }
-    return regions;
-}
-
-std::string HWC2On1Adapter::Layer::dump() const {
-    std::stringstream output;
-    const char* fill = "      ";
-
-    output << fill << to_string(mCompositionType);
-    output << " Layer  HWC2/1: " << mId << "/" << mHwc1Id << "  ";
-    output << "Z: " << mZ;
-    if (mCompositionType == HWC2::Composition::SolidColor) {
-        output << "  " << colorString(mColor);
-    } else if (mCompositionType == HWC2::Composition::Sideband) {
-        output << "  Handle: " << mSidebandStream << '\n';
-    } else {
-        output << "  Buffer: " << mBuffer.getBuffer() << "/" <<
-                mBuffer.getFence() << '\n';
-        output << fill << "  Display frame [LTRB]: " <<
-                rectString(mDisplayFrame) << '\n';
-        output << fill << "  Source crop: " <<
-                frectString(mSourceCrop) << '\n';
-        output << fill << "  Transform: " << to_string(mTransform);
-        output << "  Blend mode: " << to_string(mBlendMode);
-        if (mPlaneAlpha != 1.0f) {
-            output << "  Alpha: " <<
-                alphaString(mPlaneAlpha) << '\n';
-        } else {
-            output << '\n';
-        }
-        output << regionStrings(mVisibleRegion, mSurfaceDamage);
-    }
-    return output.str();
-}
-
-static int getHwc1Blending(HWC2::BlendMode blendMode) {
-    switch (blendMode) {
-        case BlendMode::Coverage: return HWC_BLENDING_COVERAGE;
-        case BlendMode::Premultiplied: return HWC_BLENDING_PREMULT;
-        default: return HWC_BLENDING_NONE;
-    }
-}
-
-void HWC2On1Adapter::Layer::applyCommonState(hwc_layer_1_t& hwc1Layer) {
-    auto minorVersion = mDisplay.getDevice().getHwc1MinorVersion();
-    hwc1Layer.blending = getHwc1Blending(mBlendMode);
-    hwc1Layer.displayFrame = mDisplayFrame;
-
-    auto pendingAlpha = mPlaneAlpha;
-    if (minorVersion < 2) {
-        mHasUnsupportedPlaneAlpha = pendingAlpha < 1.0f;
-    } else {
-        hwc1Layer.planeAlpha =
-                static_cast<uint8_t>(255.0f * pendingAlpha + 0.5f);
-    }
-
-    if (minorVersion < 3) {
-        auto pending = mSourceCrop;
-        hwc1Layer.sourceCropi.left =
-                static_cast<int32_t>(std::ceil(pending.left));
-        hwc1Layer.sourceCropi.top =
-                static_cast<int32_t>(std::ceil(pending.top));
-        hwc1Layer.sourceCropi.right =
-                static_cast<int32_t>(std::floor(pending.right));
-        hwc1Layer.sourceCropi.bottom =
-                static_cast<int32_t>(std::floor(pending.bottom));
-    } else {
-        hwc1Layer.sourceCropf = mSourceCrop;
-    }
-
-    hwc1Layer.transform = static_cast<uint32_t>(mTransform);
-
-    auto& hwc1VisibleRegion = hwc1Layer.visibleRegionScreen;
-    hwc1VisibleRegion.numRects = mVisibleRegion.size();
-    hwc_rect_t* rects = mDisplay.GetRects(hwc1VisibleRegion.numRects);
-    hwc1VisibleRegion.rects = rects;
-    for (size_t i = 0; i < mVisibleRegion.size(); i++) {
-        rects[i] = mVisibleRegion[i];
-    }
-}
-
-void HWC2On1Adapter::Layer::applySolidColorState(hwc_layer_1_t& hwc1Layer) {
-    // If the device does not support background color it is likely to make
-    // assumption regarding backgroundColor and handle (both fields occupy
-    // the same location in hwc_layer_1_t union).
-    // To not confuse these devices we don't set background color and we
-    // make sure handle is a null pointer.
-    if (hasUnsupportedBackgroundColor()) {
-        hwc1Layer.handle = nullptr;
-    } else {
-        hwc1Layer.backgroundColor = mColor;
-    }
-}
-
-void HWC2On1Adapter::Layer::applySidebandState(hwc_layer_1_t& hwc1Layer) {
-    hwc1Layer.sidebandStream = mSidebandStream;
-}
-
-void HWC2On1Adapter::Layer::applyBufferState(hwc_layer_1_t& hwc1Layer) {
-    hwc1Layer.handle = mBuffer.getBuffer();
-    hwc1Layer.acquireFenceFd = mBuffer.getFence();
-}
-
-void HWC2On1Adapter::Layer::applyCompositionType(hwc_layer_1_t& hwc1Layer) {
-    // HWC1 never supports color transforms or dataspaces and only sometimes
-    // supports plane alpha (depending on the version). These require us to drop
-    // some or all layers to client composition.
-    if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
-            hasUnsupportedBackgroundColor()) {
-        hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-        hwc1Layer.flags = HWC_SKIP_LAYER;
-        return;
-    }
-
-    hwc1Layer.flags = 0;
-    switch (mCompositionType) {
-        case Composition::Client:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-        case Composition::Device:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            break;
-        case Composition::SolidColor:
-            // In theory the following line should work, but since the HWC1
-            // version of SurfaceFlinger never used HWC_BACKGROUND, HWC1
-            // devices may not work correctly. To be on the safe side, we
-            // fall back to client composition.
-            //
-            // hwc1Layer.compositionType = HWC_BACKGROUND;
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-        case Composition::Cursor:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            if (mDisplay.getDevice().getHwc1MinorVersion() >= 4) {
-                hwc1Layer.hints |= HWC_IS_CURSOR_LAYER;
-            }
-            break;
-        case Composition::Sideband:
-            if (mDisplay.getDevice().getHwc1MinorVersion() < 4) {
-                hwc1Layer.compositionType = HWC_SIDEBAND;
-            } else {
-                hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-                hwc1Layer.flags |= HWC_SKIP_LAYER;
-            }
-            break;
-        default:
-            hwc1Layer.compositionType = HWC_FRAMEBUFFER;
-            hwc1Layer.flags |= HWC_SKIP_LAYER;
-            break;
-    }
-    ALOGV("Layer %" PRIu64 " %s set to %d", mId,
-            to_string(mCompositionType).c_str(),
-            hwc1Layer.compositionType);
-    ALOGV_IF(hwc1Layer.flags & HWC_SKIP_LAYER, "    and skipping");
-}
-
-// Adapter helpers
-
-void HWC2On1Adapter::populateCapabilities() {
-    if (mHwc1MinorVersion >= 3U) {
-        int supportedTypes = 0;
-        auto result = mHwc1Device->query(mHwc1Device,
-                HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
-        if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
-            ALOGI("Found support for HWC virtual displays");
-            mHwc1SupportsVirtualDisplays = true;
-        }
-    }
-    if (mHwc1MinorVersion >= 4U) {
-        mCapabilities.insert(Capability::SidebandStream);
-    }
-
-    // Check for HWC background color layer support.
-    if (mHwc1MinorVersion >= 1U) {
-        int backgroundColorSupported = 0;
-        auto result = mHwc1Device->query(mHwc1Device,
-                                         HWC_BACKGROUND_LAYER_SUPPORTED,
-                                         &backgroundColorSupported);
-        if ((result == 0) && (backgroundColorSupported == 1)) {
-            ALOGV("Found support for HWC background color");
-            mHwc1SupportsBackgroundColor = true;
-        }
-    }
-
-    // Some devices might have HWC1 retire fences that accurately emulate
-    // HWC2 present fences when they are deferred, but it's not very reliable.
-    // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
-    mCapabilities.insert(Capability::PresentFenceIsNotReliable);
-}
-
-HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    auto display = mDisplays.find(id);
-    if (display == mDisplays.end()) {
-        return nullptr;
-    }
-
-    return display->second.get();
-}
-
-std::tuple<HWC2On1Adapter::Layer*, Error> HWC2On1Adapter::getLayer(
-        hwc2_display_t displayId, hwc2_layer_t layerId) {
-    auto display = getDisplay(displayId);
-    if (!display) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
-    }
-
-    auto layerEntry = mLayers.find(layerId);
-    if (layerEntry == mLayers.end()) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
-    }
-
-    auto layer = layerEntry->second;
-    if (layer->getDisplay().getId() != displayId) {
-        return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
-    }
-    return std::make_tuple(layer.get(), Error::None);
-}
-
-void HWC2On1Adapter::populatePrimary() {
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
-    mHwc1DisplayMap[HWC_DISPLAY_PRIMARY] = display->getId();
-    display->setHwc1Id(HWC_DISPLAY_PRIMARY);
-    display->populateConfigs();
-    mDisplays.emplace(display->getId(), std::move(display));
-}
-
-bool HWC2On1Adapter::prepareAllDisplays() {
-    ATRACE_CALL();
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    for (const auto& displayPair : mDisplays) {
-        auto& display = displayPair.second;
-        if (!display->prepare()) {
-            return false;
-        }
-    }
-
-    if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
-        ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
-        return false;
-    }
-
-    // Build an array of hwc_display_contents_1 to call prepare() on HWC1.
-    mHwc1Contents.clear();
-
-    // Always push the primary display
-    auto primaryDisplayId = mHwc1DisplayMap[HWC_DISPLAY_PRIMARY];
-    auto& primaryDisplay = mDisplays[primaryDisplayId];
-    mHwc1Contents.push_back(primaryDisplay->getDisplayContents());
-
-    // Push the external display, if present
-    if (mHwc1DisplayMap.count(HWC_DISPLAY_EXTERNAL) != 0) {
-        auto externalDisplayId = mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL];
-        auto& externalDisplay = mDisplays[externalDisplayId];
-        mHwc1Contents.push_back(externalDisplay->getDisplayContents());
-    } else {
-        // Even if an external display isn't present, we still need to send
-        // at least two displays down to HWC1
-        mHwc1Contents.push_back(nullptr);
-    }
-
-    // Push the hardware virtual display, if supported and present
-    if (mHwc1MinorVersion >= 3) {
-        if (mHwc1DisplayMap.count(HWC_DISPLAY_VIRTUAL) != 0) {
-            auto virtualDisplayId = mHwc1DisplayMap[HWC_DISPLAY_VIRTUAL];
-            auto& virtualDisplay = mDisplays[virtualDisplayId];
-            mHwc1Contents.push_back(virtualDisplay->getDisplayContents());
-        } else {
-            mHwc1Contents.push_back(nullptr);
-        }
-    }
-
-    for (auto& displayContents : mHwc1Contents) {
-        if (!displayContents) {
-            continue;
-        }
-
-        ALOGV("Display %zd layers:", mHwc1Contents.size() - 1);
-        for (size_t l = 0; l < displayContents->numHwLayers; ++l) {
-            auto& layer = displayContents->hwLayers[l];
-            ALOGV("  %zd: %d", l, layer.compositionType);
-        }
-    }
-
-    ALOGV("Calling HWC1 prepare");
-    {
-        ATRACE_NAME("HWC1 prepare");
-        mHwc1Device->prepare(mHwc1Device, mHwc1Contents.size(),
-                mHwc1Contents.data());
-    }
-
-    for (size_t c = 0; c < mHwc1Contents.size(); ++c) {
-        auto& contents = mHwc1Contents[c];
-        if (!contents) {
-            continue;
-        }
-        ALOGV("Display %zd layers:", c);
-        for (size_t l = 0; l < contents->numHwLayers; ++l) {
-            ALOGV("  %zd: %d", l, contents->hwLayers[l].compositionType);
-        }
-    }
-
-    // Return the received contents to their respective displays
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        display->generateChanges();
-    }
-
-    return true;
-}
-
-void dumpHWC1Message(hwc_composer_device_1* device, size_t numDisplays,
-                     hwc_display_contents_1_t** displays) {
-    ALOGV("*****************************");
-    size_t displayId = 0;
-    while (displayId < numDisplays) {
-        hwc_display_contents_1_t* display = displays[displayId];
-
-        ALOGV("hwc_display_contents_1_t[%zu] @0x%p", displayId, display);
-        if (display == nullptr) {
-            displayId++;
-            continue;
-        }
-        ALOGV("  retirefd:0x%08x", display->retireFenceFd);
-        ALOGV("  outbuf  :0x%p", display->outbuf);
-        ALOGV("  outbuffd:0x%08x", display->outbufAcquireFenceFd);
-        ALOGV("  flags   :0x%08x", display->flags);
-        for(size_t layerId=0 ; layerId < display->numHwLayers ; layerId++) {
-            hwc_layer_1_t& layer = display->hwLayers[layerId];
-            ALOGV("    Layer[%zu]:", layerId);
-            ALOGV("      composition        : 0x%08x", layer.compositionType);
-            ALOGV("      hints              : 0x%08x", layer.hints);
-            ALOGV("      flags              : 0x%08x", layer.flags);
-            ALOGV("      handle             : 0x%p", layer.handle);
-            ALOGV("      transform          : 0x%08x", layer.transform);
-            ALOGV("      blending           : 0x%08x", layer.blending);
-            ALOGV("      sourceCropf        : %f, %f, %f, %f",
-                  layer.sourceCropf.left,
-                  layer.sourceCropf.top,
-                  layer.sourceCropf.right,
-                  layer.sourceCropf.bottom);
-            ALOGV("      displayFrame       : %d, %d, %d, %d",
-                  layer.displayFrame.left,
-                  layer.displayFrame.left,
-                  layer.displayFrame.left,
-                  layer.displayFrame.left);
-            hwc_region_t& visReg = layer.visibleRegionScreen;
-            ALOGV("      visibleRegionScreen: #0x%08zx[@0x%p]",
-                  visReg.numRects,
-                  visReg.rects);
-            for (size_t visRegId=0; visRegId < visReg.numRects ; visRegId++) {
-                if (layer.visibleRegionScreen.rects == nullptr) {
-                    ALOGV("        null");
-                } else {
-                    ALOGV("        visibleRegionScreen[%zu] %d, %d, %d, %d",
-                          visRegId,
-                          visReg.rects[visRegId].left,
-                          visReg.rects[visRegId].top,
-                          visReg.rects[visRegId].right,
-                          visReg.rects[visRegId].bottom);
-                }
-            }
-            ALOGV("      acquireFenceFd     : 0x%08x", layer.acquireFenceFd);
-            ALOGV("      releaseFenceFd     : 0x%08x", layer.releaseFenceFd);
-            ALOGV("      planeAlpha         : 0x%08x", layer.planeAlpha);
-            if (getMinorVersion(device) < 5)
-               continue;
-            ALOGV("      surfaceDamage      : #0x%08zx[@0x%p]",
-                  layer.surfaceDamage.numRects,
-                  layer.surfaceDamage.rects);
-            for (size_t sdId=0; sdId < layer.surfaceDamage.numRects ; sdId++) {
-                if (layer.surfaceDamage.rects == nullptr) {
-                    ALOGV("      null");
-                } else {
-                    ALOGV("      surfaceDamage[%zu] %d, %d, %d, %d",
-                          sdId,
-                          layer.surfaceDamage.rects[sdId].left,
-                          layer.surfaceDamage.rects[sdId].top,
-                          layer.surfaceDamage.rects[sdId].right,
-                          layer.surfaceDamage.rects[sdId].bottom);
-                }
-            }
-        }
-        displayId++;
-    }
-    ALOGV("-----------------------------");
-}
-
-Error HWC2On1Adapter::setAllDisplays() {
-    ATRACE_CALL();
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // Make sure we're ready to validate
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        Error error = display->set(*mHwc1Contents[hwc1Id]);
-        if (error != Error::None) {
-            ALOGE("setAllDisplays: Failed to set display %zd: %s", hwc1Id,
-                    to_string(error).c_str());
-            return error;
-        }
-    }
-
-    ALOGV("Calling HWC1 set");
-    {
-        ATRACE_NAME("HWC1 set");
-        //dumpHWC1Message(mHwc1Device, mHwc1Contents.size(), mHwc1Contents.data());
-        mHwc1Device->set(mHwc1Device, mHwc1Contents.size(),
-                mHwc1Contents.data());
-    }
-
-    // Add retire and release fences
-    for (size_t hwc1Id = 0; hwc1Id < mHwc1Contents.size(); ++hwc1Id) {
-        if (mHwc1Contents[hwc1Id] == nullptr) {
-            continue;
-        }
-
-        auto displayId = mHwc1DisplayMap[hwc1Id];
-        auto& display = mDisplays[displayId];
-        auto retireFenceFd = mHwc1Contents[hwc1Id]->retireFenceFd;
-        ALOGV("setAllDisplays: Adding retire fence %d to display %zd",
-                retireFenceFd, hwc1Id);
-        display->addRetireFence(mHwc1Contents[hwc1Id]->retireFenceFd);
-        display->addReleaseFences(*mHwc1Contents[hwc1Id]);
-    }
-
-    return Error::None;
-}
-
-void HWC2On1Adapter::hwc1Invalidate() {
-    ALOGV("Received hwc1Invalidate");
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered.
-    if (mCallbacks.count(Callback::Refresh) == 0) {
-        mHasPendingInvalidate = true;
-        return;
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Refresh];
-    std::vector<hwc2_display_t> displays;
-    for (const auto& displayPair : mDisplays) {
-        displays.emplace_back(displayPair.first);
-    }
-
-    // Call back without the state lock held.
-    lock.unlock();
-
-    auto refresh = reinterpret_cast<HWC2_PFN_REFRESH>(callbackInfo.pointer);
-    for (auto display : displays) {
-        refresh(callbackInfo.data, display);
-    }
-}
-
-void HWC2On1Adapter::hwc1Vsync(int hwc1DisplayId, int64_t timestamp) {
-    ALOGV("Received hwc1Vsync(%d, %" PRId64 ")", hwc1DisplayId, timestamp);
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered.
-    if (mCallbacks.count(Callback::Vsync) == 0) {
-        mPendingVsyncs.emplace_back(hwc1DisplayId, timestamp);
-        return;
-    }
-
-    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-        ALOGE("hwc1Vsync: Couldn't find display for HWC1 id %d", hwc1DisplayId);
-        return;
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Vsync];
-    auto displayId = mHwc1DisplayMap[hwc1DisplayId];
-
-    // Call back without the state lock held.
-    lock.unlock();
-
-    auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
-    vsync(callbackInfo.data, displayId, timestamp);
-}
-
-void HWC2On1Adapter::hwc1Hotplug(int hwc1DisplayId, int connected) {
-    ALOGV("Received hwc1Hotplug(%d, %d)", hwc1DisplayId, connected);
-
-    if (hwc1DisplayId != HWC_DISPLAY_EXTERNAL) {
-        ALOGE("hwc1Hotplug: Received hotplug for non-external display");
-        return;
-    }
-
-    std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
-
-    // If the HWC2-side callback hasn't been registered yet, buffer this until
-    // it is registered
-    if (mCallbacks.count(Callback::Hotplug) == 0) {
-        mPendingHotplugs.emplace_back(hwc1DisplayId, connected);
-        return;
-    }
-
-    hwc2_display_t displayId = UINT64_MAX;
-    if (mHwc1DisplayMap.count(hwc1DisplayId) == 0) {
-        if (connected == 0) {
-            ALOGW("hwc1Hotplug: Received disconnect for unconnected display");
-            return;
-        }
-
-        // Create a new display on connect
-        auto display = std::make_shared<HWC2On1Adapter::Display>(*this,
-                HWC2::DisplayType::Physical);
-        display->setHwc1Id(HWC_DISPLAY_EXTERNAL);
-        display->populateConfigs();
-        displayId = display->getId();
-        mHwc1DisplayMap[HWC_DISPLAY_EXTERNAL] = displayId;
-        mDisplays.emplace(displayId, std::move(display));
-    } else {
-        if (connected != 0) {
-            ALOGW("hwc1Hotplug: Received connect for previously connected "
-                    "display");
-            return;
-        }
-
-        // Disconnect an existing display
-        displayId = mHwc1DisplayMap[hwc1DisplayId];
-        mHwc1DisplayMap.erase(HWC_DISPLAY_EXTERNAL);
-        mDisplays.erase(displayId);
-    }
-
-    const auto& callbackInfo = mCallbacks[Callback::Hotplug];
-
-    // Call back without the state lock held
-    lock.unlock();
-
-    auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(callbackInfo.pointer);
-    auto hwc2Connected = (connected == 0) ?
-            HWC2::Connection::Disconnected : HWC2::Connection::Connected;
-    hotplug(callbackInfo.data, displayId, static_cast<int32_t>(hwc2Connected));
-}
-} // namespace android
diff --git a/libs/hwc2on1adapter/MiniFence.cpp b/libs/hwc2on1adapter/MiniFence.cpp
deleted file mode 100644
index dfbe4d6..0000000
--- a/libs/hwc2on1adapter/MiniFence.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "hwc2on1adapter/MiniFence.h"
-
-#include <unistd.h>
-
-namespace android {
-
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
-
-MiniFence::MiniFence() :
-    mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
-    mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
-}
-
-int MiniFence::dup() const {
-    return ::dup(mFenceFd);
-}
-}
diff --git a/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
deleted file mode 100644
index 3badfce..0000000
--- a/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
- * Copyright 2015 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 ANDROID_SF_HWC2_ON_1_ADAPTER_H
-#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "MiniFence.h"
-
-#include <atomic>
-#include <map>
-#include <mutex>
-#include <queue>
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-
-namespace android {
-
-// For devices unable to provide an implementation of HWC2 (see hwcomposer2.h),
-// we provide an adapter able to talk to HWC1 (see hwcomposer.h). It translates
-// streamed function calls ala HWC2 model to batched array of structs calls ala
-// HWC1 model.
-class HWC2On1Adapter : public hwc2_device_t
-{
-public:
-    explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
-    ~HWC2On1Adapter();
-
-    struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
-    uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
-
-private:
-    static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
-        return static_cast<HWC2On1Adapter*>(device);
-    }
-
-    // getCapabilities
-
-    void doGetCapabilities(uint32_t* outCount,
-            int32_t* /*hwc2_capability_t*/ outCapabilities);
-    static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
-            int32_t* /*hwc2_capability_t*/ outCapabilities) {
-        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
-    }
-
-    bool supportsBackgroundColor() {
-        return mHwc1SupportsBackgroundColor;
-    }
-
-    // getFunction
-
-    hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
-    static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
-            int32_t intDesc) {
-        auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
-        return getAdapter(device)->doGetFunction(descriptor);
-    }
-
-    // Device functions
-
-    HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
-            hwc2_display_t* outDisplay);
-    static int32_t createVirtualDisplayHook(hwc2_device_t* device,
-            uint32_t width, uint32_t height, int32_t* /*format*/,
-            hwc2_display_t* outDisplay) {
-        // HWC1 implementations cannot override the buffer format requested by
-        // the consumer
-        auto error = getAdapter(device)->createVirtualDisplay(width, height,
-                outDisplay);
-        return static_cast<int32_t>(error);
-    }
-
-    HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
-    static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
-            hwc2_display_t display) {
-        auto error = getAdapter(device)->destroyVirtualDisplay(display);
-        return static_cast<int32_t>(error);
-    }
-
-    std::string mDumpString;
-    void dump(uint32_t* outSize, char* outBuffer);
-    static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
-            char* outBuffer) {
-        getAdapter(device)->dump(outSize, outBuffer);
-    }
-
-    uint32_t getMaxVirtualDisplayCount();
-    static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
-        return getAdapter(device)->getMaxVirtualDisplayCount();
-    }
-
-    HWC2::Error registerCallback(HWC2::Callback descriptor,
-            hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
-    static int32_t registerCallbackHook(hwc2_device_t* device,
-            int32_t intDesc, hwc2_callback_data_t callbackData,
-            hwc2_function_pointer_t pointer) {
-        auto descriptor = static_cast<HWC2::Callback>(intDesc);
-        auto error = getAdapter(device)->registerCallback(descriptor,
-                callbackData, pointer);
-        return static_cast<int32_t>(error);
-    }
-
-    // Display functions
-
-    class Layer;
-
-    class SortLayersByZ {
-        public:
-            bool operator()(const std::shared_ptr<Layer>& lhs,
-                    const std::shared_ptr<Layer>& rhs);
-    };
-
-    // The semantics of the fences returned by the device differ between
-    // hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
-    // for more information.
-    //
-    // Release fences in hwc1 are obtained on set() for a frame n and signaled
-    // when the layer buffer is not needed for read operations anymore
-    // (typically on frame n+1). In HWC2, release fences are obtained with a
-    // special call after present() for frame n. These fences signal
-    // on frame n: More specifically, the fence for a given buffer provided in
-    // frame n will signal when the prior buffer is no longer required.
-    //
-    // A retire fence (HWC1) is signaled when a composition is replaced
-    // on the panel whereas a present fence (HWC2) is signaled when a
-    // composition starts to be displayed on a panel.
-    //
-    // The HWC2to1Adapter emulates the new fence semantics for a frame
-    // n by returning the fence from frame n-1. For frame 0, the adapter
-    // returns NO_FENCE.
-    class DeferredFence {
-        public:
-            DeferredFence()
-              : mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
-
-            void add(int32_t fenceFd) {
-                mFences.emplace(new MiniFence(fenceFd));
-                mFences.pop();
-            }
-
-            const sp<MiniFence>& get() const {
-                return mFences.front();
-            }
-
-        private:
-            // There are always two fences in this queue.
-            std::queue<sp<MiniFence>> mFences;
-    };
-
-    class FencedBuffer {
-        public:
-            FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
-
-            void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
-            void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
-
-            buffer_handle_t getBuffer() const { return mBuffer; }
-            int getFence() const { return mFence->dup(); }
-
-        private:
-            buffer_handle_t mBuffer;
-            sp<MiniFence> mFence;
-    };
-
-    class Display {
-        public:
-            Display(HWC2On1Adapter& device, HWC2::DisplayType type);
-
-            hwc2_display_t getId() const { return mId; }
-            HWC2On1Adapter& getDevice() const { return mDevice; }
-
-            // Does not require locking because it is set before adding the
-            // Displays to the Adapter's list of displays
-            void setHwc1Id(int32_t id) { mHwc1Id = id; }
-            int32_t getHwc1Id() const { return mHwc1Id; }
-
-            // HWC2 Display functions
-            HWC2::Error acceptChanges();
-            HWC2::Error createLayer(hwc2_layer_t* outLayerId);
-            HWC2::Error destroyLayer(hwc2_layer_t layerId);
-            HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
-            HWC2::Error getAttribute(hwc2_config_t configId,
-                    HWC2::Attribute attribute, int32_t* outValue);
-            HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
-                    hwc2_layer_t* outLayers, int32_t* outTypes);
-            HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
-            HWC2::Error getConfigs(uint32_t* outNumConfigs,
-                    hwc2_config_t* outConfigIds);
-            HWC2::Error getDozeSupport(int32_t* outSupport);
-            HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
-                    int32_t* outTypes, float* outMaxLuminance,
-                    float* outMaxAverageLuminance, float* outMinLuminance);
-            HWC2::Error getName(uint32_t* outSize, char* outName);
-            HWC2::Error getReleaseFences(uint32_t* outNumElements,
-                    hwc2_layer_t* outLayers, int32_t* outFences);
-            HWC2::Error getRequests(int32_t* outDisplayRequests,
-                    uint32_t* outNumElements, hwc2_layer_t* outLayers,
-                    int32_t* outLayerRequests);
-            HWC2::Error getType(int32_t* outType);
-
-            // Since HWC1 "presents" (called "set" in HWC1) all Displays
-            // at once, the first call to any Display::present will trigger
-            // present() on all Displays in the Device. Subsequent calls without
-            // first calling validate() are noop (except for duping/returning
-            // the retire fence).
-            HWC2::Error present(int32_t* outRetireFence);
-
-            HWC2::Error setActiveConfig(hwc2_config_t configId);
-            HWC2::Error setClientTarget(buffer_handle_t target,
-                    int32_t acquireFence, int32_t dataspace,
-                    hwc_region_t damage);
-            HWC2::Error setColorMode(android_color_mode_t mode);
-            HWC2::Error setColorTransform(android_color_transform_t hint);
-            HWC2::Error setOutputBuffer(buffer_handle_t buffer,
-                    int32_t releaseFence);
-            HWC2::Error setPowerMode(HWC2::PowerMode mode);
-            HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
-
-            // Since HWC1 "validates" (called "prepare" in HWC1) all Displays
-            // at once, the first call to any Display::validate() will trigger
-            // validate() on all other Displays in the Device.
-            HWC2::Error validate(uint32_t* outNumTypes,
-                    uint32_t* outNumRequests);
-
-            HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
-
-            HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
-                     int32_t format, int32_t dataspace);
-
-            // Read configs from HWC1 device
-            void populateConfigs();
-
-            // Set configs for a virtual display
-            void populateConfigs(uint32_t width, uint32_t height);
-
-            bool prepare();
-
-            // Called after hwc.prepare() with responses from the device.
-            void generateChanges();
-
-            bool hasChanges() const;
-            HWC2::Error set(hwc_display_contents_1& hwcContents);
-            void addRetireFence(int fenceFd);
-            void addReleaseFences(const hwc_display_contents_1& hwcContents);
-
-            bool hasColorTransform() const;
-
-            std::string dump() const;
-
-            // Return a rect from the pool allocated during validate()
-            hwc_rect_t* GetRects(size_t numRects);
-
-            hwc_display_contents_1* getDisplayContents();
-
-            void markGeometryChanged() { mGeometryChanged = true; }
-            void resetGeometryMarker() { mGeometryChanged = false;}
-        private:
-            class Config {
-                public:
-                    Config(Display& display)
-                      : mDisplay(display),
-                        mId(0),
-                        mAttributes() {}
-
-                    bool isOnDisplay(const Display& display) const {
-                        return display.getId() == mDisplay.getId();
-                    }
-
-                    void setAttribute(HWC2::Attribute attribute, int32_t value);
-                    int32_t getAttribute(HWC2::Attribute attribute) const;
-
-                    void setHwc1Id(uint32_t id);
-                    bool hasHwc1Id(uint32_t id) const;
-                    HWC2::Error getColorModeForHwc1Id(uint32_t id,
-                            android_color_mode_t *outMode) const;
-                    HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
-                            uint32_t* outId) const;
-
-                    void setId(hwc2_config_t id) { mId = id; }
-                    hwc2_config_t getId() const { return mId; }
-
-                    // Attempts to merge two configs that differ only in color
-                    // mode. Returns whether the merge was successful
-                    bool merge(const Config& other);
-
-                    std::set<android_color_mode_t> getColorModes() const;
-
-                    // splitLine divides the output into two lines suitable for
-                    // dumpsys SurfaceFlinger
-                    std::string toString(bool splitLine = false) const;
-
-                private:
-                    Display& mDisplay;
-                    hwc2_config_t mId;
-                    std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
-
-                    // Maps from color transform to HWC1 config ID
-                    std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
-            };
-
-            // Stores changes requested from the device upon calling prepare().
-            // Handles change request to:
-            //   - Layer composition type.
-            //   - Layer hints.
-            class Changes {
-                public:
-                    uint32_t getNumTypes() const {
-                        return static_cast<uint32_t>(mTypeChanges.size());
-                    }
-
-                    uint32_t getNumLayerRequests() const {
-                        return static_cast<uint32_t>(mLayerRequests.size());
-                    }
-
-                    const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
-                            getTypeChanges() const {
-                        return mTypeChanges;
-                    }
-
-                    const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
-                            getLayerRequests() const {
-                        return mLayerRequests;
-                    }
-
-                    void addTypeChange(hwc2_layer_t layerId,
-                            HWC2::Composition type) {
-                        mTypeChanges.insert({layerId, type});
-                    }
-
-                    void clearTypeChanges() { mTypeChanges.clear(); }
-
-                    void addLayerRequest(hwc2_layer_t layerId,
-                            HWC2::LayerRequest request) {
-                        mLayerRequests.insert({layerId, request});
-                    }
-
-                private:
-                    std::unordered_map<hwc2_layer_t, HWC2::Composition>
-                            mTypeChanges;
-                    std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
-                            mLayerRequests;
-            };
-
-            std::shared_ptr<const Config>
-                    getConfig(hwc2_config_t configId) const;
-
-            void populateColorModes();
-            void initializeActiveConfig();
-
-            // Creates a bi-directional mapping between index in HWC1
-            // prepare/set array and Layer object. Stores mapping in
-            // mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
-            void assignHwc1LayerIds();
-
-            // Called after a response to prepare() has been received:
-            // Ingest composition type changes requested by the device.
-            void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
-                    const Layer& layer);
-
-            // Called after a response to prepare() has been received:
-            // Ingest layer hint changes requested by the device.
-            void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
-                    const Layer& layer);
-
-            // Set all fields in HWC1 comm array for layer containing the
-            // HWC_FRAMEBUFFER_TARGET (always the last layer).
-            void prepareFramebufferTarget();
-
-            // Display ID generator.
-            static std::atomic<hwc2_display_t> sNextId;
-            const hwc2_display_t mId;
-
-
-            HWC2On1Adapter& mDevice;
-
-            // The state of this display should only be modified from
-            // SurfaceFlinger's main loop, with the exception of when dump is
-            // called. To prevent a bad state from crashing us during a dump
-            // call, all public calls into Display must acquire this mutex.
-            //
-            // It is recursive because we don't want to deadlock in validate
-            // (or present) when we call HWC2On1Adapter::prepareAllDisplays
-            // (or setAllDisplays), which calls back into Display functions
-            // which require locking.
-            mutable std::recursive_mutex mStateMutex;
-
-            // Allocate RAM able to store all layers and rects used for
-            // communication with HWC1. Place allocated RAM in variable
-            // mHwc1RequestedContents.
-            void allocateRequestedContents();
-
-            // Array of structs exchanged between client and hwc1 device.
-            // Sent to device upon calling prepare().
-            std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
-    private:
-            DeferredFence mRetireFence;
-
-            // Will only be non-null after the Display has been validated and
-            // before it has been presented
-            std::unique_ptr<Changes> mChanges;
-
-            int32_t mHwc1Id;
-
-            std::vector<std::shared_ptr<Config>> mConfigs;
-            std::shared_ptr<const Config> mActiveConfig;
-            std::set<android_color_mode_t> mColorModes;
-            android_color_mode_t mActiveColorMode;
-            std::string mName;
-            HWC2::DisplayType mType;
-            HWC2::PowerMode mPowerMode;
-            HWC2::Vsync mVsyncEnabled;
-
-            // Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
-            FencedBuffer mClientTarget;
-
-
-            FencedBuffer mOutputBuffer;
-
-            bool mHasColorTransform;
-
-            // All layers this Display is aware of.
-            std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
-
-            // Mapping between layer index in array of hwc_display_contents_1*
-            // passed to HWC1 during validate/set and Layer object.
-            std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
-
-            // All communication with HWC1 via prepare/set is done with one
-            // alloc. This pointer is pointing to a pool of hwc_rect_t.
-            size_t mNumAvailableRects;
-            hwc_rect_t* mNextAvailableRect;
-
-            // True if any of the Layers contained in this Display have been
-            // updated with anything other than a buffer since last call to
-            // Display::set()
-            bool mGeometryChanged;
-    };
-
-    // Utility template calling a Display object method directly based on the
-    // hwc2_display_t displayId parameter.
-    template <typename ...Args>
-    static int32_t callDisplayFunction(hwc2_device_t* device,
-            hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
-            Args... args) {
-        auto display = getAdapter(device)->getDisplay(displayId);
-        if (!display) {
-            return static_cast<int32_t>(HWC2::Error::BadDisplay);
-        }
-        auto error = ((*display).*member)(std::forward<Args>(args)...);
-        return static_cast<int32_t>(error);
-    }
-
-    template <typename MF, MF memFunc, typename ...Args>
-    static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
-            Args... args) {
-        return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
-                std::forward<Args>(args)...);
-    }
-
-    static int32_t getDisplayAttributeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_config_t config,
-            int32_t intAttribute, int32_t* outValue) {
-        auto attribute = static_cast<HWC2::Attribute>(intAttribute);
-        return callDisplayFunction(device, display, &Display::getAttribute,
-                config, attribute, outValue);
-    }
-
-    static int32_t setColorTransformHook(hwc2_device_t* device,
-            hwc2_display_t display, const float* /*matrix*/,
-            int32_t /*android_color_transform_t*/ intHint) {
-        // We intentionally throw away the matrix, because if the hint is
-        // anything other than IDENTITY, we have to fall back to client
-        // composition anyway
-        auto hint = static_cast<android_color_transform_t>(intHint);
-        return callDisplayFunction(device, display, &Display::setColorTransform,
-                hint);
-    }
-
-    static int32_t setColorModeHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
-        auto mode = static_cast<android_color_mode_t>(intMode);
-        return callDisplayFunction(device, display, &Display::setColorMode,
-                mode);
-    }
-
-    static int32_t setPowerModeHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t intMode) {
-        auto mode = static_cast<HWC2::PowerMode>(intMode);
-        return callDisplayFunction(device, display, &Display::setPowerMode,
-                mode);
-    }
-
-    static int32_t setVsyncEnabledHook(hwc2_device_t* device,
-            hwc2_display_t display, int32_t intEnabled) {
-        auto enabled = static_cast<HWC2::Vsync>(intEnabled);
-        return callDisplayFunction(device, display, &Display::setVsyncEnabled,
-                enabled);
-    }
-
-    class Layer {
-        public:
-            explicit Layer(Display& display);
-
-            bool operator==(const Layer& other) { return mId == other.mId; }
-            bool operator!=(const Layer& other) { return !(*this == other); }
-
-            hwc2_layer_t getId() const { return mId; }
-            Display& getDisplay() const { return mDisplay; }
-
-            // HWC2 Layer functions
-            HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
-            HWC2::Error setCursorPosition(int32_t x, int32_t y);
-            HWC2::Error setSurfaceDamage(hwc_region_t damage);
-
-            // HWC2 Layer state functions
-            HWC2::Error setBlendMode(HWC2::BlendMode mode);
-            HWC2::Error setColor(hwc_color_t color);
-            HWC2::Error setCompositionType(HWC2::Composition type);
-            HWC2::Error setDataspace(android_dataspace_t dataspace);
-            HWC2::Error setDisplayFrame(hwc_rect_t frame);
-            HWC2::Error setPlaneAlpha(float alpha);
-            HWC2::Error setSidebandStream(const native_handle_t* stream);
-            HWC2::Error setSourceCrop(hwc_frect_t crop);
-            HWC2::Error setTransform(HWC2::Transform transform);
-            HWC2::Error setVisibleRegion(hwc_region_t visible);
-            HWC2::Error setZ(uint32_t z);
-
-            HWC2::Composition getCompositionType() const {
-                return mCompositionType;
-            }
-            uint32_t getZ() const { return mZ; }
-
-            void addReleaseFence(int fenceFd);
-            const sp<MiniFence>& getReleaseFence() const;
-
-            void setHwc1Id(size_t id) { mHwc1Id = id; }
-            size_t getHwc1Id() const { return mHwc1Id; }
-
-            // Write state to HWC1 communication struct.
-            void applyState(struct hwc_layer_1& hwc1Layer);
-
-            std::string dump() const;
-
-            std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
-
-            std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
-
-            // True if a layer cannot be properly rendered by the device due
-            // to usage of SolidColor (a.k.a BackgroundColor in HWC1).
-            bool hasUnsupportedBackgroundColor() {
-                return (mCompositionType == HWC2::Composition::SolidColor &&
-                        !mDisplay.getDevice().supportsBackgroundColor());
-            }
-        private:
-            void applyCommonState(struct hwc_layer_1& hwc1Layer);
-            void applySolidColorState(struct hwc_layer_1& hwc1Layer);
-            void applySidebandState(struct hwc_layer_1& hwc1Layer);
-            void applyBufferState(struct hwc_layer_1& hwc1Layer);
-            void applyCompositionType(struct hwc_layer_1& hwc1Layer);
-
-            static std::atomic<hwc2_layer_t> sNextId;
-            const hwc2_layer_t mId;
-            Display& mDisplay;
-
-            FencedBuffer mBuffer;
-            std::vector<hwc_rect_t> mSurfaceDamage;
-
-            HWC2::BlendMode mBlendMode;
-            hwc_color_t mColor;
-            HWC2::Composition mCompositionType;
-            hwc_rect_t mDisplayFrame;
-            float mPlaneAlpha;
-            const native_handle_t* mSidebandStream;
-            hwc_frect_t mSourceCrop;
-            HWC2::Transform mTransform;
-            std::vector<hwc_rect_t> mVisibleRegion;
-
-            uint32_t mZ;
-
-            DeferredFence mReleaseFence;
-
-            size_t mHwc1Id;
-            bool mHasUnsupportedPlaneAlpha;
-    };
-
-    // Utility tempate calling a Layer object method based on ID parameters:
-    // hwc2_display_t displayId
-    // and
-    // hwc2_layer_t layerId
-    template <typename ...Args>
-    static int32_t callLayerFunction(hwc2_device_t* device,
-            hwc2_display_t displayId, hwc2_layer_t layerId,
-            HWC2::Error (Layer::*member)(Args...), Args... args) {
-        auto result = getAdapter(device)->getLayer(displayId, layerId);
-        auto error = std::get<HWC2::Error>(result);
-        if (error == HWC2::Error::None) {
-            auto layer = std::get<Layer*>(result);
-            error = ((*layer).*member)(std::forward<Args>(args)...);
-        }
-        return static_cast<int32_t>(error);
-    }
-
-    template <typename MF, MF memFunc, typename ...Args>
-    static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
-            hwc2_layer_t layerId, Args... args) {
-        return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
-                memFunc, std::forward<Args>(args)...);
-    }
-
-    // Layer state functions
-
-    static int32_t setLayerBlendModeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
-        auto mode = static_cast<HWC2::BlendMode>(intMode);
-        return callLayerFunction(device, display, layer,
-                &Layer::setBlendMode, mode);
-    }
-
-    static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
-        auto type = static_cast<HWC2::Composition>(intType);
-        return callLayerFunction(device, display, layer,
-                &Layer::setCompositionType, type);
-    }
-
-    static int32_t setLayerDataspaceHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
-        auto dataspace = static_cast<android_dataspace_t>(intDataspace);
-        return callLayerFunction(device, display, layer, &Layer::setDataspace,
-                dataspace);
-    }
-
-    static int32_t setLayerTransformHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
-        auto transform = static_cast<HWC2::Transform>(intTransform);
-        return callLayerFunction(device, display, layer, &Layer::setTransform,
-                transform);
-    }
-
-    static int32_t setLayerZOrderHook(hwc2_device_t* device,
-            hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
-        return callDisplayFunction(device, display, &Display::updateLayerZ,
-                layer, z);
-    }
-
-    // Adapter internals
-
-    void populateCapabilities();
-    Display* getDisplay(hwc2_display_t id);
-    std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
-            hwc2_layer_t layerId);
-    void populatePrimary();
-
-    bool prepareAllDisplays();
-    std::vector<struct hwc_display_contents_1*> mHwc1Contents;
-    HWC2::Error setAllDisplays();
-
-    // Callbacks
-    void hwc1Invalidate();
-    void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
-    void hwc1Hotplug(int hwc1DisplayId, int connected);
-
-    // These are set in the constructor and before any asynchronous events are
-    // possible
-
-    struct hwc_composer_device_1* const mHwc1Device;
-    const uint8_t mHwc1MinorVersion;
-    bool mHwc1SupportsVirtualDisplays;
-    bool mHwc1SupportsBackgroundColor;
-
-    class Callbacks;
-    const std::unique_ptr<Callbacks> mHwc1Callbacks;
-
-    std::unordered_set<HWC2::Capability> mCapabilities;
-
-    // These are only accessed from the main SurfaceFlinger thread (not from
-    // callbacks or dump
-
-    std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
-
-    // A HWC1 supports only one virtual display.
-    std::shared_ptr<Display> mHwc1VirtualDisplay;
-
-    // These are potentially accessed from multiple threads, and are protected
-    // by this mutex. This needs to be recursive, since the HWC1 implementation
-    // can call back into the invalidate callback on the same thread that is
-    // calling prepare.
-    std::recursive_timed_mutex mStateMutex;
-
-    struct CallbackInfo {
-        hwc2_callback_data_t data;
-        hwc2_function_pointer_t pointer;
-    };
-    std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
-    bool mHasPendingInvalidate;
-
-    // There is a small gap between the time the HWC1 module is started and
-    // when the callbacks for vsync and hotplugs are registered by the
-    // HWC2on1Adapter. To prevent losing events they are stored in these arrays
-    // and fed to the callback as soon as possible.
-    std::vector<std::pair<int, int64_t>> mPendingVsyncs;
-    std::vector<std::pair<int, int>> mPendingHotplugs;
-
-    // Mapping between HWC1 display id and Display objects.
-    std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
-
-    // Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
-    // HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
-    std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
-};
-
-} // namespace android
-
-#endif
diff --git a/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h b/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
deleted file mode 100644
index 75de764..0000000
--- a/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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 MINIFENCE_H
-#define MINIFENCE_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
- * avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
- */
-class MiniFence : public LightRefBase<MiniFence> {
-public:
-    static const sp<MiniFence> NO_FENCE;
-
-    // Construct a new MiniFence object with an invalid file descriptor.
-    MiniFence();
-
-    // Construct a new MiniFence object to manage a given fence file descriptor.
-    // When the new MiniFence object is destructed the file descriptor will be
-    // closed.
-    explicit MiniFence(int fenceFd);
-
-    // Not copyable or movable.
-    MiniFence(const MiniFence& rhs) = delete;
-    MiniFence& operator=(const MiniFence& rhs) = delete;
-    MiniFence(MiniFence&& rhs) = delete;
-    MiniFence& operator=(MiniFence&& rhs) = delete;
-
-    // Return a duplicate of the fence file descriptor. The caller is
-    // responsible for closing the returned file descriptor. On error, -1 will
-    // be returned and errno will indicate the problem.
-    int dup() const;
-
-private:
-    // Only allow instantiation using ref counting.
-    friend class LightRefBase<MiniFence>;
-    ~MiniFence();
-
-    int mFenceFd;
-
-};
-}
-#endif //MINIFENCE_H
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 1918379..03f593f 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -199,34 +199,34 @@
 
 // --- InputChannel ---
 
-InputChannel::InputChannel(const String8& name, int fd) :
+InputChannel::InputChannel(const std::string& name, int fd) :
         mName(name), mFd(fd) {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel constructed: name='%s', fd=%d",
-            mName.string(), fd);
+            mName.c_str(), fd);
 #endif
 
     int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
     LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
-            "non-blocking.  errno=%d", mName.string(), errno);
+            "non-blocking.  errno=%d", mName.c_str(), errno);
 }
 
 InputChannel::~InputChannel() {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel destroyed: name='%s', fd=%d",
-            mName.string(), mFd);
+            mName.c_str(), mFd);
 #endif
 
     ::close(mFd);
 }
 
-status_t InputChannel::openInputChannelPair(const String8& name,
+status_t InputChannel::openInputChannelPair(const std::string& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     int sockets[2];
     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
         status_t result = -errno;
         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
-                name.string(), errno);
+                name.c_str(), errno);
         outServerChannel.clear();
         outClientChannel.clear();
         return result;
@@ -238,12 +238,12 @@
     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
 
-    String8 serverChannelName = name;
-    serverChannelName.append(" (server)");
+    std::string serverChannelName = name;
+    serverChannelName += " (server)";
     outServerChannel = new InputChannel(serverChannelName, sockets[0]);
 
-    String8 clientChannelName = name;
-    clientChannelName.append(" (client)");
+    std::string clientChannelName = name;
+    clientChannelName += " (client)";
     outClientChannel = new InputChannel(clientChannelName, sockets[1]);
     return OK;
 }
@@ -260,7 +260,7 @@
     if (nWrite < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),
                 msg->header.type, error);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
@@ -275,13 +275,13 @@
     if (size_t(nWrite) != msgLength) {
 #if DEBUG_CHANNEL_MESSAGES
         ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
-                mName.string(), msg->header.type);
+                mName.c_str(), msg->header.type);
 #endif
         return DEAD_OBJECT;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -295,7 +295,7 @@
     if (nRead < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
             return WOULD_BLOCK;
@@ -308,20 +308,20 @@
 
     if (nRead == 0) { // check for EOF
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
+        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
 #endif
         return DEAD_OBJECT;
     }
 
     if (!msg->isValid(nRead)) {
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ received invalid message", mName.string());
+        ALOGD("channel '%s' ~ received invalid message", mName.c_str());
 #endif
         return BAD_VALUE;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -356,8 +356,8 @@
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
-            "downTime=%lld, eventTime=%lld",
-            mChannel->getName().string(), seq,
+            "downTime=%" PRId64 ", eventTime=%" PRId64,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
 #endif
@@ -407,9 +407,9 @@
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
             "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
+            "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
-            mChannel->getName().string(), seq,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
@@ -421,7 +421,7 @@
 
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
         ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
-                mChannel->getName().string(), pointerCount);
+                mChannel->getName().c_str(), pointerCount);
         return BAD_VALUE;
     }
 
@@ -454,7 +454,7 @@
 status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
-            mChannel->getName().string());
+            mChannel->getName().c_str());
 #endif
 
     InputMessage msg;
@@ -466,7 +466,7 @@
     }
     if (msg.header.type != InputMessage::TYPE_FINISHED) {
         ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
-                mChannel->getName().string(), msg.header.type);
+                mChannel->getName().c_str(), msg.header.type);
         return UNKNOWN_ERROR;
     }
     *outSeq = msg.body.finished.seq;
@@ -503,8 +503,8 @@
         bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
         int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
-            mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
+    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
+            mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
     *outSeq = 0;
@@ -528,7 +528,7 @@
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
-                                mChannel->getName().string(), *outSeq);
+                                mChannel->getName().c_str(), *outSeq);
 #endif
                         break;
                     }
@@ -547,12 +547,12 @@
             *outEvent = keyEvent;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
 
-        case AINPUT_EVENT_TYPE_MOTION: {
+        case InputMessage::TYPE_MOTION: {
             ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
             if (batchIndex >= 0) {
                 Batch& batch = mBatches.editItemAt(batchIndex);
@@ -560,7 +560,7 @@
                     batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ appended to batch event",
-                            mChannel->getName().string());
+                            mChannel->getName().c_str());
 #endif
                     break;
                 } else {
@@ -576,7 +576,7 @@
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ consumed batch event and "
                             "deferred current event, seq=%u",
-                            mChannel->getName().string(), *outSeq);
+                            mChannel->getName().c_str(), *outSeq);
 #endif
                     break;
                 }
@@ -590,7 +590,7 @@
                 batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                 ALOGD("channel '%s' consumer ~ started batch event",
-                        mChannel->getName().string());
+                        mChannel->getName().c_str());
 #endif
                 break;
             }
@@ -605,14 +605,14 @@
             *displayId = mMsg.body.motion.displayId;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
 
         default:
             ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
-                    mChannel->getName().string(), mMsg.header.type);
+                    mChannel->getName().c_str(), mMsg.header.type);
             return UNKNOWN_ERROR;
         }
     }
@@ -943,7 +943,7 @@
 status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
-            mChannel->getName().string(), seq, handled ? "true" : "false");
+            mChannel->getName().c_str(), seq, handled ? "true" : "false");
 #endif
 
     if (!seq) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 0627ca6..cba1111 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -824,6 +824,9 @@
     } else if (typeToken == "FULL") {
         type = KEYBOARD_TYPE_FULL;
     } else if (typeToken == "SPECIAL_FUNCTION") {
+        ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
+                "the property 'keyboard.specialFunction' to '1' there instead.");
+        // TODO: return BAD_VALUE here in Q
         type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
     } else if (typeToken == "OVERLAY") {
         type = KEYBOARD_TYPE_OVERLAY;
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 07f2289..11842ee 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -148,9 +148,19 @@
 
 // --- Global functions ---
 
+bool isKeyboardSpecialFunction(const PropertyMap* config) {
+    if (config == nullptr) {
+        return false;
+    }
+    bool isSpecialFunction = false;
+    config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction);
+    return isSpecialFunction;
+}
+
 bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
         const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
-    if (!keyMap->haveKeyCharacterMap()
+    // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q
+    if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration)
             || keyMap->keyCharacterMap->getKeyboardType()
                     == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
         return false;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index b174fa8..c70ace0 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -75,7 +75,9 @@
     str += " ]";
     return str;
 }
+#endif
 
+#if DEBUG_STRATEGY
 static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
     std::string str;
     str = "[";
@@ -141,6 +143,11 @@
 }
 
 VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
+    if (!strcmp("impulse", strategy)) {
+        // Physical model of pushing an object.  Quality: VERY GOOD.
+        // Works with duplicate coordinates, unclean finger liftoff.
+        return new ImpulseVelocityTrackerStrategy();
+    }
     if (!strcmp("lsq1", strategy)) {
         // 1st order least squares.  Quality: POOR.
         // Frequently underfits the touch data especially when the finger accelerates
@@ -352,9 +359,6 @@
 
 // --- LeastSquaresVelocityTrackerStrategy ---
 
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
 LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
         uint32_t degree, Weighting weighting) :
         mDegree(degree), mWeighting(weighting) {
@@ -556,6 +560,46 @@
     return true;
 }
 
+/*
+ * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to
+ * the default implementation
+ */
+static float solveUnweightedLeastSquaresDeg2(const float* x, const float* y, size_t count) {
+    float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+
+    for (size_t i = 0; i < count; i++) {
+        float xi = x[i];
+        float yi = y[i];
+        float xi2 = xi*xi;
+        float xi3 = xi2*xi;
+        float xi4 = xi3*xi;
+        float xi2yi = xi2*yi;
+        float xiyi = xi*yi;
+
+        sxi += xi;
+        sxi2 += xi2;
+        sxiyi += xiyi;
+        sxi2yi += xi2yi;
+        syi += yi;
+        sxi3 += xi3;
+        sxi4 += xi4;
+    }
+
+    float Sxx = sxi2 - sxi*sxi / count;
+    float Sxy = sxiyi - sxi*syi / count;
+    float Sxx2 = sxi3 - sxi*sxi2 / count;
+    float Sx2y = sxi2yi - sxi2*syi / count;
+    float Sx2x2 = sxi4 - sxi2*sxi2 / count;
+
+    float numerator = Sxy*Sx2x2 - Sx2y*Sxx2;
+    float denominator = Sxx*Sx2x2 - Sxx2*Sxx2;
+    if (denominator == 0) {
+        ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2);
+        return 0;
+    }
+    return numerator/denominator;
+}
+
 bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
         VelocityTracker::Estimator* outEstimator) const {
     outEstimator->clear();
@@ -597,6 +641,19 @@
         degree = m - 1;
     }
     if (degree >= 1) {
+        if (degree == 2 && mWeighting == WEIGHTING_NONE) { // optimize unweighted, degree=2 fit
+            outEstimator->time = newestMovement.eventTime;
+            outEstimator->degree = 2;
+            outEstimator->confidence = 1;
+            outEstimator->xCoeff[0] = 0; // only slope is calculated, set rest of coefficients = 0
+            outEstimator->yCoeff[0] = 0;
+            outEstimator->xCoeff[1] = solveUnweightedLeastSquaresDeg2(time, x, m);
+            outEstimator->yCoeff[1] = solveUnweightedLeastSquaresDeg2(time, y, m);
+            outEstimator->xCoeff[2] = 0;
+            outEstimator->yCoeff[2] = 0;
+            return true;
+        }
+
         float xdet, ydet;
         uint32_t n = degree + 1;
         if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
@@ -810,10 +867,6 @@
 
 // --- LegacyVelocityTrackerStrategy ---
 
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
 LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
     clear();
 }
@@ -926,4 +979,194 @@
     return true;
 }
 
+// --- ImpulseVelocityTrackerStrategy ---
+
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
+    clear();
+}
+
+ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
+}
+
+void ImpulseVelocityTrackerStrategy::clear() {
+    mIndex = 0;
+    mMovements[0].idBits.clear();
+}
+
+void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+    mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+        const VelocityTracker::Position* positions) {
+    if (++mIndex == HISTORY_SIZE) {
+        mIndex = 0;
+    }
+
+    Movement& movement = mMovements[mIndex];
+    movement.eventTime = eventTime;
+    movement.idBits = idBits;
+    uint32_t count = idBits.count();
+    for (uint32_t i = 0; i < count; i++) {
+        movement.positions[i] = positions[i];
+    }
+}
+
+/**
+ * Calculate the total impulse provided to the screen and the resulting velocity.
+ *
+ * The touchscreen is modeled as a physical object.
+ * Initial condition is discussed below, but for now suppose that v(t=0) = 0
+ *
+ * The kinetic energy of the object at the release is E=0.5*m*v^2
+ * Then vfinal = sqrt(2E/m). The goal is to calculate E.
+ *
+ * The kinetic energy at the release is equal to the total work done on the object by the finger.
+ * The total work W is the sum of all dW along the path.
+ *
+ * dW = F*dx, where dx is the piece of path traveled.
+ * Force is change of momentum over time, F = dp/dt = m dv/dt.
+ * Then substituting:
+ * dW = m (dv/dt) * dx = m * v * dv
+ *
+ * Summing along the path, we get:
+ * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv)
+ * Since the mass stays constant, the equation for final velocity is:
+ * vfinal = sqrt(2*sum(v * dv))
+ *
+ * Here,
+ * dv : change of velocity = (v[i+1]-v[i])
+ * dx : change of distance = (x[i+1]-x[i])
+ * dt : change of time = (t[i+1]-t[i])
+ * v : instantaneous velocity = dx/dt
+ *
+ * The final formula is:
+ * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i
+ * The absolute value is needed to properly account for the sign. If the velocity over a
+ * particular segment descreases, then this indicates braking, which means that negative
+ * work was done. So for two positive, but decreasing, velocities, this contribution would be
+ * negative and will cause a smaller final velocity.
+ *
+ * Initial condition
+ * There are two ways to deal with initial condition:
+ * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest.
+ * This is not entirely accurate. We are only taking the past X ms of touch data, where X is
+ * currently equal to 100. However, a touch event that created a fling probably lasted for longer
+ * than that, which would mean that the user has already been interacting with the touchscreen
+ * and it has probably already been moving.
+ * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this
+ * initial velocity and the equivalent energy, and start with this initial energy.
+ * Consider an example where we have the following data, consisting of 3 points:
+ *                 time: t0, t1, t2
+ *                 x   : x0, x1, x2
+ *                 v   : 0 , v1, v2
+ * Here is what will happen in each of these scenarios:
+ * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get
+ * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0
+ * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1)))
+ * since velocity is a real number
+ * 2) If we treat the screen as already moving, then it must already have an energy (per mass)
+ * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment
+ * will contribute to the total kinetic energy (since we can effectively consider that v0=v1).
+ * This will give the following expression for the final velocity:
+ * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1)))
+ * This analysis can be generalized to an arbitrary number of samples.
+ *
+ *
+ * Comparing the two equations above, we see that the only mathematical difference
+ * is the factor of 1/2 in front of the first velocity term.
+ * This boundary condition would allow for the "proper" calculation of the case when all of the
+ * samples are equally spaced in time and distance, which should suggest a constant velocity.
+ *
+ * Note that approach 2) is sensitive to the proper ordering of the data in time, since
+ * the boundary condition must be applied to the oldest sample to be accurate.
+ */
+static float kineticEnergyToVelocity(float work) {
+    static constexpr float sqrt2 = 1.41421356237;
+    return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
+static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
+    // The input should be in reversed time order (most recent sample at index i=0)
+    // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
+    static constexpr float SECONDS_PER_NANO = 1E-9;
+
+    if (count < 2) {
+        return 0; // if 0 or 1 points, velocity is zero
+    }
+    if (t[1] > t[0]) { // Algorithm will still work, but not perfectly
+        ALOGE("Samples provided to calculateImpulseVelocity in the wrong order");
+    }
+    if (count == 2) { // if 2 points, basic linear calculation
+        if (t[1] == t[0]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
+            return 0;
+        }
+        return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0]));
+    }
+    // Guaranteed to have at least 3 points here
+    float work = 0;
+    for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
+        if (t[i] == t[i-1]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
+            continue;
+        }
+        float vprev = kineticEnergyToVelocity(work); // v[i-1]
+        float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i]
+        work += (vcurr - vprev) * fabsf(vcurr);
+        if (i == count - 1) {
+            work *= 0.5; // initial condition, case 2) above
+        }
+    }
+    return kineticEnergyToVelocity(work);
+}
+
+bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
+        VelocityTracker::Estimator* outEstimator) const {
+    outEstimator->clear();
+
+    // Iterate over movement samples in reverse time order and collect samples.
+    float x[HISTORY_SIZE];
+    float y[HISTORY_SIZE];
+    nsecs_t time[HISTORY_SIZE];
+    size_t m = 0; // number of points that will be used for fitting
+    size_t index = mIndex;
+    const Movement& newestMovement = mMovements[mIndex];
+    do {
+        const Movement& movement = mMovements[index];
+        if (!movement.idBits.hasBit(id)) {
+            break;
+        }
+
+        nsecs_t age = newestMovement.eventTime - movement.eventTime;
+        if (age > HORIZON) {
+            break;
+        }
+
+        const VelocityTracker::Position& position = movement.getPosition(id);
+        x[m] = position.x;
+        y[m] = position.y;
+        time[m] = movement.eventTime;
+        index = (index == 0 ? HISTORY_SIZE : index) - 1;
+    } while (++m < HISTORY_SIZE);
+
+    if (m == 0) {
+        return false; // no data
+    }
+    outEstimator->xCoeff[0] = 0;
+    outEstimator->yCoeff[0] = 0;
+    outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+    outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+    outEstimator->xCoeff[2] = 0;
+    outEstimator->yCoeff[2] = 0;
+    outEstimator->time = newestMovement.eventTime;
+    outEstimator->degree = 2; // similar results to 2nd degree fit
+    outEstimator->confidence = 1;
+#if DEBUG_STRATEGY
+    ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+#endif
+    return true;
+}
+
 } // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 029a420..aca9521 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,13 @@
         "InputChannel_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "VelocityTracker_test.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wno-unused-variable",
     ],
     shared_libs: [
         "libinput",
@@ -13,6 +20,7 @@
         "libutils",
         "libbinder",
         "libui",
+        "libbase",
     ]
 }
 
@@ -24,5 +32,7 @@
     srcs: ["StructLayout_test.cpp"],
     cflags: [
         "-O0",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index e71ebe2..96c165c 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -41,9 +41,9 @@
     // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
     Pipe pipe;
 
-    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
+    sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd);
 
-    EXPECT_STREQ("channel name", inputChannel->getName().string())
+    EXPECT_STREQ("channel name", inputChannel->getName().c_str())
             << "channel should have provided name";
     EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
             << "channel should have provided fd";
@@ -60,16 +60,16 @@
 TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
     // Name
-    EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
+    EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str())
             << "server channel should have suffixed name";
-    EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
+    EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str())
             << "client channel should have suffixed name";
 
     // Server->Client communication
@@ -111,7 +111,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -125,7 +125,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -141,7 +141,7 @@
 TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 3fb1c6d..fd3b7c8 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -184,7 +184,7 @@
 
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
     ASSERT_EQ(2, event.getDeviceId());
-    ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
+    ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
     ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
     ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
     ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
@@ -196,7 +196,7 @@
 
     // Set source.
     event.setSource(AINPUT_SOURCE_JOYSTICK);
-    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+    ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
 }
 
 
@@ -300,7 +300,7 @@
     // Check properties.
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
     ASSERT_EQ(2, event->getDeviceId());
-    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
+    ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
     ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
     ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
@@ -432,7 +432,7 @@
 
     // Set source.
     event.setSource(AINPUT_SOURCE_JOYSTICK);
-    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+    ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
 
     // Set action.
     event.setAction(AMOTION_EVENT_ACTION_CANCEL);
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index a136738..c532241 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -36,7 +36,7 @@
     PreallocatedInputEventFactory mEventFactory;
 
     virtual void SetUp() {
-        status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+        status_t result = InputChannel::openInputChannelPair("channel name",
                 serverChannel, clientChannel);
 
         mPublisher = new InputPublisher(serverChannel);
@@ -89,8 +89,9 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
+    int32_t displayId;
     status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            0);
+            &displayId);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -133,7 +134,7 @@
     const uint32_t seq = 15;
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
-    const int32_t displayId = 0;
+    int32_t displayId = 0;
     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
     const int32_t actionButton = 0;
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -176,7 +177,7 @@
     uint32_t consumeSeq;
     InputEvent* event;
     status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            0);
+            &displayId);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -253,11 +254,15 @@
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
+TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
     status_t status;
-    const size_t pointerCount = 0;
+    const size_t pointerCount = 1;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
@@ -265,7 +270,20 @@
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
+TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
+    status_t status;
+    const size_t pointerCount = 0;
+    PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
+    ASSERT_EQ(BAD_VALUE, status)
+            << "publisher publishMotionEvent should return BAD_VALUE";
+}
+
+TEST_F(InputPublisherAndConsumerTest,
+        PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
     status_t status;
     const size_t pointerCount = MAX_POINTERS + 1;
     PointerProperties pointerProperties[pointerCount];
@@ -275,7 +293,7 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
new file mode 100644
index 0000000..43b6012
--- /dev/null
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VelocityTracker_test"
+
+#include <math.h>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <input/VelocityTracker.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
+
+// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
+// here EV = expected value, tol = VELOCITY_TOLERANCE
+constexpr float VELOCITY_TOLERANCE = 0.2;
+
+// --- VelocityTrackerTest ---
+class VelocityTrackerTest : public testing::Test { };
+
+static void checkVelocity(float Vactual, float Vtarget) {
+    // Compare directions
+    if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
+        FAIL() << StringPrintf("Velocity %f does not have the same direction"
+                " as the target velocity %f", Vactual, Vtarget);
+    }
+
+    // Compare magnitudes
+    const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
+    const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
+    if (fabsf(Vactual) < Vlower) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    if (fabsf(Vactual) > Vupper) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
+            Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+}
+
+void failWithMessage(std::string message) {
+    FAIL() << message; // cannot do this directly from a non-void function
+}
+
+struct Position {
+      nsecs_t time;
+      float x;
+      float y;
+};
+
+
+MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) {
+    /**
+     * Only populate the basic fields of a MotionEvent, such as time and a single axis
+     * Designed for use with manually-defined tests.
+     * Create a new MotionEvent on the heap, caller responsible for destroying the object.
+     */
+    if (numSamples < 1) {
+        failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent."
+                " Received numSamples=%zu", numSamples));
+    }
+
+    MotionEvent* event = new MotionEvent();
+    PointerCoords coords;
+    PointerProperties properties[1];
+
+    properties[0].id = DEFAULT_POINTER_ID;
+    properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+    // First sample added separately with initialize
+    coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
+    coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
+    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+
+    for (size_t i = 1; i < numSamples; i++) {
+        coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
+        coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
+        event->addSample(positions[i].time, &coords);
+    }
+    return event;
+}
+
+static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
+            int32_t axis, float targetVelocity) {
+    VelocityTracker vt(nullptr);
+    float Vx, Vy;
+
+    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+    vt.addMovement(event);
+
+    vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
+
+    switch (axis) {
+    case AMOTION_EVENT_AXIS_X:
+        checkVelocity(Vx, targetVelocity);
+        break;
+    case AMOTION_EVENT_AXIS_Y:
+        checkVelocity(Vy, targetVelocity);
+        break;
+    default:
+        FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
+    }
+    delete event;
+}
+
+/*
+ * ================== VelocityTracker tests generated manually =====================================
+ */
+ // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) {
+    // Same coordinate is reported 2 times in a row
+    // It is difficult to determine the correct answer here, but at least the direction
+    // of the reported velocity should be positive.
+    Position values[] = {
+        { 0, 273, NAN },
+        { 12585000, 293, NAN },
+        { 14730000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
+    // Same coordinate is reported 3 times in a row
+    Position values[] = {
+        { 0, 293, NAN },
+        { 6132000, 293, NAN },
+        { 11283000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
+    // Fixed velocity at 5 points per 10 milliseconds
+    Position values[] = {
+        { 0, 0, NAN },
+        { 10000000, 5, NAN },
+        { 20000000, 10, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+}
+
+
+/**
+ * ================== VelocityTracker tests generated by recording real events =====================
+ *
+ * To add a test, record the input coordinates and event times to all calls
+ * to void VelocityTracker::addMovement(const MotionEvent* event).
+ * Also record all calls to VelocityTracker::clear().
+ * Finally, record the output of VelocityTracker::getVelocity(...)
+ * This will give you the necessary data to create a new test.
+ */
+
+// --------------- Recorded by hand on swordfish ---------------------------------------------------
+// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
+    // Recording of a fling on Swordfish that could cause a fling in the wrong direction
+    Position values[] = {
+        { 0, 271, 96 },
+        { 16071042, 269.786346, 106.922775 },
+        { 35648403, 267.983063, 156.660034 },
+        { 52313925, 262.638397, 220.339081 },
+        { 68976522, 266.138824, 331.581116 },
+        { 85639375, 274.79245, 428.113159 },
+        { 96948871, 274.79245, 428.113159 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633);
+}
+
+// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
+// For some of these tests, the X-direction velocity checking has been removed, because the lsq2
+// and the impulse VelocityTrackerStrategies did not agree within 20%.
+// Since the flings were recorded in the Y-direction, the intentional user action should only
+// be relevant for the Y axis.
+// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction.
+// Those recordings have been discarded because we didn't feel one strategy's interpretation was
+// more correct than another's but didn't want to increase the tolerance for the entire test suite.
+//
+// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite.
+// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly
+// characterizes the velocity of the finger motion.
+// These can be treated approximately as:
+// slow - less than 1 page gets scrolled
+// faster - more than 1 page gets scrolled, but less than 3
+// fast - entire list is scrolled (fling is done as hard as possible)
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) {
+    // Sailfish - fling up - slow - 1
+    Position values[] = {
+        { 235089067457000, 528.00, 983.00 },
+        { 235089084684000, 527.00, 981.00 },
+        { 235089093349000, 527.00, 977.00 },
+        { 235089095677625, 527.00, 975.93 },
+        { 235089101859000, 527.00, 970.00 },
+        { 235089110378000, 528.00, 960.00 },
+        { 235089112497111, 528.25, 957.51 },
+        { 235089118760000, 531.00, 946.00 },
+        { 235089126686000, 535.00, 931.00 },
+        { 235089129316820, 536.33, 926.02 },
+        { 235089135199000, 540.00, 914.00 },
+        { 235089144297000, 546.00, 896.00 },
+        { 235089146136443, 547.21, 892.36 },
+        { 235089152923000, 553.00, 877.00 },
+        { 235089160784000, 559.00, 851.00 },
+        { 235089162955851, 560.66, 843.82 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) {
+    // Sailfish - fling up - slow - 2
+    Position values[] = {
+        { 235110560704000, 522.00, 1107.00 },
+        { 235110575764000, 522.00, 1107.00 },
+        { 235110584385000, 522.00, 1107.00 },
+        { 235110588421179, 521.52, 1106.52 },
+        { 235110592830000, 521.00, 1106.00 },
+        { 235110601385000, 520.00, 1104.00 },
+        { 235110605088160, 519.14, 1102.27 },
+        { 235110609952000, 518.00, 1100.00 },
+        { 235110618353000, 517.00, 1093.00 },
+        { 235110621755146, 516.60, 1090.17 },
+        { 235110627010000, 517.00, 1081.00 },
+        { 235110634785000, 518.00, 1063.00 },
+        { 235110638422450, 518.87, 1052.58 },
+        { 235110643161000, 520.00, 1039.00 },
+        { 235110651767000, 524.00, 1011.00 },
+        { 235110655089581, 525.54, 1000.19 },
+        { 235110660368000, 530.00, 980.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) {
+    // Sailfish - fling up - slow - 3
+    Position values[] = {
+        { 792536237000, 580.00, 1317.00 },
+        { 792541538987, 580.63, 1311.94 },
+        { 792544613000, 581.00, 1309.00 },
+        { 792552301000, 583.00, 1295.00 },
+        { 792558362309, 585.13, 1282.92 },
+        { 792560828000, 586.00, 1278.00 },
+        { 792569446000, 589.00, 1256.00 },
+        { 792575185095, 591.54, 1241.41 },
+        { 792578491000, 593.00, 1233.00 },
+        { 792587044000, 597.00, 1211.00 },
+        { 792592008172, 600.28, 1195.92 },
+        { 792594616000, 602.00, 1188.00 },
+        { 792603129000, 607.00, 1167.00 },
+        { 792608831290, 609.48, 1155.83 },
+        { 792612321000, 611.00, 1149.00 },
+        { 792620768000, 615.00, 1131.00 },
+        { 792625653873, 617.32, 1121.73 },
+        { 792629200000, 619.00, 1115.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) {
+    // Sailfish - fling up - faster - 1
+    Position values[] = {
+        { 235160420675000, 610.00, 1042.00 },
+        { 235160428220000, 609.00, 1026.00 },
+        { 235160436544000, 609.00, 1024.00 },
+        { 235160441852394, 609.64, 1020.82 },
+        { 235160444878000, 610.00, 1019.00 },
+        { 235160452673000, 613.00, 1006.00 },
+        { 235160458519743, 617.18, 992.06 },
+        { 235160461061000, 619.00, 986.00 },
+        { 235160469798000, 627.00, 960.00 },
+        { 235160475186713, 632.22, 943.02 },
+        { 235160478051000, 635.00, 934.00 },
+        { 235160486489000, 644.00, 906.00 },
+        { 235160491853697, 649.56, 890.56 },
+        { 235160495177000, 653.00, 881.00 },
+        { 235160504148000, 662.00, 858.00 },
+        { 235160509231495, 666.81, 845.37 },
+        { 235160512603000, 670.00, 837.00 },
+        { 235160520366000, 679.00, 814.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) {
+    // Sailfish - fling up - faster - 2
+    Position values[] = {
+        { 847153808000, 576.00, 1264.00 },
+        { 847171174000, 576.00, 1262.00 },
+        { 847179640000, 576.00, 1257.00 },
+        { 847185187540, 577.41, 1249.22 },
+        { 847187487000, 578.00, 1246.00 },
+        { 847195710000, 581.00, 1227.00 },
+        { 847202027059, 583.93, 1209.40 },
+        { 847204324000, 585.00, 1203.00 },
+        { 847212672000, 590.00, 1176.00 },
+        { 847218861395, 594.36, 1157.11 },
+        { 847221190000, 596.00, 1150.00 },
+        { 847230484000, 602.00, 1124.00 },
+        { 847235701400, 607.56, 1103.83 },
+        { 847237986000, 610.00, 1095.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) {
+    // Sailfish - fling up - faster - 3
+    Position values[] = {
+        { 235200532789000, 507.00, 1084.00 },
+        { 235200549221000, 507.00, 1083.00 },
+        { 235200557841000, 507.00, 1081.00 },
+        { 235200558051189, 507.00, 1080.95 },
+        { 235200566314000, 507.00, 1078.00 },
+        { 235200574876586, 508.97, 1070.12 },
+        { 235200575006000, 509.00, 1070.00 },
+        { 235200582900000, 514.00, 1054.00 },
+        { 235200591276000, 525.00, 1023.00 },
+        { 235200591701829, 525.56, 1021.42 },
+        { 235200600064000, 542.00, 976.00 },
+        { 235200608519000, 563.00, 911.00 },
+        { 235200608527086, 563.02, 910.94 },
+        { 235200616933000, 590.00, 844.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) {
+    // Sailfish - fling up - fast - 1
+    Position values[] = {
+        { 920922149000, 561.00, 1412.00 },
+        { 920930185000, 559.00, 1377.00 },
+        { 920930262463, 558.98, 1376.66 },
+        { 920938547000, 559.00, 1371.00 },
+        { 920947096857, 562.91, 1342.68 },
+        { 920947302000, 563.00, 1342.00 },
+        { 920955502000, 577.00, 1272.00 },
+        { 920963931021, 596.87, 1190.54 },
+        { 920963987000, 597.00, 1190.00 },
+        { 920972530000, 631.00, 1093.00 },
+        { 920980765511, 671.31, 994.68 },
+        { 920980906000, 672.00, 993.00 },
+        { 920989261000, 715.00, 903.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) {
+    // Sailfish - fling up - fast - 2
+    Position values[] = {
+        { 235247153233000, 518.00, 1168.00 },
+        { 235247170452000, 517.00, 1167.00 },
+        { 235247178908000, 515.00, 1159.00 },
+        { 235247179556213, 514.85, 1158.39 },
+        { 235247186821000, 515.00, 1125.00 },
+        { 235247195265000, 521.00, 1051.00 },
+        { 235247196389476, 521.80, 1041.15 },
+        { 235247203649000, 538.00, 932.00 },
+        { 235247212253000, 571.00, 794.00 },
+        { 235247213222491, 574.72, 778.45 },
+        { 235247220736000, 620.00, 641.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) {
+    // Sailfish - fling up - fast - 3
+    Position values[] = {
+        { 235302568736000, 529.00, 1167.00 },
+        { 235302576644000, 523.00, 1140.00 },
+        { 235302579395063, 520.91, 1130.61 },
+        { 235302585140000, 522.00, 1130.00 },
+        { 235302593615000, 527.00, 1065.00 },
+        { 235302596207444, 528.53, 1045.12 },
+        { 235302602102000, 559.00, 872.00 },
+        { 235302610545000, 652.00, 605.00 },
+        { 235302613019881, 679.26, 526.73 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) {
+    // Sailfish - fling down - slow - 1
+    Position values[] = {
+        { 235655749552755, 582.00, 432.49 },
+        { 235655750638000, 582.00, 433.00 },
+        { 235655758865000, 582.00, 440.00 },
+        { 235655766221523, 581.16, 448.43 },
+        { 235655767594000, 581.00, 450.00 },
+        { 235655776044000, 580.00, 462.00 },
+        { 235655782890696, 579.18, 474.35 },
+        { 235655784360000, 579.00, 477.00 },
+        { 235655792795000, 578.00, 496.00 },
+        { 235655799559531, 576.27, 515.04 },
+        { 235655800612000, 576.00, 518.00 },
+        { 235655809535000, 574.00, 542.00 },
+        { 235655816988015, 572.17, 564.86 },
+        { 235655817685000, 572.00, 567.00 },
+        { 235655825981000, 569.00, 595.00 },
+        { 235655833808653, 566.26, 620.60 },
+        { 235655834541000, 566.00, 623.00 },
+        { 235655842893000, 563.00, 649.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) {
+    // Sailfish - fling down - slow - 2
+    Position values[] = {
+        { 235671152083370, 485.24, 558.28 },
+        { 235671154126000, 485.00, 559.00 },
+        { 235671162497000, 484.00, 566.00 },
+        { 235671168750511, 483.27, 573.29 },
+        { 235671171071000, 483.00, 576.00 },
+        { 235671179390000, 482.00, 588.00 },
+        { 235671185417210, 481.31, 598.98 },
+        { 235671188173000, 481.00, 604.00 },
+        { 235671196371000, 480.00, 624.00 },
+        { 235671202084196, 479.27, 639.98 },
+        { 235671204235000, 479.00, 646.00 },
+        { 235671212554000, 478.00, 673.00 },
+        { 235671219471011, 476.39, 697.12 },
+        { 235671221159000, 476.00, 703.00 },
+        { 235671229592000, 474.00, 734.00 },
+        { 235671236281462, 472.43, 758.38 },
+        { 235671238098000, 472.00, 765.00 },
+        { 235671246532000, 470.00, 799.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) {
+    // Sailfish - fling down - slow - 3
+    Position values[] = {
+        { 170983201000, 557.00, 533.00 },
+        { 171000668000, 556.00, 534.00 },
+        { 171007359750, 554.73, 535.27 },
+        { 171011197000, 554.00, 536.00 },
+        { 171017660000, 552.00, 540.00 },
+        { 171024201831, 549.97, 544.73 },
+        { 171027333000, 549.00, 547.00 },
+        { 171034603000, 545.00, 557.00 },
+        { 171041043371, 541.98, 567.55 },
+        { 171043147000, 541.00, 571.00 },
+        { 171051052000, 536.00, 586.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) {
+    // Sailfish - fling down - faster - 1
+    Position values[] = {
+        { 235695280333000, 558.00, 451.00 },
+        { 235695283971237, 558.43, 454.45 },
+        { 235695289038000, 559.00, 462.00 },
+        { 235695297388000, 561.00, 478.00 },
+        { 235695300638465, 561.83, 486.25 },
+        { 235695305265000, 563.00, 498.00 },
+        { 235695313591000, 564.00, 521.00 },
+        { 235695317305492, 564.43, 532.68 },
+        { 235695322181000, 565.00, 548.00 },
+        { 235695330709000, 565.00, 577.00 },
+        { 235695333972227, 565.00, 588.10 },
+        { 235695339250000, 565.00, 609.00 },
+        { 235695347839000, 565.00, 642.00 },
+        { 235695351313257, 565.00, 656.18 },
+        { 235695356412000, 565.00, 677.00 },
+        { 235695364899000, 563.00, 710.00 },
+        { 235695368118682, 562.24, 722.52 },
+        { 235695373403000, 564.00, 744.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) {
+    // Sailfish - fling down - faster - 2
+    Position values[] = {
+        { 235709624766000, 535.00, 579.00 },
+        { 235709642256000, 534.00, 580.00 },
+        { 235709643350278, 533.94, 580.06 },
+        { 235709650760000, 532.00, 584.00 },
+        { 235709658615000, 530.00, 593.00 },
+        { 235709660170495, 529.60, 594.78 },
+        { 235709667095000, 527.00, 606.00 },
+        { 235709675616000, 524.00, 628.00 },
+        { 235709676983261, 523.52, 631.53 },
+        { 235709684289000, 521.00, 652.00 },
+        { 235709692763000, 518.00, 682.00 },
+        { 235709693804993, 517.63, 685.69 },
+        { 235709701438000, 515.00, 709.00 },
+        { 235709709830000, 512.00, 739.00 },
+        { 235709710626776, 511.72, 741.85 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) {
+    // Sailfish - fling down - faster - 3
+    Position values[] = {
+        { 235727628927000, 540.00, 440.00 },
+        { 235727636810000, 537.00, 454.00 },
+        { 235727646176000, 536.00, 454.00 },
+        { 235727653586628, 535.12, 456.65 },
+        { 235727654557000, 535.00, 457.00 },
+        { 235727663024000, 534.00, 465.00 },
+        { 235727670410103, 533.04, 479.45 },
+        { 235727670691000, 533.00, 480.00 },
+        { 235727679255000, 531.00, 501.00 },
+        { 235727687233704, 529.09, 526.73 },
+        { 235727687628000, 529.00, 528.00 },
+        { 235727696113000, 526.00, 558.00 },
+        { 235727704057546, 523.18, 588.98 },
+        { 235727704576000, 523.00, 591.00 },
+        { 235727713099000, 520.00, 626.00 },
+        { 235727720880776, 516.33, 655.36 },
+        { 235727721580000, 516.00, 658.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) {
+    // Sailfish - fling down - fast - 1
+    Position values[] = {
+        { 235762352849000, 467.00, 286.00 },
+        { 235762360250000, 443.00, 344.00 },
+        { 235762362787412, 434.77, 363.89 },
+        { 235762368807000, 438.00, 359.00 },
+        { 235762377220000, 425.00, 423.00 },
+        { 235762379608561, 421.31, 441.17 },
+        { 235762385698000, 412.00, 528.00 },
+        { 235762394133000, 406.00, 648.00 },
+        { 235762396429369, 404.37, 680.67 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) {
+    // Sailfish - fling down - fast - 2
+    Position values[] = {
+        { 235772487188000, 576.00, 204.00 },
+        { 235772495159000, 553.00, 236.00 },
+        { 235772503568000, 551.00, 240.00 },
+        { 235772508192247, 545.55, 254.17 },
+        { 235772512051000, 541.00, 266.00 },
+        { 235772520794000, 520.00, 337.00 },
+        { 235772525015263, 508.92, 394.43 },
+        { 235772529174000, 498.00, 451.00 },
+        { 235772537635000, 484.00, 589.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) {
+    // Sailfish - fling down - fast - 3
+    Position values[] = {
+        { 507650295000, 628.00, 233.00 },
+        { 507658234000, 605.00, 269.00 },
+        { 507666784000, 601.00, 274.00 },
+        { 507669660483, 599.65, 275.68 },
+        { 507675427000, 582.00, 308.00 },
+        { 507683740000, 541.00, 404.00 },
+        { 507686506238, 527.36, 435.95 },
+        { 507692220000, 487.00, 581.00 },
+        { 507700707000, 454.00, 792.00 },
+        { 507703352649, 443.71, 857.77 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
+}
+
+
+} // namespace android
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
index 0ed24a2..0184f56 100644
--- a/libs/math/tests/Android.bp
+++ b/libs/math/tests/Android.bp
@@ -18,22 +18,26 @@
     name: "vec_test",
     srcs: ["vec_test.cpp"],
     static_libs: ["libmath"],
+    cflags: ["-Wall", "-Werror"],
 }
 
 cc_test {
     name: "mat_test",
     srcs: ["mat_test.cpp"],
     static_libs: ["libmath"],
+    cflags: ["-Wall", "-Werror"],
 }
 
 cc_test {
     name: "half_test",
     srcs: ["half_test.cpp"],
     static_libs: ["libmath"],
+    cflags: ["-Wall", "-Werror"],
 }
 
 cc_test {
     name: "quat_test",
     srcs: ["quat_test.cpp"],
     static_libs: ["libmath"],
+    cflags: ["-Wall", "-Werror"],
 }
diff --git a/libs/math/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
index 3217a1a..a14c7ea 100644
--- a/libs/math/tests/mat_test.cpp
+++ b/libs/math/tests/mat_test.cpp
@@ -35,7 +35,7 @@
 
 TEST_F(MatTest, Basics) {
     mat4 m0;
-    EXPECT_EQ(sizeof(mat4), sizeof(float)*16);
+    EXPECT_EQ(sizeof(m0), sizeof(float)*16);
 }
 
 TEST_F(MatTest, ComparisonOps) {
@@ -76,6 +76,7 @@
     EXPECT_EQ(m3, m1);
 
     mat4 m4(vec4(1), vec4(2), vec4(3), vec4(4));
+    EXPECT_NE(m4, m1);
 }
 
 TEST_F(MatTest, ArithmeticOps) {
@@ -172,7 +173,7 @@
 
 TEST_F(Mat3Test, Basics) {
     mat3 m0;
-    EXPECT_EQ(sizeof(mat3), sizeof(float)*9);
+    EXPECT_EQ(sizeof(m0), sizeof(float)*9);
 }
 
 TEST_F(Mat3Test, ComparisonOps) {
@@ -279,7 +280,7 @@
 
 TEST_F(Mat2Test, Basics) {
     mat2 m0;
-    EXPECT_EQ(sizeof(mat2), sizeof(float)*4);
+    EXPECT_EQ(sizeof(m0), sizeof(float)*4);
 }
 
 TEST_F(Mat2Test, ComparisonOps) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ed292e7..49ffc8f 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -29,7 +29,7 @@
 #include <system/graphics.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
-#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 
 
 static constexpr int kFdBufferSize = 128 * sizeof(int);  // 128 ints
@@ -60,6 +60,13 @@
         return BAD_VALUE;
     }
 
+    if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
+        (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
+        ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
+              "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
+        return BAD_VALUE;
+    }
+
     uint64_t usage =  AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
     sp<GraphicBuffer> gbuffer(new GraphicBuffer(
             desc->width, desc->height, format, desc->layers, usage,
@@ -311,6 +318,18 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
             "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
@@ -331,14 +350,6 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
             "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8,
-            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
@@ -354,6 +365,12 @@
         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
         case AHARDWAREBUFFER_FORMAT_BLOB:
+        case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_S8_UINT:
             // VNDK formats only -- unfortunately we can't differentiate from where we're called
         case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
         case AHARDWAREBUFFER_FORMAT_YV12:
@@ -365,10 +382,6 @@
         case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
         case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
         case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
@@ -388,7 +401,7 @@
 }
 
 uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
-    using android::hardware::graphics::common::V1_0::BufferUsage;
+    using android::hardware::graphics::common::V1_1::BufferUsage;
     static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER,
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_RARELY == (uint64_t)BufferUsage::CPU_READ_RARELY,
@@ -413,6 +426,10 @@
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA == (uint64_t)BufferUsage::SENSOR_DIRECT_DATA,
             "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP == (uint64_t)BufferUsage::GPU_CUBE_MAP,
+            "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
+            "gralloc and AHardwareBuffer flags don't match");
     return usage;
 }
 
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c6994c3..765dcd9 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -33,6 +33,27 @@
     return res < 0 ? res : value;
 }
 
+static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) {
+    bool supported = false;
+    switch (dataSpace) {
+        case HAL_DATASPACE_UNKNOWN:
+        case HAL_DATASPACE_V0_SRGB:
+            return true;
+        // These data space need wide gamut support.
+        case HAL_DATASPACE_V0_SCRGB_LINEAR:
+        case HAL_DATASPACE_V0_SCRGB:
+        case HAL_DATASPACE_DISPLAY_P3:
+            native_window_get_wide_color_support(window, &supported);
+            return supported;
+        // These data space need HDR support.
+        case HAL_DATASPACE_BT2020_PQ:
+            native_window_get_hdr_support(window, &supported);
+            return supported;
+        default:
+            return false;
+    }
+}
+
 /**************************************************************************************************
  * NDK
  **************************************************************************************************/
@@ -92,7 +113,10 @@
     constexpr int32_t kAllTransformBits =
             ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
             ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
-            ANATIVEWINDOW_TRANSFORM_ROTATE_90;
+            ANATIVEWINDOW_TRANSFORM_ROTATE_90 |
+            // We don't expose INVERSE_DISPLAY as an NDK constant, but someone could have read it
+            // from a buffer already set by Camera framework, so we allow it to be forwarded.
+            NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
         return -EINVAL;
     if ((transform & ~kAllTransformBits) != 0)
@@ -101,6 +125,28 @@
     return native_window_set_buffers_transform(window, transform);
 }
 
+int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
+    static_assert(ADATASPACE_UNKNOWN == HAL_DATASPACE_UNKNOWN);
+    static_assert(ADATASPACE_SCRGB_LINEAR == HAL_DATASPACE_V0_SCRGB_LINEAR);
+    static_assert(ADATASPACE_SRGB == HAL_DATASPACE_V0_SRGB);
+    static_assert(ADATASPACE_SCRGB == HAL_DATASPACE_V0_SCRGB);
+    static_assert(ADATASPACE_DISPLAY_P3 == HAL_DATASPACE_DISPLAY_P3);
+    static_assert(ADATASPACE_BT2020_PQ == HAL_DATASPACE_BT2020_PQ);
+
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
+            !isDataSpaceValid(window, dataSpace)) {
+        return -EINVAL;
+    }
+    return native_window_set_buffers_data_space(window,
+                                                static_cast<android_dataspace_t>(dataSpace));
+}
+
+int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) {
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
+        return -EINVAL;
+    return query(window, NATIVE_WINDOW_DATASPACE);
+}
+
 /**************************************************************************************************
  * vndk-stable
  **************************************************************************************************/
@@ -209,10 +255,6 @@
     return native_window_set_buffers_timestamp(window, timestamp);
 }
 
-int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace) {
-    return native_window_set_buffers_data_space(window, dataSpace);
-}
-
 int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode) {
     return native_window_set_shared_buffer_mode(window, sharedBufferMode);
 }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index e61fbd6..5fbb3b2 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -30,14 +30,25 @@
 
 cc_library {
     name: "libnativewindow",
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+        "include-private",
+    ],
 
     clang: true,
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-function",
+    ],
+
     cppflags: [
         "-std=c++1z"
     ],
 
+    version_script: "libnativewindow.map.txt",
+
     srcs: [
         "AHardwareBuffer.cpp",
         "ANativeWindow.cpp",
@@ -49,7 +60,7 @@
         "liblog",
         "libutils",
         "libui",
-        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
     ],
 
     static_libs: [
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
similarity index 100%
rename from libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
rename to libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
new file mode 100644
index 0000000..3ac1c58
--- /dev/null
+++ b/libs/nativewindow/include/android/data_space.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file data_space.h
+ */
+
+#ifndef ANDROID_DATA_SPACE_H
+#define ANDROID_DATA_SPACE_H
+
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * ADataSpace.
+ */
+enum ADataSpace {
+    /**
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    ADATASPACE_UNKNOWN = 0,
+
+    /**
+     * scRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+    /**
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the SRGB transfer function
+     * for each of the R, G and B components. When written, the inverse
+     * transformation is performed.
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * Use full range and BT.709 standard.
+     */
+    ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * scRGB:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+
+    /**
+     * Display P3
+     *
+     * Use same primaries and white-point as DCI-P3
+     * but sRGB transfer function.
+     */
+    ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+};
+
+__END_DECLS
+
+#endif // ANDROID_DATA_SPACE_H
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 52440a5..78cec41 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -41,9 +41,11 @@
     AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM           = 1,
 
     /**
+     * 32 bits per pixel, 8 bits per channel format where alpha values are
+     * ignored (always opaque).
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
-     *   OpenGL ES: GL_RGBA8
+     *   OpenGL ES: GL_RGB8
      */
     AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM           = 2,
 
@@ -80,39 +82,94 @@
      * the buffer size in bytes.
      */
     AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D16_UNORM
+     *   OpenGL ES: GL_DEPTH_COMPONENT16
+     */
+    AHARDWAREBUFFER_FORMAT_D16_UNORM                = 0x30,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
+     *   OpenGL ES: GL_DEPTH_COMPONENT24
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM                = 0x31,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
+     *   OpenGL ES: GL_DEPTH24_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT        = 0x32,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT
+     *   OpenGL ES: GL_DEPTH_COMPONENT32F
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT                = 0x33,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
+     *   OpenGL ES: GL_DEPTH32F_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT        = 0x34,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_S8_UINT
+     *   OpenGL ES: GL_STENCIL_INDEX8
+     */
+    AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
 };
 
+/**
+ * Buffer usage flags, specifying how the buffer will be accessed.
+ */
 enum {
-    /* The buffer will never be read by the CPU */
+    /// The buffer will never be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /* The buffer will sometimes be read by the CPU */
+    /// The buffer will sometimes be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /* The buffer will often be read by the CPU */
+    /// The buffer will often be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
-    /* CPU read value mask */
+    /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /* The buffer will never be written by the CPU */
+    /// The buffer will never be written by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /* The buffer will sometimes be written to by the CPU */
+    /// The buffer will sometimes be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /* The buffer will often be written to by the CPU */
+    /// The buffer will often be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
-    /* CPU write value mask */
+    /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
-    /* The buffer will be read from by the GPU */
+    /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
-    /* The buffer will be written to by the GPU */
+    /**
+     * The buffer will be written to by the GPU as a framebuffer attachment.
+     * Note that the name of this flag is somewhat misleading: it does not imply
+     * that the buffer contains a color format. A buffer with depth or stencil
+     * format that will be used as a framebuffer attachment should also have
+     * this flag.
+     */
     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /* The buffer must not be used outside of a protected hardware path */
+    /// The buffer must not be used outside of a protected hardware path.
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
-    /* The buffer will be read by a hardware video encoder */
+    /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /** The buffer will be used for sensor direct data */
+    /// The buffer will be used for direct writes from sensors.
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /* The buffer will be used as a shader storage or uniform buffer object*/
+    /// The buffer will be used as a shader storage or uniform buffer object.
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
+    /// The buffer will be used as a cube map texture.
+    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
+    /// The buffer contains a complete mipmap hierarchy.
+    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
     AHARDWAREBUFFER_USAGE_VENDOR_1  = 1ULL << 29,
@@ -136,15 +193,19 @@
     AHARDWAREBUFFER_USAGE_VENDOR_19 = 1ULL << 63,
 };
 
+/**
+ * Buffer description. Used for allocating new buffers and querying parameters
+ * of existing ones.
+ */
 typedef struct AHardwareBuffer_Desc {
-    uint32_t    width;      // width in pixels
-    uint32_t    height;     // height in pixels
-    uint32_t    layers;     // number of images
-    uint32_t    format;     // One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      // Combination of AHARDWAREBUFFER_USAGE_*
-    uint32_t    stride;     // Stride in pixels, ignored for AHardwareBuffer_allocate()
-    uint32_t    rfu0;       // Initialize to zero, reserved for future use
-    uint64_t    rfu1;       // Initialize to zero, reserved for future use
+    uint32_t    width;      ///< Width in pixels.
+    uint32_t    height;     ///< Height in pixels.
+    uint32_t    layers;     ///< Number of images in an image array.
+    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
+    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
+    uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
+    uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
 typedef struct AHardwareBuffer AHardwareBuffer;
@@ -153,8 +214,8 @@
  * Allocates a buffer that backs an AHardwareBuffer using the passed
  * AHardwareBuffer_Desc.
  *
- * Returns NO_ERROR on success, or an error number of the allocation fails for
- * any reason.
+ * \return 0 on success, or an error number of the allocation fails for
+ * any reason. The returned buffer has a reference count of 1.
  */
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
         AHardwareBuffer** outBuffer);
@@ -177,7 +238,7 @@
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
         AHardwareBuffer_Desc* outDesc);
 
-/*
+/**
  * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
  * passed.  This call may block if the hardware needs to finish rendering or if
  * CPU caches need to be synchronized, or possibly for other implementation-
@@ -185,16 +246,16 @@
  * descriptor that will be signaled when the buffer is locked, otherwise the
  * caller will block until the buffer is available.
  *
- * If rect is not NULL, the caller promises to modify only data in the area
+ * If \a rect is not NULL, the caller promises to modify only data in the area
  * specified by rect. If rect is NULL, the caller may modify the contents of the
  * entire buffer.
  *
  * The content of the buffer outside of the specified rect is NOT modified
  * by this call.
  *
- * The buffer usage may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, then
- * outVirtualAddress is filled with the address of the buffer in virtual memory,
- * otherwise this function will fail.
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
+ * then outVirtualAddress is filled with the address of the buffer in virtual
+ * memory.
  *
  * THREADING CONSIDERATIONS:
  *
@@ -206,38 +267,38 @@
  * may return an error or leave the buffer's content into an indeterminate
  * state.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage
+ * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
  * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
  * number of the lock fails for any reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress);
 
-/*
+/**
  * Unlock the AHardwareBuffer; must be called after all changes to the buffer
  * are completed by the caller. If fence is not NULL then it will be set to a
  * file descriptor that is signaled when all pending work on the buffer is
  * completed. The caller is responsible for closing the fence when it is no
  * longer needed.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the unlock fails for any reason.
  */
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
 
-/*
+/**
  * Send the AHardwareBuffer to an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
 
-/*
+/**
  * Receive the AHardwareBuffer from an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 5290dd5..d5e5e9d 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -29,6 +29,7 @@
 
 #include <sys/cdefs.h>
 
+#include <android/data_space.h>
 #include <android/hardware_buffer.h>
 #include <android/rect.h>
 
@@ -84,23 +85,23 @@
  * A pointer can be obtained using {@link ANativeWindow_lock()}.
  */
 typedef struct ANativeWindow_Buffer {
-    // The number of pixels that are show horizontally.
+    /// The number of pixels that are shown horizontally.
     int32_t width;
 
-    // The number of pixels that are shown vertically.
+    /// The number of pixels that are shown vertically.
     int32_t height;
 
-    // The number of *pixels* that a line in the buffer takes in
-    // memory. This may be >= width.
+    /// The number of *pixels* that a line in the buffer takes in
+    /// memory. This may be >= width.
     int32_t stride;
 
-    // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
     int32_t format;
 
-    // The actual bits.
+    /// The actual bits.
     void* bits;
 
-    // Do not touch.
+    /// Do not touch.
     uint32_t reserved[6];
 } ANativeWindow_Buffer;
 
@@ -189,6 +190,33 @@
 
 #endif // __ANDROID_API__ >= __ANDROID_API_O__
 
+#if __ANDROID_API__ >= __ANDROID_API_P__
+
+/**
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer.
+ * For example, it can be used to convey the color space of the image data in
+ * the buffer, or it can be used to indicate that the buffers contain depth
+ * measurement data instead of color images. The default dataSpace is 0,
+ * ADATASPACE_UNKNOWN, unless it has been overridden by the producer.
+ *
+ * \param dataSpace data space of all buffers queued after this call.
+ * \return 0 for success, -EINVAL if window is invalid or the dataspace is not
+ * supported.
+ */
+int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace);
+
+/**
+ * Get the dataspace of the buffers in window.
+ * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
+ * dataspace is unknown, or -EINVAL if window is invalid.
+ */
+int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window);
+
+#endif // __ANDROID_API__ >= __ANDROID_API_P__
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 6490804..197f73f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -179,6 +179,16 @@
      * with GRALLOC_USAGE_PROTECTED usage bits on.
      */
     NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19,
+
+    /*
+     * Returns data space for the buffers.
+     */
+    NATIVE_WINDOW_DATASPACE = 20,
+
+    /*
+     * Returns maxBufferCount set by BufferQueueConsumer
+     */
+    NATIVE_WINDOW_MAX_BUFFER_COUNT = 21,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -225,6 +235,8 @@
     NATIVE_WINDOW_GET_HDR_SUPPORT               = 29,
     NATIVE_WINDOW_SET_USAGE64                   = 30,
     NATIVE_WINDOW_GET_CONSUMER_USAGE64          = 31,
+    NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
+    NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
 // clang-format on
 };
 
@@ -700,6 +712,42 @@
 }
 
 /*
+ * native_window_set_buffers_smpte2086_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the SMPTE
+ * ST.2086 metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed.  When it is nullptr, it means no such
+ * information is available.  No SMPTE ST.2086 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_smpte2086_metadata(
+        struct ANativeWindow* window,
+        const struct android_smpte2086_metadata* metadata)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA,
+            metadata);
+}
+
+/*
+ * native_window_set_buffers_cta861_3_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the CTA-861.3
+ * metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed.  When it is nullptr, it means no such
+ * information is available.  No CTA-861.3 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_cta861_3_metadata(
+        struct ANativeWindow* window,
+        const struct android_cta861_3_metadata* metadata)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA,
+            metadata);
+}
+
+/*
  * native_window_set_buffers_transform(..., int transform)
  * All buffers queued after this call will be displayed transformed according
  * to the transform parameter specified.
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 802edcc..7a4b31f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -53,14 +53,6 @@
     AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
     /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
     AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422             = 0x27,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444             = 0x28,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8              = 0x29,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8            = 0x2A,
     /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
     AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
     /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index a7b340a..995ba44 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -306,20 +306,6 @@
 
 
 /*
- * All buffers queued after this call will be associated with the dataSpace
- * parameter specified.
- *
- * dataSpace specifies additional information about the buffer that's dependent
- * on the buffer format and the endpoints. For example, it can be used to convey
- * the color space of the image data in the buffer, or it can be used to
- * indicate that the buffers contain depth measurement data instead of color
- * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
- * overridden by the consumer.
- */
-int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace);
-
-
-/*
  * Enable/disable shared buffer mode
  */
 int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode);
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 58045be..d2ba971 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -3,13 +3,11 @@
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
     AHardwareBuffer_describe;
-    AHardwareBuffer_fromHardwareBuffer;
     AHardwareBuffer_getNativeHandle; # vndk
     AHardwareBuffer_lock;
     AHardwareBuffer_recvHandleFromUnixSocket;
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
-    AHardwareBuffer_toHardwareBuffer;
     AHardwareBuffer_unlock;
     ANativeWindowBuffer_getHardwareBuffer; # vndk
     ANativeWindow_OemStorageGet; # vndk
@@ -17,8 +15,7 @@
     ANativeWindow_acquire;
     ANativeWindow_cancelBuffer; # vndk
     ANativeWindow_dequeueBuffer; # vndk
-    ANativeWindow_fromSurface;
-    ANativeWindow_fromSurfaceTexture;
+    ANativeWindow_getBuffersDataSpace; # introduced=28
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getWidth;
@@ -29,7 +26,7 @@
     ANativeWindow_release;
     ANativeWindow_setAutoRefresh; # vndk
     ANativeWindow_setBufferCount; # vndk
-    ANativeWindow_setBufferDataSpace; # vndk
+    ANativeWindow_setBuffersDataSpace; # introduced=28
     ANativeWindow_setBuffersDimensions; # vndk
     ANativeWindow_setBuffersFormat; # vndk
     ANativeWindow_setBuffersGeometry;
@@ -42,3 +39,17 @@
   local:
     *;
 };
+
+LIBNATIVEWINDOW_PLATFORM {
+  global:
+    extern "C++" {
+      android::AHardwareBuffer_isValidPixelFormat*;
+      android::AHardwareBuffer_convertFromPixelFormat*;
+      android::AHardwareBuffer_convertToPixelFormat*;
+      android::AHardwareBuffer_convertFromGrallocUsageBits*;
+      android::AHardwareBuffer_convertToGrallocUsageBits*;
+      android::AHardwareBuffer_to_GraphicBuffer*;
+      android::AHardwareBuffer_to_ANativeWindowBuffer*;
+      android::AHardwareBuffer_from_GraphicBuffer*;
+    };
+} LIBNATIVEWINDOW;
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index b89c35a..20071be 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -23,4 +23,5 @@
     srcs: [
         "AHardwareBufferTest.cpp",
         "c_compatibility.c"],
+    cflags: ["-Wall", "-Werror"],
 }
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 171a627..940ff5a 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -16,9 +16,12 @@
     name: "libsensor",
 
     clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     cppflags: [
         "-Weverything",
-        "-Werror",
 
         // The static constructors and destructors in this library have not been noted to
         // introduce significant overheads
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index f20668d..5200545 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -27,6 +27,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
+#include <binder/IResultReceiver.h>
 
 #include <sensor/Sensor.h>
 #include <sensor/ISensorEventConnection.h>
@@ -63,7 +64,8 @@
         Vector<Sensor> v;
         uint32_t n = reply.readUint32();
         v.setCapacity(n);
-        while (n--) {
+        while (n) {
+            n--;
             reply.read(s);
             v.add(s);
         }
@@ -80,7 +82,8 @@
         Vector<Sensor> v;
         uint32_t n = reply.readUint32();
         v.setCapacity(n);
-        while (n--) {
+        while (n) {
+            n--;
             reply.read(s);
             v.add(s);
         }
@@ -225,6 +228,30 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String16> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+               args.add(data.readString16());
+            }
+            sp<IBinder> unusedCallback;
+            sp<IResultReceiver> resultReceiver;
+            status_t status;
+            if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
+                return status;
+            }
+            if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
+                return status;
+            }
+            status = shellCommand(in, out, err, args);
+            if (resultReceiver != nullptr) {
+                resultReceiver->send(status);
+            }
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
new file mode 100644
index 0000000..d4393d6
--- /dev/null
+++ b/libs/sensor/OWNERS
@@ -0,0 +1,2 @@
+arthuri@google.com
+bduddie@google.com
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 6fe72a1..b9ae524 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -27,6 +27,7 @@
 #include <utils/Singleton.h>
 
 #include <binder/IBinder.h>
+#include <binder/IPermissionController.h>
 #include <binder/IServiceManager.h>
 
 #include <sensor/ISensorServer.h>
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index edf3e0f..402678f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -60,6 +60,9 @@
 class BnSensorServer : public BnInterface<ISensorServer>
 {
 public:
+    virtual status_t shellCommand(int in, int out, int err,
+                                  Vector<String16>& args) = 0;
+
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 9d530fc..9fd84bc 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -17,6 +17,8 @@
 
     clang: true,
 
+    cflags: ["-Wall", "-Werror"],
+
     srcs: [
         "Sensor_test.cpp",
     ],
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 59173cb..ff9d19e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -20,9 +20,12 @@
     },
 
     clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     cppflags: [
         "-Weverything",
-        "-Werror",
 
         // The static constructors and destructors in this library have not been noted to
         // introduce significant overheads
@@ -44,7 +47,7 @@
     ],
 
     sanitize: {
-        //misc_undefined: ["integer"],
+        integer_overflow: true,
     },
 
     srcs: [
@@ -70,7 +73,9 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
         "libbase",
@@ -81,9 +86,14 @@
         "libhwbinder",
         "libsync",
         "libutils",
+        "libutilscallstack",
         "liblog",
     ],
 
+    export_shared_lib_headers: [
+        "android.hardware.graphics.common@1.1",
+    ],
+
     static_libs: [
         "libarect",
         "libgrallocusage",
@@ -91,20 +101,23 @@
     ],
 
     header_libs: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
+        "libpdx_headers",
     ],
 
-    export_include_dirs: ["include"],
-
     export_static_lib_headers: [
         "libarect",
         "libmath",
     ],
 
     export_header_lib_headers: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
     ],
 }
 
@@ -112,6 +125,14 @@
     name: "libui_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    target: {
+        vendor: {
+            override_export_include_dirs: ["include_vndk"],
+        },
+    },
 }
 
-subdirs = ["tests"]
+subdirs = [
+    "tests",
+    "tools",
+]
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index d5676cc..61df02d 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -16,10 +16,15 @@
 
 #include <ui/DebugUtils.h>
 #include <ui/PixelFormat.h>
+#include <ui/Rect.h>
 
 #include <android-base/stringprintf.h>
 #include <string>
 
+using android::base::StringPrintf;
+using android::ui::ColorMode;
+using android::ui::RenderIntent;
+
 std::string decodeStandard(android_dataspace dataspace) {
     const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
     switch (dataspaceSelect) {
@@ -71,7 +76,7 @@
                 case HAL_DATASPACE_SRGB:
                     return std::string("(deprecated) sRGB");
 
-                case HAL_DATASPACE_V0_BT709:
+                case HAL_DATASPACE_BT709:
                     return std::string("(deprecated) BT709");
 
                 case HAL_DATASPACE_ARBITRARY:
@@ -81,7 +86,7 @@
                 // Fallthrough
                 default:
                     return android::base::StringPrintf("Unknown deprecated dataspace code %d",
-                                                       dataspaceSelect);
+                                                       dataspace);
             }
     }
 
@@ -95,7 +100,7 @@
             case HAL_DATASPACE_JFIF:
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
+            case HAL_DATASPACE_BT709:
                 return std::string("SMPTE_170M");
 
             case HAL_DATASPACE_SRGB_LINEAR:
@@ -156,8 +161,8 @@
 
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
-                return std::string("Limited range)");
+            case HAL_DATASPACE_BT709:
+                return std::string("Limited range");
 
             case HAL_DATASPACE_ARBITRARY:
             case HAL_DATASPACE_UNKNOWN:
@@ -187,49 +192,85 @@
 
 std::string dataspaceDetails(android_dataspace dataspace) {
     if (dataspace == 0) {
-        return "Default (0)";
+        return "Default";
     }
     return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
                                        decodeTransfer(dataspace).c_str(),
                                        decodeRange(dataspace).c_str());
 }
 
-std::string decodeColorMode(android_color_mode colorMode) {
+std::string decodeColorMode(ColorMode colorMode) {
     switch (colorMode) {
-        case HAL_COLOR_MODE_NATIVE:
-            return std::string("HAL_COLOR_MODE_NATIVE");
+        case ColorMode::NATIVE:
+            return std::string("ColorMode::NATIVE");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625:
-            return std::string("HAL_COLOR_MODE_BT601_625");
+        case ColorMode::STANDARD_BT601_625:
+            return std::string("ColorMode::BT601_625");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_625_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+            return std::string("ColorMode::BT601_625_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525:
-            return std::string("HAL_COLOR_MODE_BT601_525");
+        case ColorMode::STANDARD_BT601_525:
+            return std::string("ColorMode::BT601_525");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_525_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+            return std::string("ColorMode::BT601_525_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT709:
-            return std::string("HAL_COLOR_MODE_BT709");
+        case ColorMode::STANDARD_BT709:
+            return std::string("ColorMode::BT709");
 
-        case HAL_COLOR_MODE_DCI_P3:
-            return std::string("HAL_COLOR_MODE_DCI_P3");
+        case ColorMode::DCI_P3:
+            return std::string("ColorMode::DCI_P3");
 
-        case HAL_COLOR_MODE_SRGB:
-            return std::string("HAL_COLOR_MODE_SRGB");
+        case ColorMode::SRGB:
+            return std::string("ColorMode::SRGB");
 
-        case HAL_COLOR_MODE_ADOBE_RGB:
-            return std::string("HAL_COLOR_MODE_ADOBE_RGB");
+        case ColorMode::ADOBE_RGB:
+            return std::string("ColorMode::ADOBE_RGB");
 
-        case HAL_COLOR_MODE_DISPLAY_P3:
-            return std::string("HAL_COLOR_MODE_DISPLAY_P3");
+        case ColorMode::DISPLAY_P3:
+            return std::string("ColorMode::DISPLAY_P3");
+
+        case ColorMode::BT2020:
+            return std::string("ColorMode::BT2020");
+
+        case ColorMode::BT2100_PQ:
+            return std::string("ColorMode::BT2100_PQ");
+
+        case ColorMode::BT2100_HLG:
+            return std::string("ColorMode::BT2100_HLG");
     }
 
     return android::base::StringPrintf("Unknown color mode %d", colorMode);
 }
 
+std::string decodeColorTransform(android_color_transform colorTransform) {
+    switch (colorTransform) {
+        case HAL_COLOR_TRANSFORM_IDENTITY:
+            return std::string("Identity");
+
+        case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+            return std::string("Arbitrary matrix");
+
+        case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
+            return std::string("Inverse value");
+
+        case HAL_COLOR_TRANSFORM_GRAYSCALE:
+            return std::string("Grayscale");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
+            return std::string("Correct protanopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
+            return std::string("Correct deuteranopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
+            return std::string("Correct tritanopia");
+    }
+
+    return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 std::string decodePixelFormat(android::PixelFormat format) {
@@ -262,3 +303,21 @@
             return android::base::StringPrintf("Unknown %#08x", format);
     }
 }
+
+std::string decodeRenderIntent(RenderIntent renderIntent) {
+    switch(renderIntent) {
+      case RenderIntent::COLORIMETRIC:
+          return std::string("RenderIntent::COLORIMETRIC");
+      case RenderIntent::ENHANCE:
+          return std::string("RenderIntent::ENHANCE");
+      case RenderIntent::TONE_MAP_COLORIMETRIC:
+          return std::string("RenderIntent::TONE_MAP_COLORIMETRIC");
+      case RenderIntent::TONE_MAP_ENHANCE:
+          return std::string("RenderIntent::TONE_MAP_ENHANCE");
+    }
+    return std::string("Unknown RenderIntent");
+}
+
+std::string to_string(const android::Rect& rect) {
+    return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
+}
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index b67f4d9..ff53aa8 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -37,18 +37,12 @@
 
 const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
 
-Fence::Fence() :
-    mFenceFd(-1) {
-}
-
 Fence::Fence(int fenceFd) :
     mFenceFd(fenceFd) {
 }
 
-Fence::~Fence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
+Fence::Fence(base::unique_fd fenceFd) :
+    mFenceFd(std::move(fenceFd)) {
 }
 
 status_t Fence::wait(int timeout) {
@@ -68,7 +62,7 @@
     int warningTimeout = 3000;
     int err = sync_wait(mFenceFd, warningTimeout);
     if (err < 0 && errno == ETIME) {
-        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
+        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
                 warningTimeout);
         err = sync_wait(mFenceFd, TIMEOUT_NEVER);
     }
@@ -94,7 +88,7 @@
     if (result == -1) {
         status_t err = -errno;
         ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
-                name, f1->mFenceFd, f2->mFenceFd,
+                name, f1->mFenceFd.get(), f2->mFenceFd.get(),
                 strerror(-err), err);
         return NO_FENCE;
     }
@@ -117,7 +111,7 @@
 
     struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd);
     if (finfo == NULL) {
-        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd);
+        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd.get());
         return SIGNAL_TIME_INVALID;
     }
     if (finfo->status != 1) {
@@ -181,7 +175,7 @@
     }
 
     if (numFds) {
-        mFenceFd = *fds++;
+        mFenceFd.reset(*fds++);
         count--;
     }
 
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 0eb08e5..b92cbf3 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -20,6 +20,7 @@
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc2.h>
 
+#include <inttypes.h>
 #include <log/log.h>
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wzero-length-array"
@@ -30,35 +31,104 @@
 
 namespace Gralloc2 {
 
+namespace {
+
 static constexpr Error kTransactionError = Error::NO_RESOURCES;
 
+uint64_t getValid10UsageBits() {
+    static const uint64_t valid10UsageBits = []() -> uint64_t {
+        using hardware::graphics::common::V1_0::BufferUsage;
+        uint64_t bits = 0;
+        for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+            bits = bits | bit;
+        }
+        // TODO(b/72323293, b/72703005): Remove these additional bits
+        bits = bits | (1 << 10) | (1 << 13);
+
+        return bits;
+    }();
+    return valid10UsageBits;
+}
+
+uint64_t getValid11UsageBits() {
+    static const uint64_t valid11UsageBits = []() -> uint64_t {
+        using hardware::graphics::common::V1_1::BufferUsage;
+        uint64_t bits = 0;
+        for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+            bits = bits | bit;
+        }
+        return bits;
+    }();
+    return valid11UsageBits;
+}
+
+}  // anonymous namespace
+
 void Mapper::preload() {
     android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
 }
 
 Mapper::Mapper()
 {
-    mMapper = IMapper::getService();
-    if (mMapper == nullptr || mMapper->isRemote()) {
+    mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
+    if (mMapper == nullptr) {
+        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+    }
+    if (mMapper->isRemote()) {
         LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
     }
+
+    // IMapper 2.1 is optional
+    mMapperV2_1 = IMapper::castFrom(mMapper);
+}
+
+Gralloc2::Error Mapper::validateBufferDescriptorInfo(
+        const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+    uint64_t validUsageBits = getValid10UsageBits();
+    if (mMapperV2_1 != nullptr) {
+        validUsageBits = validUsageBits | getValid11UsageBits();
+    }
+
+    if (descriptorInfo.usage & ~validUsageBits) {
+        ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+              descriptorInfo.usage & ~validUsageBits);
+        return Error::BAD_VALUE;
+    }
+    return Error::NONE;
 }
 
 Error Mapper::createDescriptor(
         const IMapper::BufferDescriptorInfo& descriptorInfo,
         BufferDescriptor* outDescriptor) const
 {
-    Error error;
-    auto ret = mMapper->createDescriptor(descriptorInfo,
-            [&](const auto& tmpError, const auto& tmpDescriptor)
-            {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
+    Error error = validateBufferDescriptorInfo(descriptorInfo);
+    if (error != Error::NONE) {
+        return error;
+    }
 
-                *outDescriptor = tmpDescriptor;
-            });
+    auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
+                   {
+                       error = tmpError;
+                       if (error != Error::NONE) {
+                           return;
+                       }
+
+                       *outDescriptor = tmpDescriptor;
+                   };
+
+    hardware::Return<void> ret;
+    if (mMapperV2_1 != nullptr) {
+        ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+    } else {
+        const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
+            descriptorInfo.width,
+            descriptorInfo.height,
+            descriptorInfo.layerCount,
+            static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
+            descriptorInfo.usage,
+        };
+        ret = mMapper->createDescriptor(info, hidl_cb);
+    }
 
     return (ret.isOk()) ? error : kTransactionError;
 }
@@ -91,6 +161,50 @@
             buffer, error);
 }
 
+Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
+        const IMapper::BufferDescriptorInfo& descriptorInfo,
+        uint32_t stride) const
+{
+    if (mMapperV2_1 == nullptr) {
+        return Error::NONE;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+
+    return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+}
+
+void Mapper::getTransportSize(buffer_handle_t bufferHandle,
+        uint32_t* outNumFds, uint32_t* outNumInts) const
+{
+    *outNumFds = uint32_t(bufferHandle->numFds);
+    *outNumInts = uint32_t(bufferHandle->numInts);
+
+    if (mMapperV2_1 == nullptr) {
+        return;
+    }
+
+    Error error;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->getTransportSize(buffer,
+            [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outNumFds = tmpNumFds;
+                *outNumInts = tmpNumInts;
+            });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
+            buffer, error);
+}
+
 Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
         const IMapper::Rect& accessRegion,
         int acquireFence, void** outData) const
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6235bd6..7670ac6 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,6 +22,7 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <ui/DetachedBufferHandle.h>
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -170,6 +171,8 @@
             inUsage, &handle, &outStride, mId,
             std::move(requestorName));
     if (err == NO_ERROR) {
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
         format = inFormat;
@@ -199,7 +202,8 @@
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, width, height,
+                layerCount, format, usage, stride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -212,6 +216,7 @@
         }
 
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     ANativeWindowBuffer::handle = handle;
@@ -323,11 +328,11 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
-    return static_cast<size_t>(handle ? handle->numFds : 0);
+    return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
@@ -353,18 +358,18 @@
     buf[12] = int(usage >> 32); // high 32-bits
 
     if (handle) {
-        buf[10] = handle->numFds;
-        buf[11] = handle->numInts;
-        memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+        buf[10] = int32_t(mTransportNumFds);
+        buf[11] = int32_t(mTransportNumInts);
+        memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
         memcpy(buf + 13, handle->data + handle->numFds,
-                static_cast<size_t>(handle->numInts) * sizeof(int));
+                static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
     size -= sizeNeeded;
     if (handle) {
-        fds += handle->numFds;
-        count -= static_cast<size_t>(handle->numFds);
+        fds += mTransportNumFds;
+        count -= static_cast<size_t>(mTransportNumFds);
     }
 
     return NO_ERROR;
@@ -461,7 +466,8 @@
 
     if (handle != 0) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
+                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
         if (err != NO_ERROR) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
@@ -474,6 +480,7 @@
         native_handle_close(handle);
         native_handle_delete(const_cast<native_handle_t*>(handle));
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
@@ -484,6 +491,24 @@
     return NO_ERROR;
 }
 
+bool GraphicBuffer::isDetachedBuffer() const {
+    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
+}
+
+status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
+    if (isDetachedBuffer()) {
+        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
+              "GraphicBuffer. Replacing the old one.");
+    }
+
+    mDetachedBufferHandle = std::move(channel);
+    return NO_ERROR;
+}
+
+std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
+    return std::move(mDetachedBufferHandle);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index d52c508..2d8e582 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -52,17 +52,43 @@
 }
 
 status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
+        uint32_t width, uint32_t height, uint32_t layerCount,
+        PixelFormat format, uint64_t usage, uint32_t stride,
         buffer_handle_t* outHandle)
 {
     ATRACE_CALL();
 
+    buffer_handle_t bufferHandle;
     Gralloc2::Error error = mMapper->importBuffer(
-            hardware::hidl_handle(rawHandle), outHandle);
+            hardware::hidl_handle(rawHandle), &bufferHandle);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
+        return static_cast<status_t>(error);
+    }
 
-    ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d",
-            rawHandle, error);
+    Gralloc2::IMapper::BufferDescriptorInfo info = {};
+    info.width = width;
+    info.height = height;
+    info.layerCount = layerCount;
+    info.format = static_cast<Gralloc2::PixelFormat>(format);
+    info.usage = usage;
 
-    return static_cast<status_t>(error);
+    error = mMapper->validateBufferSize(bufferHandle, info, stride);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
+        freeBuffer(bufferHandle);
+        return static_cast<status_t>(error);
+    }
+
+    *outHandle = bufferHandle;
+
+    return NO_ERROR;
+}
+
+void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
+{
+    mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts);
 }
 
 status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
@@ -99,7 +125,7 @@
 {
     int32_t fenceFd = -1;
     status_t error = unlockAsync(handle, &fenceFd);
-    if (error == NO_ERROR) {
+    if (error == NO_ERROR && fenceFd >= 0) {
         sync_wait(fenceFd, -1);
         close(fenceFd);
     }
@@ -129,29 +155,6 @@
     return static_cast<status_t>(error);
 }
 
-static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
-    if (plane.bits_per_component != 8) {
-        ALOGV("Invalid number of bits per component: %d",
-                plane.bits_per_component);
-        return false;
-    }
-    if (plane.bits_used != 8) {
-        ALOGV("Invalid number of bits used: %d", plane.bits_used);
-        return false;
-    }
-
-    bool hasValidIncrement = plane.h_increment == 1 ||
-            (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
-    hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
-    if (!hasValidIncrement) {
-        ALOGV("Invalid increment: h %d v %d", plane.h_increment,
-                plane.v_increment);
-        return false;
-    }
-
-    return true;
-}
-
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
 {
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 755e60c..a36911d 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -27,13 +27,12 @@
 HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
 HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
 
-
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
             sizeof(mMaxAverageLuminance) +
             sizeof(mMinLuminance) +
             sizeof(int32_t) +
-            mSupportedHdrTypes.size() * sizeof(int32_t);
+            mSupportedHdrTypes.size() * sizeof(ui::Hdr);
 }
 
 status_t HdrCapabilities::flatten(void* buffer, size_t size) const {
@@ -48,7 +47,7 @@
     reinterpret_cast<float&>(buf[2]) = mMinLuminance;
     buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size());
     for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) {
-        buf[4 + i] = mSupportedHdrTypes[i];
+        buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]);
     }
     return NO_ERROR;
 }
@@ -78,7 +77,7 @@
     if (itemCount) {
         mSupportedHdrTypes.resize(itemCount);
         for (size_t i = 0; i < itemCount; ++i) {
-            mSupportedHdrTypes[i] = buf[4 + i];
+            mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]);
         }
     }
     return NO_ERROR;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index b53c563..fe4ae6c 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -513,6 +513,12 @@
 
 bool Region::validate(const Region& reg, const char* name, bool silent)
 {
+    if (reg.mStorage.isEmpty()) {
+        ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
+        // return immediately as the code below assumes mStorage is non-empty
+        return false;
+    }
+
     bool result = true;
     const_iterator cur = reg.begin();
     const_iterator const tail = reg.end();
@@ -832,6 +838,11 @@
 }
 
 Region::const_iterator Region::end() const {
+    // Workaround for b/77643177
+    // mStorage should never be empty, but somehow it is and it's causing
+    // an abort in ubsan
+    if (mStorage.isEmpty()) return mStorage.array();
+
     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
     return mStorage.array() + numRects;
 }
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 30f4a59..92b2bfb 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -16,14 +16,21 @@
 
 #pragma once
 
-#include <system/graphics.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <string>
 
+namespace android {
+class Rect;
+}
+
 std::string decodeStandard(android_dataspace dataspace);
 std::string decodeTransfer(android_dataspace dataspace);
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
-std::string decodeColorMode(android_color_mode colormode);
+std::string decodeColorMode(android::ui::ColorMode colormode);
+std::string decodeColorTransform(android_color_transform colorTransform);
 std::string decodePixelFormat(android::PixelFormat format);
+std::string decodeRenderIntent(android::ui::RenderIntent renderIntent);
+std::string to_string(const android::Rect& rect);
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
new file mode 100644
index 0000000..f3c328d
--- /dev/null
+++ b/libs/ui/include/ui/DetachedBufferHandle.h
@@ -0,0 +1,52 @@
+/*
+ * 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 ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+
+#include <pdx/channel_handle.h>
+
+#include <memory>
+
+namespace android {
+
+// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
+// created. Current implementation assumes that the underlying transport is using libpdx (thus
+// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
+// backend if ever needed.
+class DetachedBufferHandle {
+public:
+    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
+        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
+    }
+
+    // Accessors to get or take the internal pdx::LocalChannelHandle.
+    pdx::LocalChannelHandle& handle() { return mHandle; }
+    const pdx::LocalChannelHandle& handle() const { return mHandle; }
+
+    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
+    bool isValid() const { return mHandle.valid(); }
+
+private:
+    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
+    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
+
+    pdx::LocalChannelHandle mHandle;
+};
+
+} // namespace android
+
+#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 37811bc..ec67fa9 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <android-base/unique_fd.h>
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -49,12 +50,13 @@
     // Construct a new Fence object with an invalid file descriptor.  This
     // should be done when the Fence object will be set up by unflattening
     // serialized data.
-    Fence();
+    Fence() = default;
 
     // Construct a new Fence object to manage a given fence file descriptor.
     // When the new Fence object is destructed the file descriptor will be
     // closed.
     explicit Fence(int fenceFd);
+    explicit Fence(base::unique_fd fenceFd);
 
     // Not copyable or movable.
     Fence(const Fence& rhs) = delete;
@@ -136,9 +138,9 @@
 private:
     // Only allow instantiation using ref counting.
     friend class LightRefBase<Fence>;
-    ~Fence();
+    ~Fence() = default;
 
-    int mFenceFd;
+    base::unique_fd mFenceFd;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 270675c..6a7479a 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -27,6 +27,17 @@
     float getWidth() const { return right - left; }
     float getHeight() const { return bottom - top; }
 
+    FloatRect intersect(const FloatRect& other) const {
+        return {
+            // Inline to avoid tromping on other min/max defines or adding a
+            // dependency on STL
+            (left > other.left) ? left : other.left,
+            (top > other.top) ? top : other.top,
+            (right < other.right) ? right : other.right,
+            (bottom < other.bottom) ? bottom : other.bottom
+        };
+    }
+
     float left = 0.0f;
     float top = 0.0f;
     float right = 0.0f;
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 8aee160..5a8dbda 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -20,7 +20,9 @@
 #include <string>
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -28,11 +30,11 @@
 namespace Gralloc2 {
 
 using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_0::BufferUsage;
-using hardware::graphics::common::V1_0::PixelFormat;
+using hardware::graphics::common::V1_1::BufferUsage;
+using hardware::graphics::common::V1_1::PixelFormat;
+using hardware::graphics::mapper::V2_1::IMapper;
 using hardware::graphics::mapper::V2_0::BufferDescriptor;
 using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::IMapper;
 using hardware::graphics::mapper::V2_0::YCbCrLayout;
 
 // A wrapper to IMapper
@@ -55,6 +57,13 @@
 
     void freeBuffer(buffer_handle_t bufferHandle) const;
 
+    Error validateBufferSize(buffer_handle_t bufferHandle,
+            const IMapper::BufferDescriptorInfo& descriptorInfo,
+            uint32_t stride) const;
+
+    void getTransportSize(buffer_handle_t bufferHandle,
+            uint32_t* outNumFds, uint32_t* outNumInts) const;
+
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
     Error lock(buffer_handle_t bufferHandle, uint64_t usage,
@@ -72,7 +81,12 @@
     int unlock(buffer_handle_t bufferHandle) const;
 
 private:
-    sp<IMapper> mMapper;
+    // Determines whether the passed info is compatible with the mapper.
+    Error validateBufferDescriptorInfo(
+            const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+
+    sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
+    sp<IMapper> mMapperV2_1;
 };
 
 // A wrapper to IAllocator
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 95c2d22..cc38982 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,6 +34,7 @@
 
 namespace android {
 
+class DetachedBufferHandle;
 class GraphicBufferMapper;
 
 // ===========================================================================
@@ -190,6 +191,11 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
+    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
+    bool isDetachedBuffer() const;
+    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
+    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
+
 private:
     ~GraphicBuffer();
 
@@ -230,12 +236,27 @@
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
+    // numbers of fds/ints in native_handle_t to flatten
+    uint32_t mTransportNumFds;
+    uint32_t mTransportNumInts;
+
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
+
+    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
+    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
+    // there are three different modes:
+    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
+    //    invalid.
+    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be valid.
+    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be invalid.
+    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 06961b1..7cf003d 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,6 +22,7 @@
 
 #include <memory>
 
+#include <ui/PixelFormat.h>
 #include <utils/Singleton.h>
 
 
@@ -49,10 +50,15 @@
     // The imported outHandle must be freed with freeBuffer when no longer
     // needed. rawHandle is owned by the caller.
     status_t importBuffer(buffer_handle_t rawHandle,
+            uint32_t width, uint32_t height, uint32_t layerCount,
+            PixelFormat format, uint64_t usage, uint32_t stride,
             buffer_handle_t* outHandle);
 
     status_t freeBuffer(buffer_handle_t handle);
 
+    void getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
+
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
 
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
new file mode 100644
index 0000000..0fa819d
--- /dev/null
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <system/graphics.h>
+
+// android::ui::* in this header file will alias different types as
+// the HIDL interface is updated.
+namespace android {
+namespace ui {
+
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::common::V1_1::RenderIntent;
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 925aa1b..4e98c28 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -21,6 +21,7 @@
 
 #include <vector>
 
+#include <ui/GraphicTypes.h>
 #include <utils/Flattenable.h>
 
 namespace android {
@@ -28,7 +29,7 @@
 class HdrCapabilities : public LightFlattenable<HdrCapabilities>
 {
 public:
-    HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
+    HdrCapabilities(const std::vector<ui::Hdr>& types,
             float maxLuminance, float maxAverageLuminance, float minLuminance)
       : mSupportedHdrTypes(types),
         mMaxLuminance(maxLuminance),
@@ -47,7 +48,7 @@
 
     ~HdrCapabilities();
 
-    const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
+    const std::vector<ui::Hdr>& getSupportedHdrTypes() const {
         return mSupportedHdrTypes;
     }
     float getDesiredMaxLuminance() const { return mMaxLuminance; }
@@ -61,7 +62,7 @@
     status_t unflatten(void const* buffer, size_t size);
 
 private:
-    std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
+    std::vector<ui::Hdr> mSupportedHdrTypes;
     float mMaxLuminance;
     float mMaxAverageLuminance;
     float mMinLuminance;
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index b50e4ec..0bec0b7 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -69,6 +69,15 @@
         bottom = rb.y;
     }
 
+    inline explicit Rect(const FloatRect& floatRect) {
+        // Ideally we would use std::round, but we don't want to add an STL
+        // dependency here, so we use an approximation
+        left = static_cast<int32_t>(floatRect.left + 0.5f);
+        top = static_cast<int32_t>(floatRect.top + 0.5f);
+        right = static_cast<int32_t>(floatRect.right + 0.5f);
+        bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
+    }
+
     void makeInvalid();
 
     inline void clear() {
@@ -86,15 +95,18 @@
     }
 
     // rectangle's width
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getWidth() const {
         return right - left;
     }
 
     // rectangle's height
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getHeight() const {
         return bottom - top;
     }
 
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline Rect getBounds() const {
         return Rect(right - left, bottom - top);
     }
diff --git a/libs/ui/include_vndk/ui/ANativeObjectBase.h b/libs/ui/include_vndk/ui/ANativeObjectBase.h
new file mode 120000
index 0000000..4dab8d8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ANativeObjectBase.h
@@ -0,0 +1 @@
+../../include/ui/ANativeObjectBase.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/BufferQueueDefs.h b/libs/ui/include_vndk/ui/BufferQueueDefs.h
new file mode 120000
index 0000000..c886ed8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/BufferQueueDefs.h
@@ -0,0 +1 @@
+../../include/ui/BufferQueueDefs.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h
new file mode 120000
index 0000000..ddf70d5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ColorSpace.h
@@ -0,0 +1 @@
+../../include/ui/ColorSpace.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DebugUtils.h b/libs/ui/include_vndk/ui/DebugUtils.h
new file mode 120000
index 0000000..8461bb3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DebugUtils.h
@@ -0,0 +1 @@
+../../include/ui/DebugUtils.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h
new file mode 120000
index 0000000..75f14cf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayStatInfo.h b/libs/ui/include_vndk/ui/DisplayStatInfo.h
new file mode 120000
index 0000000..6689ad3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayStatInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayStatInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Fence.h b/libs/ui/include_vndk/ui/Fence.h
new file mode 120000
index 0000000..b110201
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Fence.h
@@ -0,0 +1 @@
+../../include/ui/Fence.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FenceTime.h b/libs/ui/include_vndk/ui/FenceTime.h
new file mode 120000
index 0000000..01a6ff2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FenceTime.h
@@ -0,0 +1 @@
+../../include/ui/FenceTime.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FloatRect.h b/libs/ui/include_vndk/ui/FloatRect.h
new file mode 120000
index 0000000..a526211
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FloatRect.h
@@ -0,0 +1 @@
+../../include/ui/FloatRect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FrameStats.h b/libs/ui/include_vndk/ui/FrameStats.h
new file mode 120000
index 0000000..e68e5c8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FrameStats.h
@@ -0,0 +1 @@
+../../include/ui/FrameStats.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Gralloc2.h b/libs/ui/include_vndk/ui/Gralloc2.h
new file mode 120000
index 0000000..66098c4
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Gralloc2.h
@@ -0,0 +1 @@
+../../include/ui/Gralloc2.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBuffer.h b/libs/ui/include_vndk/ui/GraphicBuffer.h
new file mode 120000
index 0000000..445eae5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBuffer.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBuffer.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferAllocator.h b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
new file mode 120000
index 0000000..9634533
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferAllocator.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferMapper.h b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
new file mode 120000
index 0000000..c3b3a7c
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferMapper.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicTypes.h b/libs/ui/include_vndk/ui/GraphicTypes.h
new file mode 120000
index 0000000..b1859e0
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicTypes.h
@@ -0,0 +1 @@
+../../include/ui/GraphicTypes.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/HdrCapabilities.h b/libs/ui/include_vndk/ui/HdrCapabilities.h
new file mode 120000
index 0000000..a240828
--- /dev/null
+++ b/libs/ui/include_vndk/ui/HdrCapabilities.h
@@ -0,0 +1 @@
+../../include/ui/HdrCapabilities.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/PixelFormat.h b/libs/ui/include_vndk/ui/PixelFormat.h
new file mode 120000
index 0000000..0aba056
--- /dev/null
+++ b/libs/ui/include_vndk/ui/PixelFormat.h
@@ -0,0 +1 @@
+../../include/ui/PixelFormat.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Point.h b/libs/ui/include_vndk/ui/Point.h
new file mode 120000
index 0000000..0aeda3e
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Point.h
@@ -0,0 +1 @@
+../../include/ui/Point.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Rect.h b/libs/ui/include_vndk/ui/Rect.h
new file mode 120000
index 0000000..01ed689
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Rect.h
@@ -0,0 +1 @@
+../../include/ui/Rect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Region.h b/libs/ui/include_vndk/ui/Region.h
new file mode 120000
index 0000000..3f829bf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Region.h
@@ -0,0 +1 @@
+../../include/ui/Region.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/UiConfig.h b/libs/ui/include_vndk/ui/UiConfig.h
new file mode 120000
index 0000000..f580ce1
--- /dev/null
+++ b/libs/ui/include_vndk/ui/UiConfig.h
@@ -0,0 +1 @@
+../../include/ui/UiConfig.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 6733505..aef6428 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -18,10 +18,19 @@
     name: "Region_test",
     shared_libs: ["libui"],
     srcs: ["Region_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
 }
 
 cc_test {
     name: "colorspace_test",
     shared_libs: ["libui"],
     srcs: ["colorspace_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
+    name: "GraphicBuffer_test",
+    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    srcs: ["GraphicBuffer_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
 }
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
new file mode 100644
index 0000000..eb679ac
--- /dev/null
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GraphicBufferTest"
+
+#include <ui/DetachedBufferHandle.h>
+#include <ui/GraphicBuffer.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+namespace {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+
+} // namespace
+
+class GraphicBufferTest : public testing::Test {};
+
+TEST_F(GraphicBufferTest, DetachedBuffer) {
+    sp<GraphicBuffer> buffer(
+            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
+
+    // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
+    // BufferHub. But this may change in the future.
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+
+    pdx::LocalChannelHandle channel{nullptr, 1234};
+    EXPECT_TRUE(channel.valid());
+
+    std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
+    EXPECT_FALSE(channel.valid());
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_TRUE(handle->handle().valid());
+
+    buffer->setDetachedBufferHandle(std::move(handle));
+    EXPECT_TRUE(handle == nullptr);
+    EXPECT_TRUE(buffer->isDetachedBuffer());
+
+    handle = buffer->takeDetachedBufferHandle();
+    EXPECT_TRUE(handle != nullptr);
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+}
+
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index f327200..7b5ad44 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,6 +15,7 @@
 sourceFiles = [
     "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
+    "detached_buffer.cpp",
     "ion_buffer.cpp",
 ]
 
@@ -22,19 +23,16 @@
     "include",
 ]
 
-staticLibraries = [
-    "libdvrcommon",
-    "libpdx_default_transport",
-]
-
 sharedLibraries = [
     "libbase",
+    "libbinder",
     "libcutils",
     "libhardware",
     "liblog",
     "libui",
     "libutils",
-    "libnativewindow"
+    "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -48,9 +46,10 @@
         "-DLOG_TAG=\"libbufferhub\"",
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+        "-Wall",
+        "-Werror",
     ],
     export_include_dirs: localIncludeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "libbufferhub",
@@ -61,10 +60,10 @@
 
 cc_test {
     tags: ["optional"],
-    srcs: ["bufferhub_tests.cpp"],
-    static_libs: ["libbufferhub"] + staticLibraries,
+    srcs: ["buffer_hub-test.cpp"],
+    static_libs: ["libbufferhub"],
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
-    name: "bufferhub_tests",
+    name: "buffer_hub-test",
 }
 
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
new file mode 100644
index 0000000..e247398
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -0,0 +1,947 @@
+#include <gtest/gtest.h>
+#include <poll.h>
+#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
+#include <private/dvr/detached_buffer.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <mutex>
+#include <thread>
+
+#define RETRY_EINTR(fnc_call)                 \
+  ([&]() -> decltype(fnc_call) {              \
+    decltype(fnc_call) result;                \
+    do {                                      \
+      result = (fnc_call);                    \
+    } while (result == -1 && errno == EINTR); \
+    return result;                            \
+  })()
+
+using android::GraphicBuffer;
+using android::sp;
+using android::dvr::BufferConsumer;
+using android::dvr::BufferProducer;
+using android::dvr::DetachedBuffer;
+using android::dvr::BufferHubDefs::IsBufferAcquired;
+using android::dvr::BufferHubDefs::IsBufferGained;
+using android::dvr::BufferHubDefs::IsBufferPosted;
+using android::dvr::BufferHubDefs::IsBufferReleased;
+using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kMetadataHeaderSize;
+using android::dvr::BufferHubDefs::kProducerStateBit;
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
+const uint64_t kContext = 42;
+const size_t kMaxConsumerCount = 63;
+const int kPollTimeoutMs = 100;
+
+using LibBufferHubTest = ::testing::Test;
+
+TEST_F(LibBufferHubTest, TestBasicUsage) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  // Check that consumers can spawn other consumers.
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(c->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+
+  // Producer state mask is unique, i.e. 1.
+  EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+  // Consumer state mask cannot have producer bit on.
+  EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U);
+  // Consumer state mask must be a single, i.e. power of 2.
+  EXPECT_NE(c->buffer_state_bit(), 0U);
+  EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U);
+  // Consumer state mask cannot have producer bit on.
+  EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U);
+  // Consumer state mask must be a single, i.e. power of 2.
+  EXPECT_NE(c2->buffer_state_bit(), 0U);
+  EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U);
+  // Each consumer should have unique bit.
+  EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U);
+
+  // Initial state: producer not available, consumers not available.
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // New state: producer not available, consumers available.
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  uint64_t context;
+  LocalHandle fence;
+  EXPECT_EQ(0, c->Acquire(&fence, &context));
+  EXPECT_EQ(kContext, context);
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, c2->Acquire(&fence, &context));
+  EXPECT_EQ(kContext, context);
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c2->Discard());
+
+  EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->Gain(&fence));
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+}
+
+TEST_F(LibBufferHubTest, TestEpoll) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
+  ASSERT_TRUE(epoll_fd.IsValid());
+
+  epoll_event event;
+  std::array<epoll_event, 64> events;
+
+  auto event_sources = p->GetEventSources();
+  ASSERT_LT(event_sources.size(), events.size());
+
+  for (const auto& event_source : event_sources) {
+    event = {.events = event_source.event_mask | EPOLLET,
+             .data = {.fd = p->event_fd()}};
+    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+                           &event));
+  }
+
+  event_sources = c->GetEventSources();
+  ASSERT_LT(event_sources.size(), events.size());
+
+  for (const auto& event_source : event_sources) {
+    event = {.events = event_source.event_mask | EPOLLET,
+             .data = {.fd = c->event_fd()}};
+    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+                           &event));
+  }
+
+  // No events should be signaled initially.
+  ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
+
+  // Post the producer and check for consumer signal.
+  EXPECT_EQ(0, p->Post({}, kContext));
+  ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  ASSERT_TRUE(events[0].events & EPOLLIN);
+  ASSERT_EQ(c->event_fd(), events[0].data.fd);
+
+  // Save the event bits to translate later.
+  event = events[0];
+
+  // Check for events again. Edge-triggered mode should prevent any.
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+
+  // Translate the events.
+  auto event_status = c->GetEventMask(event.events);
+  ASSERT_TRUE(event_status);
+  ASSERT_TRUE(event_status.get() & EPOLLIN);
+
+  // Check for events again. Edge-triggered mode should prevent any.
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestStateMask) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // It's ok to create up to kMaxConsumerCount consumer buffers.
+  uint64_t buffer_state_bits = p->buffer_state_bit();
+  std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    // Expect all buffers have unique state mask.
+    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+    buffer_state_bits |= cs[i]->buffer_state_bit();
+  }
+  EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+
+  // The 64th creation will fail with out-of-memory error.
+  auto state = p->CreateConsumer();
+  EXPECT_EQ(state.error(), E2BIG);
+
+  // Release any consumer should allow us to re-create.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    buffer_state_bits &= ~cs[i]->buffer_state_bit();
+    cs[i] = nullptr;
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    // The released state mask will be reused.
+    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+    buffer_state_bits |= cs[i]->buffer_state_bit();
+    EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+  }
+}
+
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  uint64_t context;
+  LocalHandle fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Acquire in posted state should succeed.
+  EXPECT_LE(0, c->Acquire(&fence, &context));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->Gain(&fence));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestAsyncStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Acquire in posted state should succeed.
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+}
+
+TEST_F(LibBufferHubTest, TestZeroConsumer) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Newly created.
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // The buffer should stay in posted stay until a consumer picks it up.
+  EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // A new consumer should still be able to acquire the buffer immediately.
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestMaxConsumers) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state()));
+  }
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the producer should trigger all consumers to be available.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_TRUE(
+        IsBufferPosted(cs[i]->buffer_state(), cs[i]->buffer_state_bit()));
+    EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+    EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
+    EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+  }
+
+  // All consumers have to release before the buffer is considered to be
+  // released.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+    EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
+  }
+
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Buffer state cross all clients must be consistent.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state());
+  }
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(c->buffer_state()));
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the gained buffer should signal already created consumer.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the gained buffer before any consumer gets created.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // Newly created consumer should be automatically sigalled.
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_TRUE(IsBufferPosted(c->buffer_state()));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  std::unique_ptr<BufferConsumer> c1 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c1.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post, acquire, and release the buffer..
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
+
+  // Note that the next PDX call is on the producer channel, which may be
+  // executed before Release impulse gets executed by bufferhubd. Thus, here we
+  // need to wait until the releasd is confirmed before creating another
+  // consumer.
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Create another consumer immediately after the release, should not make the
+  // buffer un-released.
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  Metadata m = {1, 3};
+  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+  EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  LocalHandle fence;
+  Metadata m2 = {};
+  EXPECT_EQ(0, c->Acquire(&fence, &m2));
+  EXPECT_EQ(m.field1, m2.field1);
+  EXPECT_EQ(m.field2, m2.field2);
+
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+}
+
+TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  struct OverSizedMetadata {
+    int64_t field1;
+    int64_t field2;
+    int64_t field3;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  // It is illegal to post metadata larger than originally requested during
+  // buffer allocation.
+  OverSizedMetadata evil_meta = {};
+  EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
+  EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  // It is ok to post metadata smaller than originally requested during
+  // buffer allocation.
+  int64_t sequence = 42;
+  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  struct OverSizedMetadata {
+    int64_t field1;
+    int64_t field2;
+    int64_t field3;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  Metadata m = {1, 3};
+  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+
+  LocalHandle fence;
+  int64_t sequence;
+  OverSizedMetadata e;
+
+  // It is illegal to acquire metadata larger than originally requested during
+  // buffer allocation.
+  EXPECT_NE(0, c->Acquire(&fence, &e));
+
+  // It is ok to acquire metadata smaller than originally requested during
+  // buffer allocation.
+  EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+  EXPECT_EQ(m.field1, sequence);
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  int64_t sequence = 3;
+  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+
+  LocalHandle fence;
+  EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestWithNoMeta) {
+  std::unique_ptr<BufferProducer> p =
+      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  LocalHandle fence;
+
+  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+  EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
+  std::unique_ptr<BufferProducer> p =
+      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  int64_t sequence = 3;
+  EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+}
+
+namespace {
+
+int PollFd(int fd, int timeout_ms) {
+  pollfd p = {fd, POLLIN, 0};
+  return poll(&p, 1, timeout_ms);
+}
+
+}  // namespace
+
+TEST_F(LibBufferHubTest, TestAcquireFence) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata meta;
+  LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+
+  // Post with unsignaled fence.
+  EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+  // Should acquire a valid fence.
+  LocalHandle f2;
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
+  EXPECT_TRUE(f2.IsValid());
+  // The original fence and acquired fence should have different fd number.
+  EXPECT_NE(f1.Get(), f2.Get());
+  EXPECT_GE(0, PollFd(f2.Get(), 0));
+
+  // Signal the original fence will trigger the new fence.
+  eventfd_write(f1.Get(), 1);
+  // Now the original FD has been signaled.
+  EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs));
+
+  // Release the consumer with an invalid fence.
+  EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
+
+  // Should gain an invalid fence.
+  LocalHandle f3;
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->GainAsync(&meta, &f3));
+  EXPECT_FALSE(f3.IsValid());
+
+  // Post with a signaled fence.
+  EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+  // Should acquire a valid fence and it's already signalled.
+  LocalHandle f4;
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
+  EXPECT_TRUE(f4.IsValid());
+  EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
+
+  // Release with an unsignalled fence and signal it immediately after release
+  // without producer gainning.
+  LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+  EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
+  eventfd_write(f5.Get(), 1);
+
+  // Should gain a valid fence, which is already signaled.
+  LocalHandle f6;
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->GainAsync(&meta, &f6));
+  EXPECT_TRUE(f6.IsValid());
+  EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c1 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c1.get() != nullptr);
+  const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+
+  DvrNativeBufferMetadata meta;
+  EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
+
+  LocalHandle fence;
+  EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+  EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
+  // Destroy the consumer now will make it orphaned and the buffer is still
+  // acquired.
+  c1 = nullptr;
+  EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+  const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
+  EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+
+  // The new consumer is available for acquire.
+  EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+  EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
+  // Releasing the consumer makes the buffer gainable.
+  EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
+
+  // The buffer is now available for the producer to gain.
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // But if another consumer is created in released state.
+  std::unique_ptr<BufferConsumer> c3 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c3.get() != nullptr);
+  const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
+  EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+  // The consumer buffer is not acquirable.
+  EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
+
+  // Producer should be able to gain no matter what.
+  EXPECT_EQ(0, p->GainAsync(&meta, &fence));
+}
+
+TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(p.get() != nullptr);
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+  int p_id = p->id();
+
+  // Detach in posted state should fail.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  auto s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in acquired state should fail.
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in released state should fail.
+  EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in gained state should succeed.
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_TRUE(s1);
+
+  LocalChannelHandle handle = s1.take();
+  EXPECT_TRUE(handle.valid());
+
+  // Both producer and consumer should have hangup.
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  auto s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  auto s3 = p->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EOPNOTSUPP as the socket towards
+  // ProducerChannel has been teared down.
+  EXPECT_EQ(s3.error(), EOPNOTSUPP);
+
+  s3 = c->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EPIPE returned from
+  // ConsumerChannel::HandleMessage as the socket is still open but the producer
+  // is gone.
+  EXPECT_EQ(s3.error(), EPIPE);
+
+  // Detached buffer handle can be use to construct a new DetachedBuffer object.
+  auto d = DetachedBuffer::Import(std::move(handle));
+  EXPECT_FALSE(handle.valid());
+  EXPECT_TRUE(d->IsConnected());
+  EXPECT_TRUE(d->IsValid());
+
+  ASSERT_TRUE(d->buffer() != nullptr);
+  EXPECT_EQ(d->buffer()->initCheck(), 0);
+  EXPECT_EQ(d->id(), p_id);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
+  // Buffer Creation will fail: BLOB format requires height to be 1.
+  auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
+                                   /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+                                   kUserMetadataSize);
+
+  EXPECT_FALSE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(b1->buffer() == nullptr);
+
+  // Buffer Creation will fail: user metadata size too large.
+  auto b2 = DetachedBuffer::Create(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage,
+      /*user_metadata_size=*/std::numeric_limits<size_t>::max());
+
+  EXPECT_FALSE(b2->IsConnected());
+  EXPECT_FALSE(b2->IsValid());
+  EXPECT_TRUE(b2->buffer() == nullptr);
+
+  // Buffer Creation will fail: user metadata size too large.
+  auto b3 = DetachedBuffer::Create(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage,
+      /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
+          kMetadataHeaderSize);
+
+  EXPECT_FALSE(b3->IsConnected());
+  EXPECT_FALSE(b3->IsValid());
+  EXPECT_TRUE(b3->buffer() == nullptr);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_TRUE(b1->IsValid());
+  ASSERT_TRUE(b1->buffer() != nullptr);
+  EXPECT_NE(b1->id(), 0);
+  EXPECT_EQ(b1->buffer()->initCheck(), 0);
+  EXPECT_FALSE(b1->buffer()->isDetachedBuffer());
+
+  // Takes a standalone GraphicBuffer which still holds on an
+  // PDX::LocalChannelHandle towards BufferHub.
+  sp<GraphicBuffer> g1 = b1->TakeGraphicBuffer();
+  ASSERT_TRUE(g1 != nullptr);
+  EXPECT_TRUE(g1->isDetachedBuffer());
+
+  EXPECT_FALSE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(b1->buffer() == nullptr);
+
+  sp<GraphicBuffer> g2 = b1->TakeGraphicBuffer();
+  ASSERT_TRUE(g2 == nullptr);
+
+  auto h1 = g1->takeDetachedBufferHandle();
+  ASSERT_TRUE(h1 != nullptr);
+  ASSERT_TRUE(h1->isValid());
+  EXPECT_FALSE(g1->isDetachedBuffer());
+
+  auto b2 = DetachedBuffer::Import(std::move(h1->handle()));
+  ASSERT_FALSE(h1->isValid());
+  EXPECT_TRUE(b2->IsConnected());
+  EXPECT_TRUE(b2->IsValid());
+
+  ASSERT_TRUE(b2->buffer() != nullptr);
+  EXPECT_EQ(b2->buffer()->initCheck(), 0);
+
+  // The newly created DetachedBuffer should share the original buffer_id.
+  EXPECT_EQ(b2->id(), b1_id);
+  EXPECT_FALSE(b2->buffer()->isDetachedBuffer());
+}
+
+TEST_F(LibBufferHubTest, TestPromoteDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+  EXPECT_TRUE(b1->IsValid());
+
+  auto status_or_handle = b1->Promote();
+  EXPECT_TRUE(status_or_handle);
+
+  // The detached buffer should have hangup.
+  EXPECT_GT(RETRY_EINTR(b1->Poll(kPollTimeoutMs)), 0);
+  auto status_or_int = b1->GetEventMask(POLLHUP);
+  EXPECT_TRUE(status_or_int.ok());
+  EXPECT_EQ(status_or_int.get(), POLLHUP);
+
+  // The buffer client is still considered as connected but invalid.
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+
+  // Gets the channel handle for the producer.
+  LocalChannelHandle h1 = status_or_handle.take();
+  EXPECT_TRUE(h1.valid());
+
+  std::unique_ptr<BufferProducer> p1 = BufferProducer::Import(std::move(h1));
+  EXPECT_FALSE(h1.valid());
+  ASSERT_TRUE(p1 != nullptr);
+  int p1_id = p1->id();
+
+  // A newly promoted ProducerBuffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, p1_id);
+  EXPECT_TRUE(IsBufferGained(p1->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestDetachThenPromote) {
+  std::unique_ptr<BufferProducer> p1 = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p1.get() != nullptr);
+  int p1_id = p1->id();
+
+  // Detached the producer.
+  auto status_or_handle = p1->Detach();
+  EXPECT_TRUE(status_or_handle.ok());
+  LocalChannelHandle h1 = status_or_handle.take();
+  EXPECT_TRUE(h1.valid());
+
+  // Detached buffer handle can be use to construct a new DetachedBuffer object.
+  auto b1 = DetachedBuffer::Import(std::move(h1));
+  EXPECT_FALSE(h1.valid());
+  EXPECT_TRUE(b1->IsValid());
+  int b1_id = b1->id();
+  EXPECT_EQ(b1_id, p1_id);
+
+  // Promote the detached buffer.
+  status_or_handle = b1->Promote();
+  // The buffer client is still considered as connected but invalid.
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(status_or_handle.ok());
+
+  // Gets the channel handle for the producer.
+  LocalChannelHandle h2 = status_or_handle.take();
+  EXPECT_TRUE(h2.valid());
+
+  std::unique_ptr<BufferProducer> p2 = BufferProducer::Import(std::move(h2));
+  EXPECT_FALSE(h2.valid());
+  ASSERT_TRUE(p2 != nullptr);
+  int p2_id = p2->id();
+
+  // A newly promoted ProducerBuffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, p2_id);
+  EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 97341b1..159f2bd 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -15,10 +15,30 @@
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Status;
+using android::pdx::default_transport::ClientChannel;
+using android::pdx::default_transport::ClientChannelFactory;
 
 namespace android {
 namespace dvr {
 
+BufferHubClient::BufferHubClient()
+    : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {}
+
+BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
+    : Client(ClientChannel::Create(std::move(channel_handle))) {}
+
+bool BufferHubClient::IsValid() const {
+  return IsConnected() && GetChannelHandle().valid();
+}
+
+LocalChannelHandle BufferHubClient::TakeChannelHandle() {
+  if (IsConnected()) {
+    return std::move(GetChannelHandle());
+  } else {
+    return {};
+  }
+}
+
 BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
     : Client{pdx::default_transport::ClientChannel::Create(
           std::move(channel_handle))},
@@ -395,25 +415,16 @@
 }
 
 BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint32_t usage, size_t user_metadata_size)
-    : BufferProducer(width, height, format, usage, usage, user_metadata_size) {}
-
-BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t user_metadata_size)
+                               uint64_t usage, size_t user_metadata_size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
   ALOGD_IF(TRACE,
            "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
-           "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64
-           " user_metadata_size=%zu",
-           event_fd(), width, height, format, producer_usage, consumer_usage,
-           user_metadata_size);
+           "usage=%" PRIx64 " user_metadata_size=%zu",
+           event_fd(), width, height, format, usage, user_metadata_size);
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE(
         "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
@@ -431,70 +442,18 @@
   }
 }
 
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t width, uint32_t height,
-                               uint32_t format, uint32_t usage,
-                               size_t user_metadata_size)
-    : BufferProducer(name, user_id, group_id, width, height, format, usage,
-                     usage, user_metadata_size) {}
-
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t width, uint32_t height,
-                               uint32_t format, uint64_t producer_usage,
-                               uint64_t consumer_usage,
-                               size_t user_metadata_size)
+BufferProducer::BufferProducer(uint64_t usage, size_t size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d "
-           "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64
-           " consumer_usage=%" PRIx64 " user_metadata_size=%zu",
-           event_fd(), name.c_str(), user_id, group_id, width, height, format,
-           producer_usage, consumer_usage, user_metadata_size);
-
-  // (b/37881101) Deprecate producer/consumer usage
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
-      name, user_id, group_id, width, height, format,
-      (producer_usage | consumer_usage), user_metadata_size);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to create/get persistent "
-        "buffer \"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(uint32_t usage, size_t size)
-    : BufferProducer(usage, usage, size) {}
-
-BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: producer_usage=%" PRIx64
-           " consumer_usage=%" PRIx64 " size=%zu",
-           producer_usage, consumer_usage, size);
+  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
+           usage, size);
   const int width = static_cast<int>(size);
   const int height = 1;
   const int format = HAL_PIXEL_FORMAT_BLOB;
   const size_t user_metadata_size = 0;
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
           status.GetErrorMessage().c_str());
@@ -511,73 +470,6 @@
   }
 }
 
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t usage, size_t size)
-    : BufferProducer(name, user_id, group_id, usage, usage, size) {}
-
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint64_t producer_usage,
-                               uint64_t consumer_usage, size_t size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: name=%s user_id=%d group=%d "
-           "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " size=%zu",
-           name.c_str(), user_id, group_id, producer_usage, consumer_usage,
-           size);
-  const int width = static_cast<int>(size);
-  const int height = 1;
-  const int format = HAL_PIXEL_FORMAT_BLOB;
-  const size_t user_metadata_size = 0;
-
-  // (b/37881101) Deprecate producer/consumer usage
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
-      name, user_id, group_id, width, height, format,
-      (producer_usage | consumer_usage), user_metadata_size);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to create persistent "
-        "buffer \"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(const std::string& name)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: name=%s", name.c_str());
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::GetPersistentBuffer>(name);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to get producer buffer by name "
-        "\"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
 BufferProducer::BufferProducer(LocalChannelHandle channel)
     : BASE(std::move(channel)) {
   const int ret = ImportBuffer();
@@ -736,18 +628,22 @@
                        : LocalChannelHandle{nullptr, -status.error()});
 }
 
-int BufferProducer::MakePersistent(const std::string& name, int user_id,
-                                   int group_id) {
-  ATRACE_NAME("BufferProducer::MakePersistent");
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ProducerMakePersistent>(name, user_id,
-                                                               group_id));
-}
+Status<LocalChannelHandle> BufferProducer::Detach() {
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a BufferProducer when it's in gained state.
+    ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
+          ") is not in gained state.",
+          id(), buffer_state);
+    return {};
+  }
 
-int BufferProducer::RemovePersistence() {
-  ATRACE_NAME("BufferProducer::RemovePersistence");
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ProducerRemovePersistence>());
+  Status<LocalChannelHandle> status =
+      InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+  ALOGE_IF(!status,
+           "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+           status.GetErrorMessage().c_str());
+  return status;
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
deleted file mode 100644
index c4b9a8c..0000000
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-#include <gtest/gtest.h>
-#include <poll.h>
-#include <private/dvr/buffer_hub_client.h>
-#include <private/dvr/bufferhub_rpc.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <mutex>
-#include <thread>
-
-#define RETRY_EINTR(fnc_call)                 \
-  ([&]() -> decltype(fnc_call) {              \
-    decltype(fnc_call) result;                \
-    do {                                      \
-      result = (fnc_call);                    \
-    } while (result == -1 && errno == EINTR); \
-    return result;                            \
-  })()
-
-using android::dvr::BufferConsumer;
-using android::dvr::BufferHubDefs::kConsumerStateMask;
-using android::dvr::BufferHubDefs::kProducerStateBit;
-using android::dvr::BufferProducer;
-using android::pdx::LocalHandle;
-
-const int kWidth = 640;
-const int kHeight = 480;
-const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-const int kUsage = 0;
-const uint64_t kContext = 42;
-
-using LibBufferHubTest = ::testing::Test;
-
-TEST_F(LibBufferHubTest, TestBasicUsage) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-  // Check that consumers can spawn other consumers.
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(c->CreateConsumer());
-  ASSERT_TRUE(c2.get() != nullptr);
-
-  // Producer state mask is unique, i.e. 1.
-  EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
-  // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0);
-  // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c->buffer_state_bit(), 0);
-  EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0);
-  // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0);
-  // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c2->buffer_state_bit(), 0);
-  EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0);
-  // Each consumer should have unique bit.
-  EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0);
-
-  // Initial state: producer not available, consumers not available.
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
-
-  // New state: producer not available, consumers available.
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
-
-  uint64_t context;
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence, &context));
-  EXPECT_EQ(kContext, context);
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
-
-  EXPECT_EQ(0, c2->Acquire(&fence, &context));
-  EXPECT_EQ(kContext, context);
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, c2->Discard());
-
-  EXPECT_EQ(1, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, p->Gain(&fence));
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-}
-
-TEST_F(LibBufferHubTest, TestEpoll) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
-  ASSERT_TRUE(epoll_fd.IsValid());
-
-  epoll_event event;
-  std::array<epoll_event, 64> events;
-
-  auto event_sources = p->GetEventSources();
-  ASSERT_LT(event_sources.size(), events.size());
-
-  for (const auto& event_source : event_sources) {
-    event = {.events = event_source.event_mask | EPOLLET,
-             .data = {.fd = p->event_fd()}};
-    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
-                           &event));
-  }
-
-  event_sources = c->GetEventSources();
-  ASSERT_LT(event_sources.size(), events.size());
-
-  for (const auto& event_source : event_sources) {
-    event = {.events = event_source.event_mask | EPOLLET,
-             .data = {.fd = c->event_fd()}};
-    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
-                           &event));
-  }
-
-  // No events should be signaled initially.
-  ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
-
-  // Post the producer and check for consumer signal.
-  EXPECT_EQ(0, p->Post({}, kContext));
-  ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  ASSERT_TRUE(events[0].events & EPOLLIN);
-  ASSERT_EQ(c->event_fd(), events[0].data.fd);
-
-  // Save the event bits to translate later.
-  event = events[0];
-
-  // Check for events again. Edge-triggered mode should prevent any.
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-
-  // Translate the events.
-  auto event_status = c->GetEventMask(event.events);
-  ASSERT_TRUE(event_status);
-  ASSERT_TRUE(event_status.get() & EPOLLIN);
-
-  // Check for events again. Edge-triggered mode should prevent any.
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-}
-
-TEST_F(LibBufferHubTest, TestStateMask) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-
-  // It's ok to create up to 63 consumer buffers.
-  uint64_t buffer_state_bits = p->buffer_state_bit();
-  std::array<std::unique_ptr<BufferConsumer>, 63> cs;
-  for (size_t i = 0; i < 63; i++) {
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
-    ASSERT_TRUE(cs[i].get() != nullptr);
-    // Expect all buffers have unique state mask.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
-  }
-  EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
-
-  // The 64th creation will fail with out-of-memory error.
-  auto state = p->CreateConsumer();
-  EXPECT_EQ(state.error(), E2BIG);
-
-  // Release any consumer should allow us to re-create.
-  for (size_t i = 0; i < 63; i++) {
-    buffer_state_bits &= ~cs[i]->buffer_state_bit();
-    cs[i] = nullptr;
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
-    ASSERT_TRUE(cs[i].get() != nullptr);
-    // The released state mask will be reused.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
-    EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
-  }
-}
-
-TEST_F(LibBufferHubTest, TestStateTransitions) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  uint64_t context;
-  LocalHandle fence;
-
-  // The producer buffer starts in gained state.
-
-  // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EALREADY, p->Gain(&fence));
-
-  // Post in gained state should succeed.
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
-
-  // Post, release, and gain in posted state should fail.
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EBUSY, p->Gain(&fence));
-
-  // Acquire in posted state should succeed.
-  EXPECT_LE(0, c->Acquire(&fence, &context));
-
-  // Acquire, post, and gain in acquired state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-  EXPECT_EQ(-EBUSY, p->Gain(&fence));
-
-  // Release in acquired state should succeed.
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // Release, acquire, and post in released state should fail.
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-
-  // Gain in released state should succeed.
-  EXPECT_EQ(0, p->Gain(&fence));
-
-  // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EALREADY, p->Gain(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
-  EXPECT_LE(0, RETRY_EINTR(c->Poll(10)));
-
-  LocalHandle fence;
-  Metadata m2 = {};
-  EXPECT_EQ(0, c->Acquire(&fence, &m2));
-  EXPECT_EQ(m.field1, m2.field1);
-  EXPECT_EQ(m.field2, m2.field2);
-
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
-}
-
-TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  struct OverSizedMetadata {
-    int64_t field1;
-    int64_t field2;
-    int64_t field3;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  // It is illegal to post metadata larger than originally requested during
-  // buffer allocation.
-  OverSizedMetadata evil_meta = {};
-  EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
-  EXPECT_GE(0, RETRY_EINTR(c->Poll(10)));
-
-  // It is ok to post metadata smaller than originally requested during
-  // buffer allocation.
-  int64_t sequence = 42;
-  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  struct OverSizedMetadata {
-    int64_t field1;
-    int64_t field2;
-    int64_t field3;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
-
-  LocalHandle fence;
-  int64_t sequence;
-  OverSizedMetadata e;
-
-  // It is illegal to acquire metadata larger than originally requested during
-  // buffer allocation.
-  EXPECT_NE(0, c->Acquire(&fence, &e));
-
-  // It is ok to acquire metadata smaller than originally requested during
-  // buffer allocation.
-  EXPECT_EQ(0, c->Acquire(&fence, &sequence));
-  EXPECT_EQ(m.field1, sequence);
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  int64_t sequence = 3;
-  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
-
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestWithNoMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  LocalHandle fence;
-
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  int64_t sequence = 3;
-  EXPECT_NE(0, p->Post(LocalHandle(), sequence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  // Record the original buffer id for later comparison.
-  const int buffer_id = p->id();
-
-  auto c = BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_NE(nullptr, c);
-
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-
-  // Close the connection to the producer. This should not affect the consumer.
-  p = nullptr;
-
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence));
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-
-  // Attempt to reconnect to the persistent buffer.
-  p = BufferProducer::Create("TestPersistentBuffer");
-  ASSERT_NE(nullptr, p);
-  EXPECT_EQ(buffer_id, p->id());
-  EXPECT_EQ(0, p->Gain(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  // Close the connection to the producer.
-  p = nullptr;
-
-  // Mismatch the params.
-  p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2,
-                             kHeight, kFormat, kUsage);
-  ASSERT_EQ(nullptr, p);
-}
-
-TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  LocalHandle fence;
-  auto c = BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_NE(nullptr, c);
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, c->Acquire(&fence));
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // Test that removing persistence and closing the producer orphans the
-  // consumer.
-  EXPECT_EQ(0, p->Gain(&fence));
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, p->RemovePersistence());
-  p = nullptr;
-
-  // Orphaned consumer can acquire the posted buffer one more time in
-  // asynchronous manner. But synchronous call will fail.
-  DvrNativeBufferMetadata meta;
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &fence));
-  EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
-}
-
-namespace {
-
-int PollFd(int fd, int timeout_ms) {
-  pollfd p = {fd, POLLIN, 0};
-  return poll(&p, 1, timeout_ms);
-}
-
-}  // namespace
-
-TEST_F(LibBufferHubTest, TestAcquireFence) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  DvrNativeBufferMetadata meta;
-  LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-
-  // Post with unsignaled fence.
-  EXPECT_EQ(0, p->PostAsync(&meta, f1));
-
-  // Should acquire a valid fence.
-  LocalHandle f2;
-  EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
-  EXPECT_TRUE(f2.IsValid());
-  // The original fence and acquired fence should have different fd number.
-  EXPECT_NE(f1.Get(), f2.Get());
-  EXPECT_GE(0, PollFd(f2.Get(), 0));
-
-  // Signal the original fence will trigger the new fence.
-  eventfd_write(f1.Get(), 1);
-  // Now the original FD has been signaled.
-  EXPECT_LT(0, PollFd(f2.Get(), 10));
-
-  // Release the consumer with an invalid fence.
-  EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
-
-  // Should gain an invalid fence.
-  LocalHandle f3;
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-  EXPECT_EQ(0, p->GainAsync(&meta, &f3));
-  EXPECT_FALSE(f3.IsValid());
-
-  // Post with a signaled fence.
-  EXPECT_EQ(0, p->PostAsync(&meta, f1));
-
-  // Should acquire a valid fence and it's already signalled.
-  LocalHandle f4;
-  EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
-  EXPECT_TRUE(f4.IsValid());
-  EXPECT_LT(0, PollFd(f4.Get(), 10));
-
-  // Release with an unsignalled fence and signal it immediately after release
-  // without producer gainning.
-  LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-  EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
-  eventfd_write(f5.Get(), 1);
-
-  // Should gain a valid fence, which is already signaled.
-  LocalHandle f6;
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-  EXPECT_EQ(0, p->GainAsync(&meta, &f6));
-  EXPECT_TRUE(f6.IsValid());
-  EXPECT_LT(0, PollFd(f6.Get(), 10));
-}
-
-TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c1 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
-
-  DvrNativeBufferMetadata meta;
-  EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
-
-  LocalHandle fence;
-  EXPECT_LT(0, RETRY_EINTR(c1->Poll(10)));
-  EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
-  // Destroy the consumer now will make it orphaned and the buffer is still
-  // acquired.
-  c1 = nullptr;
-  EXPECT_GE(0, RETRY_EINTR(p->Poll(10)));
-
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
-
-  // The new consumer is available for acquire.
-  EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
-  EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
-  // Releasing the consumer makes the buffer gainable.
-  EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
-
-  // The buffer is now available for the producer to gain.
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // But if another consumer is created in released state.
-  std::unique_ptr<BufferConsumer> c3 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c3.get() != nullptr);
-  const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
-  // The consumer buffer is not acquirable.
-  EXPECT_GE(0, RETRY_EINTR(c3->Poll(10)));
-  EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
-
-  // Producer should be able to gain no matter what.
-  EXPECT_EQ(0, p->GainAsync(&meta, &fence));
-}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
new file mode 100644
index 0000000..6fae16d
--- /dev/null
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -0,0 +1,125 @@
+#include <private/dvr/detached_buffer.h>
+
+#include <pdx/file_handle.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <poll.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height,
+                               uint32_t layer_count, uint32_t format,
+                               uint64_t usage, size_t user_metadata_size) {
+  ATRACE_NAME("DetachedBuffer::DetachedBuffer");
+  ALOGD_IF(TRACE,
+           "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, "
+           "format=%u usage=%" PRIx64 " user_metadata_size=%zu",
+           width, height, layer_count, format, usage, user_metadata_size);
+
+  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>(
+      width, height, layer_count, format, usage, user_metadata_size);
+  if (!status) {
+    ALOGE(
+        "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s",
+        status.GetErrorMessage().c_str());
+    client_.Close(-status.error());
+  }
+
+  const int ret = ImportGraphicBuffer();
+  if (ret < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
+          strerror(-ret));
+    client_.Close(ret);
+  }
+}
+
+DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle)
+    : client_(std::move(channel_handle)) {
+  const int ret = ImportGraphicBuffer();
+  if (ret < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
+          strerror(-ret));
+    client_.Close(ret);
+  }
+}
+
+int DetachedBuffer::ImportGraphicBuffer() {
+  ATRACE_NAME("DetachedBuffer::DetachedBuffer");
+
+  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>();
+  if (!status) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s",
+          status.GetErrorMessage().c_str());
+    return -status.error();
+  }
+
+  BufferDescription<LocalHandle> buffer_desc = status.take();
+  if (buffer_desc.id() < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!");
+    return -EIO;
+  }
+
+  // Stash the buffer id to replace the value in id_.
+  const int buffer_id = buffer_desc.id();
+
+  // Import the buffer.
+  IonBuffer ion_buffer;
+  ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id);
+
+  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) {
+    ALOGE("Failed to import GraphicBuffer, error=%d", ret);
+    return ret;
+  }
+
+  // If all imports succeed, replace the previous buffer and id.
+  id_ = buffer_id;
+  buffer_ = std::move(ion_buffer);
+  return 0;
+}
+
+int DetachedBuffer::Poll(int timeout_ms) {
+  ATRACE_NAME("DetachedBuffer::Poll");
+  pollfd p = {client_.event_fd(), POLLIN, 0};
+  return poll(&p, 1, timeout_ms);
+}
+
+Status<LocalChannelHandle> DetachedBuffer::Promote() {
+  ATRACE_NAME("DetachedBuffer::Promote");
+  ALOGD_IF(TRACE, "DetachedBuffer::Promote: id=%d.", id_);
+
+  auto status_or_handle =
+      client_.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
+  if (status_or_handle.ok()) {
+    // Invalidate the buffer.
+    buffer_ = {};
+  } else {
+    ALOGE("DetachedBuffer::Promote: Failed to promote buffer (id=%d): %s.", id_,
+          status_or_handle.GetErrorMessage().c_str());
+  }
+  return status_or_handle;
+}
+
+sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
+  if (!client_.IsValid() || !buffer_.buffer()) {
+    ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
+    return nullptr;
+  }
+
+  // Technically this should never happen.
+  LOG_FATAL_IF(
+      buffer_.buffer()->isDetachedBuffer(),
+      "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached.");
+
+  sp<GraphicBuffer> buffer = std::move(buffer_.buffer());
+  buffer->setDetachedBufferHandle(
+      DetachedBufferHandle::Create(client_.TakeChannelHandle()));
+  return buffer;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 1186f93..0ea77c8 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -16,6 +16,21 @@
 namespace android {
 namespace dvr {
 
+class BufferHubClient : public pdx::Client {
+ public:
+  BufferHubClient();
+  explicit BufferHubClient(pdx::LocalChannelHandle channel_handle);
+
+  bool IsValid() const;
+  pdx::LocalChannelHandle TakeChannelHandle();
+
+  using pdx::Client::Close;
+  using pdx::Client::GetChannel;
+  using pdx::Client::InvokeRemoteMethod;
+  using pdx::Client::IsConnected;
+  using pdx::Client::event_fd;
+};
+
 class BufferHubBuffer : public pdx::Client {
  public:
   using LocalHandle = pdx::LocalHandle;
@@ -94,6 +109,9 @@
 
   int id() const { return id_; }
 
+  // Returns the buffer buffer state.
+  uint64_t buffer_state() { return buffer_state_->load(); };
+
   // A state mask which is unique to a buffer hub client among all its siblings
   // sharing the same concrete graphic buffer.
   uint64_t buffer_state_bit() const { return buffer_state_bit_; }
@@ -108,10 +126,6 @@
   uint32_t usage() const { return buffer_.usage(); }
   uint32_t layer_count() const { return buffer_.layer_count(); }
 
-  // TODO(b/37881101) Clean up producer/consumer usage.
-  uint64_t producer_usage() const { return buffer_.usage(); }
-  uint64_t consumer_usage() const { return buffer_.usage(); }
-
   uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
   void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
 
@@ -218,18 +232,13 @@
   // succeeded, or a negative errno code if local error check fails.
   int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
 
-  // Attaches the producer to |name| so that it becomes a persistent buffer that
-  // may be retrieved by name at a later time. This may be used in cases where a
-  // shared memory buffer should persist across the life of the producer process
-  // (i.e. the buffer may be held by clients across a service restart). The
-  // buffer may be associated with a user and/or group id to restrict access to
-  // the buffer. If user_id or group_id is -1 then checks for the respective id
-  // are disabled. If user_id or group_id is 0 then the respective id of the
-  // calling process is used instead.
-  int MakePersistent(const std::string& name, int user_id, int group_id);
-
-  // Removes the persistence of the producer.
-  int RemovePersistence();
+  // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+  // be called when a producer buffer has exclusive access to the buffer (i.e.
+  // in the gain'ed state). On the successful return of the IPC call, a new
+  // LocalChannelHandle representing a detached buffer will be returned and all
+  // existing producer and consumer channels will be closed. Further IPCs
+  // towards those channels will return error.
+  Status<LocalChannelHandle> Detach();
 
  private:
   friend BASE;
@@ -240,44 +249,10 @@
 
   // Constructs a buffer with the given geometry and parameters.
   BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint32_t usage, size_t metadata_size = 0);
-  BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t producer_usage, uint64_t consumer_usage,
-                 size_t metadata_size);
-
-  // Constructs a persistent buffer with the given geometry and parameters and
-  // binds it to |name| in one shot. If a persistent buffer with the same name
-  // and settings already exists and matches the given geometry and parameters,
-  // that buffer is connected to this client instead of creating a new buffer.
-  // If the name matches but the geometry or settings do not match then
-  // construction fails and BufferProducer::Create() returns nullptr.
-  //
-  // Access to the persistent buffer may be restricted by |user_id| and/or
-  // |group_id|; these settings are established only when the buffer is first
-  // created and cannot be changed. A user or group id of -1 disables checks for
-  // that respective id. A user or group id of 0 is substituted with the
-  // effective user or group id of the calling process.
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t width, uint32_t height, uint32_t format,
-                 uint32_t usage, size_t metadata_size = 0);
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t producer_usage, uint64_t consumer_usage,
-                 size_t user_metadata_size);
+                 uint64_t usage, size_t metadata_size = 0);
 
   // Constructs a blob (flat) buffer with the given usage flags.
-  BufferProducer(uint32_t usage, size_t size);
-  BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, size_t size);
-
-  // Constructs a persistent blob (flat) buffer and binds it to |name|.
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t usage, size_t size);
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint64_t producer_usage, uint64_t consumer_usage, size_t size);
-
-  // Constructs a channel to persistent buffer by name only. The buffer must
-  // have been previously created or made persistent.
-  explicit BufferProducer(const std::string& name);
+  BufferProducer(uint64_t usage, size_t size);
 
   // Imports the given file handle to a producer channel, taking ownership.
   explicit BufferProducer(LocalChannelHandle channel);
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index f9fd42d..f4918c4 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -2,8 +2,8 @@
 #define ANDROID_DVR_BUFFERHUB_RPC_H_
 
 #include <cutils/native_handle.h>
-#include <gui/BufferQueueDefs.h>
 #include <sys/types.h>
+#include <ui/BufferQueueDefs.h>
 
 #include <dvr/dvr_api.h>
 #include <pdx/channel_handle.h>
@@ -366,23 +366,25 @@
   // Op codes.
   enum {
     kOpCreateBuffer = 0,
-    kOpCreatePersistentBuffer,
-    kOpGetPersistentBuffer,
     kOpGetBuffer,
     kOpNewConsumer,
-    kOpProducerMakePersistent,
-    kOpProducerRemovePersistence,
     kOpProducerPost,
     kOpProducerGain,
     kOpConsumerAcquire,
     kOpConsumerRelease,
     kOpConsumerSetIgnore,
+    kOpProducerBufferDetach,
+    kOpConsumerBufferDetach,
+    kOpDetachedBufferCreate,
+    kOpDetachedBufferPromote,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
     kOpProducerQueueAllocateBuffers,
     kOpProducerQueueRemoveBuffer,
     kOpConsumerQueueImportBuffers,
+    // TODO(b/77153033): Separate all those RPC operations into subclasses.
+    kOpDetachedBufferBase = 1000,
   };
 
   // Aliases.
@@ -394,19 +396,9 @@
   PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer,
                     void(uint32_t width, uint32_t height, uint32_t format,
                          uint64_t usage, size_t user_metadata_size));
-  PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer,
-                    void(const std::string& name, int user_id, int group_id,
-                         uint32_t width, uint32_t height, uint32_t format,
-                         uint64_t usage, size_t user_metadata_size));
-  PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer,
-                    void(const std::string& name));
   PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer,
                     BufferDescription<LocalHandle>(Void));
   PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void));
-  PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent,
-                    void(const std::string& name, int user_id, int group_id));
-  PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence,
-                    void(Void));
   PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost,
                     void(LocalFence acquire_fence));
   PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void));
@@ -414,6 +406,17 @@
   PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
                     void(LocalFence release_fence));
   PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
+  PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
+                    LocalChannelHandle(Void));
+
+  // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
+  // be called when the consumer is the only consumer and it has exclusive
+  // access to the buffer (i.e. in the acquired'ed state). On the successful
+  // return of the IPC call, a new DetachedBufferChannel handle will be returned
+  // and all existing producer and consumer channels will be closed. Further
+  // IPCs towards those channels will return error.
+  PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach,
+                    LocalChannelHandle(Void));
 
   // Buffer Queue Methods.
   PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
@@ -433,6 +436,25 @@
                     std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
 };
 
+struct DetachedBufferRPC final : public BufferHubRPC {
+ private:
+  enum {
+    kOpCreate = kOpDetachedBufferBase,
+    kOpImport,
+    kOpPromote,
+  };
+
+ public:
+  PDX_REMOTE_METHOD(Create, kOpCreate,
+                    void(uint32_t width, uint32_t height, uint32_t layer_count,
+                         uint32_t format, uint64_t usage,
+                         size_t user_metadata_size));
+  PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
+  PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+
+  PDX_REMOTE_API(API, Create, Promote);
+};
+
 }  // namespace dvr
 }  // namespace android
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
new file mode 100644
index 0000000..6d0b502
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -0,0 +1,82 @@
+#ifndef ANDROID_DVR_DETACHED_BUFFER_H_
+#define ANDROID_DVR_DETACHED_BUFFER_H_
+
+#include <private/dvr/buffer_hub_client.h>
+
+namespace android {
+namespace dvr {
+
+class DetachedBuffer {
+ public:
+  // Allocates a standalone DetachedBuffer not associated with any producer
+  // consumer set.
+  static std::unique_ptr<DetachedBuffer> Create(uint32_t width, uint32_t height,
+                                                uint32_t layer_count,
+                                                uint32_t format, uint64_t usage,
+                                                size_t user_metadata_size) {
+    return std::unique_ptr<DetachedBuffer>(new DetachedBuffer(
+        width, height, layer_count, format, usage, user_metadata_size));
+  }
+
+  // Imports the given channel handle to a DetachedBuffer, taking ownership.
+  static std::unique_ptr<DetachedBuffer> Import(
+      pdx::LocalChannelHandle channel_handle) {
+    return std::unique_ptr<DetachedBuffer>(
+        new DetachedBuffer(std::move(channel_handle)));
+  }
+
+  DetachedBuffer(const DetachedBuffer&) = delete;
+  void operator=(const DetachedBuffer&) = delete;
+
+  const sp<GraphicBuffer>& buffer() const { return buffer_.buffer(); }
+
+  int id() const { return id_; }
+
+  // Returns true if the buffer holds an open PDX channels towards bufferhubd.
+  bool IsConnected() const { return client_.IsValid(); }
+
+  // Returns true if the buffer holds an valid gralloc buffer handle that's
+  // availble for the client to read from and/or write into.
+  bool IsValid() const { return buffer_.IsValid(); }
+
+  // Returns the event mask for all the events that are pending on this buffer
+  // (see sys/poll.h for all possible bits).
+  pdx::Status<int> GetEventMask(int events) {
+    if (auto* channel = client_.GetChannel()) {
+      return channel->GetEventMask(events);
+    } else {
+      return pdx::ErrorStatus(EINVAL);
+    }
+  }
+
+  // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
+  int Poll(int timeout_ms);
+
+  // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
+  // DetachedBuffer channel will be closed automatically on successful IPC
+  // return. Further IPCs towards this channel will return error.
+  pdx::Status<pdx::LocalChannelHandle> Promote();
+
+  // Takes the underlying graphic buffer out of this DetachedBuffer. This call
+  // immediately invalidates this DetachedBuffer object and transfers the
+  // underlying pdx::LocalChannelHandle into the GraphicBuffer.
+  sp<GraphicBuffer> TakeGraphicBuffer();
+
+ private:
+  DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                 uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+  DetachedBuffer(pdx::LocalChannelHandle channel_handle);
+
+  int ImportGraphicBuffer();
+
+  // Global id for the buffer that is consistent across processes.
+  int id_;
+  IonBuffer buffer_;
+  BufferHubClient client_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_DETACHED_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index 0d337f7..f6bc547 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -23,6 +23,9 @@
   IonBuffer(IonBuffer&& other);
   IonBuffer& operator=(IonBuffer&& other);
 
+  // Returns check this IonBuffer holds a valid Gralloc buffer.
+  bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; }
+
   // Frees the underlying native handle and leaves the instance initialized to
   // empty.
   void FreeHandle();
@@ -66,6 +69,7 @@
               struct android_ycbcr* yuv);
   int Unlock();
 
+  sp<GraphicBuffer>& buffer() { return buffer_; }
   const sp<GraphicBuffer>& buffer() const { return buffer_; }
   buffer_handle_t handle() const {
     return buffer_.get() ? buffer_->handle : nullptr;
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
deleted file mode 100644
index 140ffc5..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-#ifndef ANDROID_DVR_NATIVE_BUFFER_H_
-#define ANDROID_DVR_NATIVE_BUFFER_H_
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <log/log.h>
-#include <ui/ANativeObjectBase.h>
-#include <utils/RefBase.h>
-#include <nativebase/nativebase.h>
-
-#include <private/dvr/buffer_hub_client.h>
-
-namespace android {
-namespace dvr {
-
-// ANativeWindowBuffer is the abstraction Android HALs and frameworks use to
-// pass around hardware graphics buffers. The following classes implement this
-// abstraction with different DVR backing buffers, all of which provide
-// different semantics on top of ion/gralloc buffers.
-
-// An implementation of ANativeWindowBuffer backed by an IonBuffer.
-class NativeBuffer
-    : public android::ANativeObjectBase<ANativeWindowBuffer, NativeBuffer,
-                                        android::LightRefBase<NativeBuffer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBuffer(const std::shared_ptr<IonBuffer>& buffer)
-      : BASE(), buffer_(buffer), fence_(kEmptyFence) {
-    ANativeWindowBuffer::width = buffer->width();
-    ANativeWindowBuffer::height = buffer->height();
-    ANativeWindowBuffer::stride = buffer->stride();
-    ANativeWindowBuffer::format = buffer->format();
-    ANativeWindowBuffer::usage = buffer->usage();
-    handle = buffer_->handle();
-  }
-
-  virtual ~NativeBuffer() {}
-
-  std::shared_ptr<IonBuffer> buffer() { return buffer_; }
-  int fence() const { return fence_.Get(); }
-
-  void SetFence(int fence) { fence_.Reset(fence); }
-
- private:
-  friend class android::LightRefBase<NativeBuffer>;
-
-  std::shared_ptr<IonBuffer> buffer_;
-  pdx::LocalHandle fence_;
-
-  NativeBuffer(const NativeBuffer&) = delete;
-  void operator=(NativeBuffer&) = delete;
-};
-
-class NativeBufferProducer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferProducer,
-                                 android::LightRefBase<NativeBufferProducer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer,
-                       EGLDisplay display, uint32_t surface_buffer_index)
-      : BASE(),
-        buffer_(buffer),
-        surface_buffer_index_(surface_buffer_index),
-        display_(display) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    ANativeWindowBuffer::handle = buffer_->native_handle();
-    if (display_) {
-      image_khr_ =
-          eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                            static_cast<ANativeWindowBuffer*>(this), nullptr);
-    } else {
-      image_khr_ = EGL_NO_IMAGE_KHR;
-    }
-  }
-
-  explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
-      : NativeBufferProducer(buffer, nullptr, 0) {}
-
-  virtual ~NativeBufferProducer() {
-    if (image_khr_ != EGL_NO_IMAGE_KHR)
-      eglDestroyImageKHR(display_, image_khr_);
-  }
-
-  EGLImageKHR image_khr() const { return image_khr_; }
-  std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
-  int release_fence() const { return release_fence_.Get(); }
-  uint32_t surface_buffer_index() const { return surface_buffer_index_; }
-
-  // Return the release fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimReleaseFence() { return std::move(release_fence_); }
-
-  // Post the buffer consumer, closing the acquire and release fences.
-  int Post(int acquire_fence, uint64_t sequence) {
-    release_fence_.Close();
-    return buffer_->Post(pdx::LocalHandle(acquire_fence), sequence);
-  }
-
-  // Gain the buffer producer, closing the previous release fence if valid.
-  int Gain() { return buffer_->Gain(&release_fence_); }
-
-  // Asynchronously gain the buffer, closing the previous release fence.
-  int GainAsync() {
-    release_fence_.Close();
-    return buffer_->GainAsync();
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferProducer>;
-
-  std::shared_ptr<BufferProducer> buffer_;
-  pdx::LocalHandle release_fence_;
-  EGLImageKHR image_khr_;
-  uint32_t surface_buffer_index_;
-  EGLDisplay display_;
-
-  NativeBufferProducer(const NativeBufferProducer&) = delete;
-  void operator=(NativeBufferProducer&) = delete;
-};
-
-// NativeBufferConsumer is an implementation of ANativeWindowBuffer backed by a
-// BufferConsumer.
-class NativeBufferConsumer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferConsumer,
-                                 android::LightRefBase<NativeBufferConsumer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBufferConsumer(const std::shared_ptr<BufferConsumer>& buffer)
-      : BASE(), buffer_(buffer), acquire_fence_(kEmptyFence), sequence_(0) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    handle = buffer_->native_handle();
-  }
-
-  virtual ~NativeBufferConsumer() {}
-
-  std::shared_ptr<BufferConsumer> buffer() const { return buffer_; }
-  int acquire_fence() const { return acquire_fence_.Get(); }
-  uint64_t sequence() const { return sequence_; }
-
-  // Return the acquire fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimAcquireFence() { return std::move(acquire_fence_); }
-
-  // Acquire the underlying buffer consumer, closing the previous acquire fence
-  // if valid.
-  int Acquire() { return buffer_->Acquire(&acquire_fence_, &sequence_); }
-
-  // Release the buffer consumer, closing the acquire and release fences if
-  // valid.
-  int Release(int release_fence) {
-    acquire_fence_.Close();
-    sequence_ = 0;
-    return buffer_->Release(pdx::LocalHandle(release_fence));
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferConsumer>;
-
-  std::shared_ptr<BufferConsumer> buffer_;
-  pdx::LocalHandle acquire_fence_;
-  uint64_t sequence_;
-
-  NativeBufferConsumer(const NativeBufferConsumer&) = delete;
-  void operator=(NativeBufferConsumer&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_NATIVE_BUFFER_H_
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 93ccd0f..9f72c05 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -14,7 +14,7 @@
 
 sourceFiles = [
     "buffer_hub_queue_client.cpp",
-    "buffer_hub_queue_producer.cpp",
+    "buffer_hub_queue_parcelable.cpp",
 ]
 
 includeFiles = [
@@ -23,8 +23,6 @@
 
 staticLibraries = [
     "libbufferhub",
-    "libdvrcommon",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
@@ -35,7 +33,7 @@
     "liblog",
     "libui",
     "libutils",
-    "libgui",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -43,12 +41,17 @@
     "libnativebase_headers",
 ]
 
-cc_library {
+cc_library_shared {
     name: "libbufferhubqueue",
     cflags: [
         "-DLOG_TAG=\"libbufferhubqueue\"",
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+        "-Wall",
+        "-Werror",
+        "-Wno-format",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
     ],
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
@@ -58,4 +61,4 @@
     header_libs: headerLibraries,
 }
 
-subdirs = ["tests"]
+subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
new file mode 100644
index 0000000..8ae7a0b
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -0,0 +1,27 @@
+
+cc_benchmark {
+    srcs: ["buffer_transport_benchmark.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libdvr",
+        "libgui",
+        "liblog",
+        "libhardware",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "libbufferhubqueue",
+        "libpdx_default_transport",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"buffer_transport_benchmark\"",
+        "-DTRACE=0",
+        "-O2",
+        "-Wall",
+        "-Werror",
+    ],
+    name: "buffer_transport_benchmark",
+    tags: ["optional"],
+}
diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
new file mode 100644
index 0000000..4ca8671
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
@@ -0,0 +1,589 @@
+#include <android-base/logging.h>
+#include <android/native_window.h>
+#include <benchmark/benchmark.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <dvr/dvr_api.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+#include <private/dvr/epoll_file_descriptor.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <functional>
+#include <iostream>
+#include <thread>
+#include <vector>
+
+#include <dlfcn.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+
+// Use ALWAYS at the tag level. Control is performed manually during command
+// line processing.
+#ifdef ATRACE_TAG
+#undef ATRACE_TAG
+#endif
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+
+using namespace android;
+using ::benchmark::State;
+
+static const String16 kBinderService = String16("bufferTransport");
+static const uint32_t kBufferWidth = 100;
+static const uint32_t kBufferHeight = 1;
+static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static const uint64_t kBufferUsage =
+    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+static const uint32_t kBufferLayer = 1;
+static const int kMaxAcquiredImages = 1;
+static const int kQueueDepth = 2;  // We are double buffering for this test.
+static const size_t kMaxQueueCounts = 128;
+static const int kInvalidFence = -1;
+
+enum BufferTransportServiceCode {
+  CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+// A binder services that minics a compositor that consumes buffers. It provides
+// one Binder interface to create a new Surface for buffer producer to write
+// into; while itself will carry out no-op buffer consuming by acquiring then
+// releasing the buffer immediately.
+class BufferTransportService : public BBinder {
+ public:
+  BufferTransportService() = default;
+  ~BufferTransportService() = default;
+
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0) {
+    (void)flags;
+    (void)data;
+    switch (code) {
+      case CREATE_BUFFER_QUEUE: {
+        auto new_queue = std::make_shared<BufferQueueHolder>(this);
+        reply->writeStrongBinder(
+            IGraphicBufferProducer::asBinder(new_queue->producer));
+        buffer_queues_.push_back(new_queue);
+        return NO_ERROR;
+      }
+      default:
+        return UNKNOWN_TRANSACTION;
+    };
+  }
+
+ private:
+  struct FrameListener : public ConsumerBase::FrameAvailableListener {
+   public:
+    FrameListener(BufferTransportService* /*service*/,
+                  sp<BufferItemConsumer> buffer_item_consumer)
+        : buffer_item_consumer_(buffer_item_consumer) {}
+
+    void onFrameAvailable(const BufferItem& /*item*/) override {
+      BufferItem buffer;
+      status_t ret = 0;
+      {
+        ATRACE_NAME("AcquireBuffer");
+        ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0,
+                                                   /*waitForFence=*/false);
+      }
+
+      if (ret != NO_ERROR) {
+        LOG(ERROR) << "Failed to acquire next buffer.";
+        return;
+      }
+
+      {
+        ATRACE_NAME("ReleaseBuffer");
+        ret = buffer_item_consumer_->releaseBuffer(buffer);
+      }
+
+      if (ret != NO_ERROR) {
+        LOG(ERROR) << "Failed to release buffer.";
+        return;
+      }
+    }
+
+   private:
+    sp<BufferItemConsumer> buffer_item_consumer_;
+  };
+
+  struct BufferQueueHolder {
+    explicit BufferQueueHolder(BufferTransportService* service) {
+      BufferQueue::createBufferQueue(&producer, &consumer);
+
+      sp<BufferItemConsumer> buffer_item_consumer =
+          new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
+                                 /*controlledByApp=*/true);
+      buffer_item_consumer->setName(String8("BinderBufferTransport"));
+      frame_listener_ = new FrameListener(service, buffer_item_consumer);
+      buffer_item_consumer->setFrameAvailableListener(frame_listener_);
+    }
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+   private:
+    sp<FrameListener> frame_listener_;
+  };
+
+  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+// A virtual interfaces that abstracts the common BufferQueue operations, so
+// that the test suite can use the same test case to drive different types of
+// transport backends.
+class BufferTransport {
+ public:
+  virtual ~BufferTransport() {}
+
+  virtual int Start() = 0;
+  virtual sp<Surface> CreateSurface() = 0;
+};
+
+// Binder-based buffer transport backend.
+//
+// On Start() a new process will be swapned to run a Binder server that
+// actually consumes the buffer.
+// On CreateSurface() a new Binder BufferQueue will be created, which the
+// service holds the concrete binder node of the IGraphicBufferProducer while
+// sending the binder proxy to the client. In another word, the producer side
+// operations are carried out process while the consumer side operations are
+// carried out within the BufferTransportService's own process.
+class BinderBufferTransport : public BufferTransport {
+ public:
+  BinderBufferTransport() {}
+
+  int Start() override {
+    sp<IServiceManager> sm = defaultServiceManager();
+    service_ = sm->getService(kBinderService);
+    if (service_ == nullptr) {
+      LOG(ERROR) << "Failed to get the benchmark service.";
+      return -EIO;
+    }
+
+    LOG(INFO) << "Binder server is ready for client.";
+    return 0;
+  }
+
+  sp<Surface> CreateSurface() override {
+    Parcel data;
+    Parcel reply;
+    int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
+    if (error != NO_ERROR) {
+      LOG(ERROR) << "Failed to get buffer queue over binder.";
+      return nullptr;
+    }
+
+    sp<IBinder> binder;
+    error = reply.readNullableStrongBinder(&binder);
+    if (error != NO_ERROR) {
+      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+      return nullptr;
+    }
+
+    auto producer = interface_cast<IGraphicBufferProducer>(binder);
+    if (producer == nullptr) {
+      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+      return nullptr;
+    }
+
+    sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true);
+
+    // Set buffer dimension.
+    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
+    ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
+                                     kBufferFormat);
+
+    return surface;
+  }
+
+ private:
+  sp<IBinder> service_;
+};
+
+class DvrApi {
+ public:
+  DvrApi() {
+    handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+    CHECK(handle_);
+
+    auto dvr_get_api =
+        reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
+    int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
+
+    CHECK(ret == 0);
+  }
+
+  ~DvrApi() { dlclose(handle_); }
+
+  const DvrApi_v1& Api() { return api_; }
+
+ private:
+  void* handle_ = nullptr;
+  DvrApi_v1 api_;
+};
+
+// BufferHub/PDX-based buffer transport.
+//
+// On Start() a new thread will be swapned to run an epoll polling thread which
+// minics the behavior of a compositor. Similar to Binder-based backend, the
+// buffer available handler is also a no-op: Buffer gets acquired and released
+// immediately.
+// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will
+// be created. The epoll thread holds on the consumer queue and dequeues buffer
+// from it; while the producer queue will be wrapped in a Surface and returned
+// to test suite.
+class BufferHubTransport : public BufferTransport {
+ public:
+  virtual ~BufferHubTransport() {
+    stopped_.store(true);
+    if (reader_thread_.joinable()) {
+      reader_thread_.join();
+    }
+  }
+
+  int Start() override {
+    int ret = epoll_fd_.Create();
+    if (ret < 0) {
+      LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret);
+      return -1;
+    }
+
+    // Create the reader thread.
+    reader_thread_ = std::thread([this]() {
+      int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
+        return;
+      }
+
+      stopped_.store(false);
+      LOG(INFO) << "Reader Thread Running...";
+
+      while (!stopped_.load()) {
+        std::array<epoll_event, kMaxQueueCounts> events;
+
+        // Don't sleep forever so that we will have a chance to wake up.
+        const int ret = epoll_fd_.Wait(events.data(), events.size(),
+                                       /*timeout=*/100);
+        if (ret < 0) {
+          LOG(ERROR) << "Error polling consumer queues.";
+          continue;
+        }
+        if (ret == 0) {
+          continue;
+        }
+
+        const int num_events = ret;
+        for (int i = 0; i < num_events; i++) {
+          uint32_t index = events[i].data.u32;
+          dvr_.Api().ReadBufferQueueHandleEvents(
+              buffer_queues_[index]->GetReadQueue());
+        }
+      }
+
+      LOG(INFO) << "Reader Thread Exiting...";
+    });
+
+    return 0;
+  }
+
+  sp<Surface> CreateSurface() override {
+    auto new_queue = std::make_shared<BufferQueueHolder>();
+    if (!new_queue->IsReady()) {
+      LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
+      return nullptr;
+    }
+
+    // Set buffer dimension.
+    ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
+                                     kBufferHeight, kBufferFormat);
+
+    // Use the next position as buffer_queue index.
+    uint32_t index = buffer_queues_.size();
+    epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
+    int queue_fd =
+        dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
+    const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
+    if (ret < 0) {
+      LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
+                 << ", consumer queue fd: " << queue_fd;
+      return nullptr;
+    }
+
+    buffer_queues_.push_back(new_queue);
+    ANativeWindow_acquire(new_queue->GetSurface());
+    return static_cast<Surface*>(new_queue->GetSurface());
+  }
+
+ private:
+  struct BufferQueueHolder {
+    BufferQueueHolder() {
+      int ret = 0;
+      ret = dvr_.Api().WriteBufferQueueCreate(
+          kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
+          kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
+        return;
+      }
+
+      ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
+                                                       &read_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
+        return;
+      }
+
+      ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
+          read_queue_, BufferAvailableCallback, this);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
+        return;
+      }
+
+      ret =
+          dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create surface, ret=" << ret;
+        return;
+      }
+    }
+
+    static void BufferAvailableCallback(void* context) {
+      BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
+      thiz->HandleBufferAvailable();
+    }
+
+    DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
+
+    ANativeWindow* GetSurface() { return surface_; }
+
+    bool IsReady() {
+      return write_queue_ != nullptr && read_queue_ != nullptr &&
+             surface_ != nullptr;
+    }
+
+    void HandleBufferAvailable() {
+      int ret = 0;
+      DvrNativeBufferMetadata meta;
+      DvrReadBuffer* buffer = nullptr;
+      DvrNativeBufferMetadata metadata;
+      int acquire_fence = kInvalidFence;
+
+      {
+        ATRACE_NAME("AcquireBuffer");
+        ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
+            read_queue_, 0, &buffer, &metadata, &acquire_fence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
+        return;
+      }
+
+      if (buffer != nullptr) {
+        ATRACE_NAME("ReleaseBuffer");
+        ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
+                                                      &meta, kInvalidFence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
+      }
+    }
+
+   private:
+    DvrWriteBufferQueue* write_queue_ = nullptr;
+    DvrReadBufferQueue* read_queue_ = nullptr;
+    ANativeWindow* surface_ = nullptr;
+  };
+
+  static DvrApi dvr_;
+  std::atomic<bool> stopped_;
+  std::thread reader_thread_;
+
+  dvr::EpollFileDescriptor epoll_fd_;
+  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+DvrApi BufferHubTransport::dvr_ = {};
+
+enum TransportType {
+  kBinderBufferTransport,
+  kBufferHubTransport,
+};
+
+// Main test suite, which supports two transport backend: 1) BinderBufferQueue,
+// 2) BufferHubQueue. The test case drives the producer end of both transport
+// backend by queuing buffers into the buffer queue by using ANativeWindow API.
+class BufferTransportBenchmark : public ::benchmark::Fixture {
+ public:
+  void SetUp(State& state) override {
+    if (state.thread_index == 0) {
+      const int transport = state.range(0);
+      switch (transport) {
+        case kBinderBufferTransport:
+          transport_.reset(new BinderBufferTransport);
+          break;
+        case kBufferHubTransport:
+          transport_.reset(new BufferHubTransport);
+          break;
+        default:
+          CHECK(false) << "Unknown test case.";
+          break;
+      }
+
+      CHECK(transport_);
+      const int ret = transport_->Start();
+      CHECK_EQ(ret, 0);
+
+      LOG(INFO) << "Transport backend running, transport=" << transport << ".";
+
+      // Create surfaces for each thread.
+      surfaces_.resize(state.threads);
+      for (int i = 0; i < state.threads; i++) {
+        // Common setup every thread needs.
+        surfaces_[i] = transport_->CreateSurface();
+        CHECK(surfaces_[i]);
+
+        LOG(INFO) << "Surface initialized on thread " << i << ".";
+      }
+    }
+  }
+
+  void TearDown(State& state) override {
+    if (state.thread_index == 0) {
+      surfaces_.clear();
+      transport_.reset();
+      LOG(INFO) << "Tear down benchmark.";
+    }
+  }
+
+ protected:
+  std::unique_ptr<BufferTransport> transport_;
+  std::vector<sp<Surface>> surfaces_;
+};
+
+BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
+  ANativeWindow* window = nullptr;
+  ANativeWindow_Buffer buffer;
+  int32_t error = 0;
+  double total_gain_buffer_us = 0;
+  double total_post_buffer_us = 0;
+  int iterations = 0;
+
+  while (state.KeepRunning()) {
+    if (window == nullptr) {
+      CHECK(surfaces_[state.thread_index]);
+      window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
+
+      // Lock buffers a couple time from the queue, so that we have the buffer
+      // allocated.
+      for (int i = 0; i < kQueueDepth; i++) {
+        error = ANativeWindow_lock(window, &buffer,
+                                   /*inOutDirtyBounds=*/nullptr);
+        CHECK_EQ(error, 0);
+        error = ANativeWindow_unlockAndPost(window);
+        CHECK_EQ(error, 0);
+      }
+    }
+
+    {
+      ATRACE_NAME("GainBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_lock(window, &buffer,
+                                 /*inOutDirtyBounds=*/nullptr);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_gain_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    {
+      ATRACE_NAME("PostBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_unlockAndPost(window);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_post_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    iterations++;
+  }
+
+  state.counters["gain_buffer_us"] = ::benchmark::Counter(
+      total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["post_buffer_us"] = ::benchmark::Counter(
+      total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["producer_us"] = ::benchmark::Counter(
+      (total_gain_buffer_us + total_post_buffer_us) / iterations,
+      ::benchmark::Counter::kAvgThreads);
+}
+
+BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
+    ->Unit(::benchmark::kMicrosecond)
+    ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
+    ->ThreadRange(1, 32);
+
+static void runBinderServer() {
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  ProcessState::self()->startThreadPool();
+
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<BufferTransportService> service = new BufferTransportService;
+  sm->addService(kBinderService, service, false);
+
+  LOG(INFO) << "Binder server running...";
+
+  while (true) {
+    int stat, retval;
+    retval = wait(&stat);
+    if (retval == -1 && errno == ECHILD) {
+      break;
+    }
+  }
+
+  LOG(INFO) << "Service Exiting...";
+}
+
+// To run binder-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
+//
+// To run bufferhub-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
+int main(int argc, char** argv) {
+  bool tracing_enabled = false;
+
+  // Parse arguments in addition to "--benchmark_filter" paramters.
+  for (int i = 1; i < argc; i++) {
+    if (std::string(argv[i]) == "--help") {
+      std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
+      std::cout << "\t--trace: Enable systrace logging." << std::endl;
+      return 0;
+    }
+    if (std::string(argv[i]) == "--trace") {
+      tracing_enabled = true;
+      continue;
+    }
+  }
+
+  // Setup ATRACE/systrace based on command line.
+  atrace_setup();
+  atrace_set_tracing_enabled(tracing_enabled);
+
+  pid_t pid = fork();
+  if (pid == 0) {
+    // Child, i.e. the client side.
+    ProcessState::self()->startThreadPool();
+
+    ::benchmark::Initialize(&argc, argv);
+    ::benchmark::RunSpecifiedBenchmarks();
+  } else {
+    LOG(INFO) << "Benchmark process pid: " << pid;
+    runBinderServer();
+  }
+}
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 8bea0cd..8feb1cd 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -31,20 +31,6 @@
 
 namespace {
 
-// Polls an fd for the given events.
-Status<int> PollEvents(int fd, short events) {
-  const int kTimeoutMs = 0;
-  pollfd pfd{fd, events, 0};
-  const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
-  if (count < 0) {
-    return ErrorStatus(errno);
-  } else if (count == 0) {
-    return ErrorStatus(ETIMEDOUT);
-  } else {
-    return {pfd.revents};
-  }
-}
-
 std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
   return {static_cast<int32_t>(value >> 32),
           static_cast<int32_t>(value & ((1ull << 32) - 1))};
@@ -137,6 +123,28 @@
   return status;
 }
 
+pdx::Status<ConsumerQueueParcelable>
+BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
+  auto status = CreateConsumerQueueHandle(silent);
+  if (!status)
+    return status.error_status();
+
+  // A temporary consumer queue client to pull its channel parcelable.
+  auto consumer_queue =
+      std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
+  ConsumerQueueParcelable queue_parcelable(
+      consumer_queue->GetChannel()->TakeChannelParcelable());
+
+  if (!queue_parcelable.IsValid()) {
+    ALOGE(
+        "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
+        "consumer queue parcelable.");
+    return ErrorStatus(EINVAL);
+  }
+
+  return {std::move(queue_parcelable)};
+}
+
 bool BufferHubQueue::WaitForBuffers(int timeout) {
   ATRACE_NAME("BufferHubQueue::WaitForBuffers");
   std::array<epoll_event, kMaxEvents> events;
@@ -555,6 +563,31 @@
   return {std::move(buffer)};
 }
 
+pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
+  if (capacity() != 0) {
+    ALOGE(
+        "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
+        " as a parcelable when empty. Current queue capacity: %zu",
+        capacity());
+    return ErrorStatus(EINVAL);
+  }
+
+  std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
+  ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
+
+  // Here the queue parcelable is returned and holds the underlying system
+  // resources backing the queue; while the original client channel of this
+  // producer queue is destroyed in place so that this client can no longer
+  // provide producer operations.
+  return {std::move(queue_parcelable)};
+}
+
+/*static */
+std::unique_ptr<ConsumerQueue> ConsumerQueue::Import(
+    LocalChannelHandle handle) {
+  return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
+}
+
 ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
     : BufferHubQueue(std::move(handle)) {
   auto status = ImportQueue();
@@ -629,27 +662,7 @@
     const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
   ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
            id(), buffer->id(), slot);
-  auto status = BufferHubQueue::AddBuffer(buffer, slot);
-  if (!status)
-    return status;
-
-  // Check to see if the buffer is already signaled. This is necessary to catch
-  // cases where buffers are already available; epoll edge triggered mode does
-  // not fire until an edge transition when adding new buffers to the epoll
-  // set. Note that we only poll the fd events because HandleBufferEvent() takes
-  // care of checking the translated buffer events.
-  auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
-  if (!poll_status && poll_status.error() != ETIMEDOUT) {
-    ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s",
-          poll_status.GetErrorMessage().c_str());
-    return poll_status.error_status();
-  }
-
-  // Update accounting if the buffer is available.
-  if (poll_status)
-    return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get());
-  else
-    return {};
+  return BufferHubQueue::AddBuffer(buffer, slot);
 }
 
 Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
new file mode 100644
index 0000000..2cd7c45
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
@@ -0,0 +1,82 @@
+#include "include/private/dvr/buffer_hub_queue_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <pdx/default_transport/channel_parcelable.h>
+
+namespace android {
+namespace dvr {
+
+template <BufferHubQueueParcelableMagic Magic>
+bool BufferHubQueueParcelable<Magic>::IsValid() const {
+  return !!channel_parcelable_ && channel_parcelable_->IsValid();
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() {
+  if (!IsValid()) {
+    ALOGE(
+        "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel.");
+    return {};  // Returns an empty channel handle.
+  }
+
+  // Take channel handle out of the parcelable and reset the parcelable.
+  pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle();
+  // Now channel_parcelable_ should already be invalid, but reset it to release
+  // the invalid parcelable object from unique_ptr.
+  channel_parcelable_ = nullptr;
+  return handle;
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const {
+  if (!IsValid()) {
+    ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel.");
+    return -EINVAL;
+  }
+
+  status_t res = parcel->writeUint32(Magic);
+  if (res != NO_ERROR) {
+    ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic.");
+    return res;
+  }
+
+  return channel_parcelable_->writeToParcel(parcel);
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) {
+  if (IsValid()) {
+    ALOGE(
+        "BufferHubQueueParcelable::readFromParcel: This parcelable object has "
+        "been initialized already.");
+    return -EINVAL;
+  }
+
+  uint32_t out_magic = 0;
+  status_t res = NO_ERROR;
+
+  res = parcel->readUint32(&out_magic);
+  if (res != NO_ERROR)
+    return res;
+
+  if (out_magic != Magic) {
+    ALOGE(
+        "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, "
+        "epxected: 0x%x",
+        out_magic, Magic);
+    return -EINVAL;
+  }
+
+  // (Re)Alocate channel parcelable object.
+  channel_parcelable_ =
+      std::make_unique<pdx::default_transport::ChannelParcelable>();
+  return channel_parcelable_->readFromParcel(parcel);
+}
+
+template class BufferHubQueueParcelable<
+    BufferHubQueueParcelableMagic::Producer>;
+template class BufferHubQueueParcelable<
+    BufferHubQueueParcelableMagic::Consumer>;
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
deleted file mode 100644
index 221bc4f..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_producer.h"
-
-#include <dvr/dvr_api.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <system/window.h>
-
-namespace android {
-namespace dvr {
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  auto config = ProducerQueueConfigBuilder()
-                    .SetMetadata<DvrNativeBufferMetadata>()
-                    .Build();
-  producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
-  return producer;
-}
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
-    const std::shared_ptr<ProducerQueue>& queue) {
-  if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
-    ALOGE(
-        "BufferHubQueueProducer::Create producer's metadata size is different "
-        "than the size of DvrNativeBufferMetadata");
-    return nullptr;
-  }
-
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  producer->queue_ = queue;
-  return producer;
-}
-
-status_t BufferHubQueueProducer::requestBuffer(int slot,
-                                               sp<GraphicBuffer>* buf) {
-  ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if (buffers_[slot].mGraphicBuffer != nullptr) {
-    ALOGE("requestBuffer: slot %d is not empty.", slot);
-    return BAD_VALUE;
-  } else if (buffers_[slot].mBufferProducer == nullptr) {
-    ALOGE("requestBuffer: slot %d is not dequeued.", slot);
-    return BAD_VALUE;
-  }
-
-  const auto& buffer_producer = buffers_[slot].mBufferProducer;
-  sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
-
-  buffers_[slot].mGraphicBuffer = graphic_buffer;
-  buffers_[slot].mRequestBufferCalled = true;
-
-  *buf = graphic_buffer;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
-    int max_dequeued_buffers) {
-  ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
-           max_dequeued_buffers);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (max_dequeued_buffers <= 0 ||
-      max_dequeued_buffers >
-          static_cast<int>(BufferHubQueue::kMaxQueueCapacity -
-                           kDefaultUndequeuedBuffers)) {
-    ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]",
-          max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity);
-    return BAD_VALUE;
-  }
-
-  // The new dequeued_buffers count should not be violated by the number
-  // of currently dequeued buffers.
-  int dequeued_count = 0;
-  for (const auto& buf : buffers_) {
-    if (buf.mBufferState.isDequeued()) {
-      dequeued_count++;
-    }
-  }
-  if (dequeued_count > max_dequeued_buffers) {
-    ALOGE(
-        "setMaxDequeuedBufferCount: the requested dequeued_buffers"
-        "count (%d) exceeds the current dequeued buffer count (%d)",
-        max_dequeued_buffers, dequeued_count);
-    return BAD_VALUE;
-  }
-
-  max_dequeued_buffer_count_ = max_dequeued_buffers;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAsyncMode(bool async) {
-  if (async) {
-    // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
-    // automatically and behaves differently from IGraphicBufferConsumer. Thus,
-    // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
-    // to prevent dequeueBuffer from being blocking) technically does not apply
-    // here.
-    //
-    // In Daydream, non-blocking producer side dequeue is guaranteed by careful
-    // buffer consumer implementations. In another word, BufferHubQueue based
-    // dequeueBuffer should never block whether setAsyncMode(true) is set or
-    // not.
-    //
-    // See: IGraphicBufferProducer::setAsyncMode and
-    // BufferQueueProducer::setAsyncMode for more about original implementation.
-    ALOGW(
-        "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be "
-        "asynchronous. This call makes no effact.");
-    return NO_ERROR;
-  }
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::dequeueBuffer(
-    int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
-    PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/,
-    FrameEventHistoryDelta* /* out_timestamps */) {
-  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width,
-           height, format, usage);
-
-  status_t ret;
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("dequeueBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  const uint32_t kLayerCount = 1;
-  if (static_cast<int32_t>(queue_->capacity()) <
-      max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
-    // Lazy allocation. When the capacity of |queue_| has not reached
-    // |max_dequeued_buffer_count_|, allocate new buffer.
-    // TODO(jwcai) To save memory, the really reasonable thing to do is to go
-    // over existing slots and find first existing one to dequeue.
-    ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-    if (ret < 0)
-      return ret;
-  }
-
-  size_t slot;
-  std::shared_ptr<BufferProducer> buffer_producer;
-
-  for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
-    LocalHandle fence;
-    auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
-    if (!buffer_status)
-      return NO_MEMORY;
-
-    buffer_producer = buffer_status.take();
-    if (!buffer_producer)
-      return NO_MEMORY;
-
-    if (width == buffer_producer->width() &&
-        height == buffer_producer->height() &&
-        static_cast<uint32_t>(format) == buffer_producer->format()) {
-      // The producer queue returns a buffer producer matches the request.
-      break;
-    }
-
-    // Needs reallocation.
-    // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
-    ALOGI(
-        "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
-        "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
-        "re-allocattion.",
-        width, height, format, slot, buffer_producer->width(),
-        buffer_producer->height(), buffer_producer->format());
-    // Mark the slot as reallocating, so that later we can set
-    // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
-    buffers_[slot].mIsReallocating = true;
-
-    // Remove the old buffer once the allocation before allocating its
-    // replacement.
-    RemoveBuffer(slot);
-
-    // Allocate a new producer buffer with new buffer configs. Note that if
-    // there are already multiple buffers in the queue, the next one returned
-    // from |queue_->Dequeue| may not be the new buffer we just reallocated.
-    // Retry up to BufferHubQueue::kMaxQueueCapacity times.
-    ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-    if (ret < 0)
-      return ret;
-  }
-
-  // With the BufferHub backed solution. Buffer slot returned from
-  // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
-  // It's either in free state (if the buffer has never been used before) or
-  // in queued state (if the buffer has been dequeued and queued back to
-  // BufferHubQueue).
-  LOG_ALWAYS_FATAL_IF(
-      (!buffers_[slot].mBufferState.isFree() &&
-       !buffers_[slot].mBufferState.isQueued()),
-      "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
-      buffers_[slot].mBufferState.string());
-
-  buffers_[slot].mBufferState.freeQueued();
-  buffers_[slot].mBufferState.dequeue();
-  ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot);
-
-  // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
-  // just need to exopose that through |BufferHubQueue| once we need fence.
-  *out_fence = Fence::NO_FENCE;
-  *out_slot = slot;
-  ret = NO_ERROR;
-
-  if (buffers_[slot].mIsReallocating) {
-    ret |= BUFFER_NEEDS_REALLOCATION;
-    buffers_[slot].mIsReallocating = false;
-  }
-
-  return ret;
-}
-
-status_t BufferHubQueueProducer::detachBuffer(int /* slot */) {
-  ALOGE("BufferHubQueueProducer::detachBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::detachNextBuffer(
-    sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */) {
-  ALOGE("BufferHubQueueProducer::detachNextBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::attachBuffer(
-    int* /* out_slot */, const sp<GraphicBuffer>& /* buffer */) {
-  // With this BufferHub backed implementation, we assume (for now) all buffers
-  // are allocated and owned by the BufferHub. Thus the attempt of transfering
-  // ownership of a buffer to the buffer queue is intentionally unsupported.
-  LOG_ALWAYS_FATAL("BufferHubQueueProducer::attachBuffer not supported.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::queueBuffer(int slot,
-                                             const QueueBufferInput& input,
-                                             QueueBufferOutput* output) {
-  ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
-
-  if (output == nullptr) {
-    return BAD_VALUE;
-  }
-
-  int64_t timestamp;
-  bool is_auto_timestamp;
-  android_dataspace dataspace;
-  Rect crop(Rect::EMPTY_RECT);
-  int scaling_mode;
-  uint32_t transform;
-  sp<Fence> fence;
-
-  input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop,
-                &scaling_mode, &transform, &fence);
-
-  // Check input scaling mode is valid.
-  switch (scaling_mode) {
-    case NATIVE_WINDOW_SCALING_MODE_FREEZE:
-    case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
-    case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
-    case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
-      break;
-    default:
-      ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
-      return BAD_VALUE;
-  }
-
-  // Check input fence is valid.
-  if (fence == nullptr) {
-    ALOGE("queueBuffer: fence is NULL");
-    return BAD_VALUE;
-  }
-
-  status_t ret;
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("queueBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if ((!buffers_[slot].mRequestBufferCalled ||
-              buffers_[slot].mGraphicBuffer == nullptr)) {
-    ALOGE(
-        "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
-        "mGraphicBuffer=%p)",
-        slot, buffers_[slot].mRequestBufferCalled,
-        buffers_[slot].mGraphicBuffer.get());
-    return BAD_VALUE;
-  }
-
-  // Post the buffer producer with timestamp in the metadata.
-  const auto& buffer_producer = buffers_[slot].mBufferProducer;
-
-  // Check input crop is not out of boundary of current buffer.
-  Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
-  Rect cropped_rect(Rect::EMPTY_RECT);
-  crop.intersect(buffer_rect, &cropped_rect);
-  if (cropped_rect != crop) {
-    ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
-    return BAD_VALUE;
-  }
-
-  LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
-
-  DvrNativeBufferMetadata meta_data;
-  meta_data.timestamp = timestamp;
-  meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
-  meta_data.dataspace = static_cast<int32_t>(dataspace);
-  meta_data.crop_left = crop.left;
-  meta_data.crop_top = crop.top;
-  meta_data.crop_right = crop.right;
-  meta_data.crop_bottom = crop.bottom;
-  meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
-  meta_data.transform = static_cast<int32_t>(transform);
-
-  buffer_producer->PostAsync(&meta_data, fence_fd);
-  buffers_[slot].mBufferState.queue();
-
-  output->width = buffer_producer->width();
-  output->height = buffer_producer->height();
-  output->transformHint = 0;  // default value, we don't use it yet.
-
-  // |numPendingBuffers| counts of the number of buffers that has been enqueued
-  // by the producer but not yet acquired by the consumer. Due to the nature
-  // of BufferHubQueue design, this is hard to trace from the producer's client
-  // side, but it's safe to assume it's zero.
-  output->numPendingBuffers = 0;
-
-  // Note that we are not setting nextFrameNumber here as it seems to be only
-  // used by surface flinger. See more at b/22802885, ag/791760.
-  output->nextFrameNumber = 0;
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::cancelBuffer(int slot,
-                                              const sp<Fence>& fence) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("cancelBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if (fence == nullptr) {
-    ALOGE("cancelBuffer: fence is NULL");
-    return BAD_VALUE;
-  }
-
-  auto buffer_producer = buffers_[slot].mBufferProducer;
-  queue_->Enqueue(buffer_producer, slot, 0ULL);
-  buffers_[slot].mBufferState.cancel();
-  buffers_[slot].mFence = fence;
-  ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::query(int what, int* out_value) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (out_value == nullptr) {
-    ALOGE("query: out_value was NULL");
-    return BAD_VALUE;
-  }
-
-  int value = 0;
-  switch (what) {
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-      // TODO(b/36187402) This should be the maximum number of buffers that this
-      // producer queue's consumer can acquire. Set to be at least one. Need to
-      // find a way to set from the consumer side.
-      value = kDefaultUndequeuedBuffers;
-      break;
-    case NATIVE_WINDOW_BUFFER_AGE:
-      value = 0;
-      break;
-    case NATIVE_WINDOW_WIDTH:
-      value = queue_->default_width();
-      break;
-    case NATIVE_WINDOW_HEIGHT:
-      value = queue_->default_height();
-      break;
-    case NATIVE_WINDOW_FORMAT:
-      value = queue_->default_format();
-      break;
-    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
-      // BufferHubQueue is always operating in async mode, thus semantically
-      // consumer can never be running behind. See BufferQueueCore.cpp core
-      // for more information about the original meaning of this flag.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
-      // TODO(jwcai) This is currently not implement as we don't need
-      // IGraphicBufferConsumer parity.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_DEFAULT_DATASPACE:
-      // TODO(jwcai) Return the default value android::BufferQueue is using as
-      // there is no way dvr::ConsumerQueue can set it.
-      value = 0;  // HAL_DATASPACE_UNKNOWN
-      break;
-    case NATIVE_WINDOW_STICKY_TRANSFORM:
-      // TODO(jwcai) Return the default value android::BufferQueue is using as
-      // there is no way dvr::ConsumerQueue can set it.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
-      // In Daydream's implementation, the consumer end (i.e. VR Compostior)
-      // knows how to handle protected buffers.
-      value = 1;
-      break;
-    default:
-      return BAD_VALUE;
-  }
-
-  ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value);
-  *out_value = value;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::connect(
-    const sp<IProducerListener>& /* listener */, int api,
-    bool /* producer_controlled_by_app */, QueueBufferOutput* output) {
-  // Consumer interaction are actually handled by buffer hub, and we need
-  // to maintain consumer operations here. We only need to perform basic input
-  // parameter checks here.
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  if (output == nullptr) {
-    return BAD_VALUE;
-  }
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ != kNoConnectedApi) {
-    return BAD_VALUE;
-  }
-
-  switch (api) {
-    case NATIVE_WINDOW_API_EGL:
-    case NATIVE_WINDOW_API_CPU:
-    case NATIVE_WINDOW_API_MEDIA:
-    case NATIVE_WINDOW_API_CAMERA:
-      connected_api_ = api;
-
-      output->width = queue_->default_width();
-      output->height = queue_->default_height();
-
-      // default values, we don't use them yet.
-      output->transformHint = 0;
-      output->numPendingBuffers = 0;
-      output->nextFrameNumber = 0;
-      output->bufferReplaced = false;
-
-      break;
-    default:
-      ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
-      return BAD_VALUE;
-  }
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) {
-  // Consumer interaction are actually handled by buffer hub, and we need
-  // to maintain consumer operations here.  We only need to perform basic input
-  // parameter checks here.
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (kNoConnectedApi == connected_api_) {
-    return NO_INIT;
-  } else if (api != connected_api_) {
-    return BAD_VALUE;
-  }
-
-  FreeAllBuffers();
-  connected_api_ = kNoConnectedApi;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setSidebandStream(
-    const sp<NativeHandle>& stream) {
-  if (stream != nullptr) {
-    // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
-    // metadata.
-    ALOGE("SidebandStream is not currently supported.");
-    return INVALID_OPERATION;
-  }
-  return NO_ERROR;
-}
-
-void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
-                                             uint32_t /* height */,
-                                             PixelFormat /* format */,
-                                             uint64_t /* usage */) {
-  // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
-  // of buffers permitted by the current BufferQueue configuration (aka
-  // |max_buffer_count_|).
-  ALOGE("BufferHubQueueProducer::allocateBuffers not implemented.");
-}
-
-status_t BufferHubQueueProducer::allowAllocation(bool /* allow */) {
-  ALOGE("BufferHubQueueProducer::allowAllocation not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::setGenerationNumber(
-    uint32_t generation_number) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-  generation_number_ = generation_number;
-  return NO_ERROR;
-}
-
-String8 BufferHubQueueProducer::getConsumerName() const {
-  // BufferHub based implementation could have one to many producer/consumer
-  // relationship, thus |getConsumerName| from the producer side does not
-  // make any sense.
-  ALOGE("BufferHubQueueProducer::getConsumerName not supported.");
-  return String8("BufferHubQueue::DummyConsumer");
-}
-
-status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) {
-  if (shared_buffer_mode) {
-    ALOGE(
-        "BufferHubQueueProducer::setSharedBufferMode(true) is not supported.");
-    // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
-    return INVALID_OPERATION;
-  }
-  // Setting to default should just work as a no-op.
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) {
-  if (auto_refresh) {
-    ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported.");
-    return INVALID_OPERATION;
-  }
-  // Setting to default should just work as a no-op.
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-  dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getLastQueuedBuffer(
-    sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */,
-    float /*out_transform_matrix*/[16]) {
-  ALOGE("BufferHubQueueProducer::getLastQueuedBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-void BufferHubQueueProducer::getFrameTimestamps(
-    FrameEventHistoryDelta* /*outDelta*/) {
-  ALOGE("BufferHubQueueProducer::getFrameTimestamps not implemented.");
-}
-
-status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  *out_id = unique_id_;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
-  *out_usage = 0;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
-                                                uint32_t layer_count,
-                                                PixelFormat format,
-                                                uint64_t usage) {
-  auto status =
-      queue_->AllocateBuffer(width, height, layer_count, format, usage);
-  if (!status) {
-    ALOGE(
-        "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
-        status.GetErrorMessage().c_str());
-    return NO_MEMORY;
-  }
-
-  size_t slot = status.get();
-  auto buffer_producer = queue_->GetBuffer(slot);
-
-  LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
-                      "Failed to get buffer producer at slot: %zu", slot);
-
-  buffers_[slot].mBufferProducer = buffer_producer;
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) {
-  auto status = queue_->RemoveBuffer(slot);
-  if (!status) {
-    ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s",
-          status.GetErrorMessage().c_str());
-    return INVALID_OPERATION;
-  }
-
-  // Reset in memory objects related the the buffer.
-  buffers_[slot].mBufferProducer = nullptr;
-  buffers_[slot].mGraphicBuffer = nullptr;
-  buffers_[slot].mBufferState.detachProducer();
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::FreeAllBuffers() {
-  for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
-    // Reset in memory objects related the the buffer.
-    buffers_[slot].mGraphicBuffer = nullptr;
-    buffers_[slot].mBufferState.reset();
-    buffers_[slot].mRequestBufferCalled = false;
-    buffers_[slot].mBufferProducer = nullptr;
-    buffers_[slot].mFence = Fence::NO_FENCE;
-  }
-
-  auto status = queue_->FreeAllBuffers();
-  if (!status) {
-    ALOGE(
-        "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
-        "the queue: %s",
-        status.GetErrorMessage().c_str());
-  }
-
-  if (queue_->capacity() != 0 || queue_->count() != 0) {
-    LOG_ALWAYS_FATAL(
-        "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
-  }
-
-  return NO_ERROR;
-}
-
-}  // namespace dvr
-}  // namespace android
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 6962d6c..60e1c4b 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
@@ -1,14 +1,26 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
 #define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
 
-#include <gui/BufferQueueDefs.h>
+#include <ui/BufferQueueDefs.h>
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+// The following headers are included without checking every warning.
+// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
+// 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/epoll_file_descriptor.h>
-#include <private/dvr/ring_buffer.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 
 #include <memory>
 #include <queue>
@@ -45,15 +57,20 @@
   uint32_t default_width() const { return default_width_; }
 
   // Returns the default buffer height of this buffer queue.
-  uint32_t default_height() const { return default_height_; }
+  uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
 
   // Returns the default buffer format of this buffer queue.
-  uint32_t default_format() const { return default_format_; }
+  uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
 
   // Creates a new consumer in handle form for immediate transport over RPC.
   pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
       bool silent = false);
 
+  // Creates a new consumer in parcelable form for immediate transport over
+  // Binder.
+  pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable(
+      bool silent = false);
+
   // Returns the number of buffers avaiable for dequeue.
   size_t count() const { return available_buffers_.size(); }
 
@@ -68,7 +85,8 @@
     return available_buffers_.size() >= kMaxQueueCapacity;
   }
 
-  explicit operator bool() const { return epoll_fd_.IsValid(); }
+  // Returns whether the buffer queue is connected to bufferhubd.
+  bool is_connected() const { return !!GetChannel(); }
 
   int GetBufferId(size_t slot) const {
     return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
@@ -150,20 +168,20 @@
                                       int poll_events);
   pdx::Status<void> HandleQueueEvent(int poll_events);
 
-  // Entry in the ring buffer of available buffers that stores related
+  // Entry in the priority queue of available buffers that stores related
   // per-buffer data.
   struct Entry {
     Entry() : slot(0) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot,
-          uint64_t index)
-        : buffer(buffer), slot(slot), index(index) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
-          std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
-          size_t slot)
-        : buffer(buffer),
-          metadata(std::move(metadata)),
-          fence(std::move(fence)),
-          slot(slot) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer, size_t in_slot,
+          uint64_t in_index)
+        : buffer(in_buffer), slot(in_slot), index(in_index) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer,
+          std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence,
+          size_t in_slot)
+        : buffer(in_buffer),
+          metadata(std::move(in_metadata)),
+          fence(std::move(in_fence)),
+          slot(in_slot) {}
     Entry(Entry&&) = default;
     Entry& operator=(Entry&&) = default;
 
@@ -221,13 +239,13 @@
   bool is_async_{false};
 
   // Default buffer width that is set during ProducerQueue's creation.
-  size_t default_width_{1};
+  uint32_t default_width_{1};
 
   // Default buffer height that is set during ProducerQueue's creation.
-  size_t default_height_{1};
+  uint32_t default_height_{1};
 
   // Default buffer format that is set during ProducerQueue's creation.
-  int32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
+  uint32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
 
   // Tracks the buffers belonging to this queue. Buffers are stored according to
   // "slot" in this vector. Each slot is a logical id of the buffer within this
@@ -235,7 +253,6 @@
   std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
 
   // Buffers and related data that are available for dequeue.
-  // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
   std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
       available_buffers_;
 
@@ -337,6 +354,11 @@
     return BufferHubQueue::Enqueue({buffer, slot, index});
   }
 
+  // Takes out the current producer queue as a binder parcelable object. Note
+  // that the queue must be empty to be exportable. After successful export, the
+  // producer queue client should no longer be used.
+  pdx::Status<ProducerQueueParcelable> TakeAsParcelable();
+
  private:
   friend BASE;
 
@@ -363,10 +385,7 @@
   // used to avoid participation in the buffer lifecycle by a consumer queue
   // that is only used to spawn other consumer queues, such as in an
   // intermediate service.
-  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) {
-    return std::unique_ptr<ConsumerQueue>(
-        new ConsumerQueue(std::move(handle)));
-  }
+  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle);
 
   // Import newly created buffers from the service side.
   // Returns number of buffers successfully imported or an error.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
new file mode 100644
index 0000000..4dea9b2
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -0,0 +1,74 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+// The following headers are included without checking every warning.
+// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
+// in these headers and their dependencies.
+#include <pdx/channel_parcelable.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+namespace android {
+namespace dvr {
+
+enum BufferHubQueueParcelableMagic : uint32_t {
+  Producer = 0x62687170,  // 'bhqp'
+  Consumer = 0x62687163,  // 'bhqc'
+};
+
+template <BufferHubQueueParcelableMagic Magic>
+class BufferHubQueueParcelable : public Parcelable {
+ public:
+  BufferHubQueueParcelable() = default;
+
+  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
+  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) {
+    channel_parcelable_ = std::move(other.channel_parcelable_);
+    return *this;
+  }
+
+  // Constructs an parcelable contains the channel parcelable.
+  BufferHubQueueParcelable(
+      std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
+      : channel_parcelable_(std::move(channel_parcelable)) {}
+
+  BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete;
+  void operator=(const BufferHubQueueParcelable&) = delete;
+
+  bool IsValid() const;
+
+  // Returns a channel handle constructed from this parcelable object and takes
+  // the ownership of all resources from the parcelable object.
+  pdx::LocalChannelHandle TakeChannelHandle();
+
+  // Serializes the queue parcelable into the given parcel. Note that no system
+  // resources are getting duplicated, nor did the parcel takes ownership of the
+  // queue parcelable. Thus, the parcelable object must remain valid for the
+  // lifetime of the parcel.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Deserialize the queue parcelable from the given parcel. Note that system
+  // resources are duplicated from the parcel into the queue parcelable. Returns
+  // error if the targeting parcelable object is already valid.
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_;
+};
+
+using ProducerQueueParcelable =
+    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>;
+using ConsumerQueueParcelable =
+    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>;
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
deleted file mode 100644
index 7ed55fb..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-
-#include <gui/IGraphicBufferProducer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-
-namespace android {
-namespace dvr {
-
-class BufferHubQueueProducer : public BnGraphicBufferProducer {
- public:
-  static constexpr int kNoConnectedApi = -1;
-
-  // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
-  // side logic doesn't limit the number of buffer it can acquire
-  // simultaneously. We need a way for consumer logic to configure and enforce
-  // that.
-  static constexpr int kDefaultUndequeuedBuffers = 1;
-
-  // Create a BufferHubQueueProducer instance by creating a new producer queue.
-  static sp<BufferHubQueueProducer> Create();
-
-  // Create a BufferHubQueueProducer instance by importing an existing prodcuer
-  // queue.
-  static sp<BufferHubQueueProducer> Create(
-      const std::shared_ptr<ProducerQueue>& producer);
-
-  // See |IGraphicBufferProducer::requestBuffer|
-  status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
-
-  // For the BufferHub based implementation. All buffers in the queue are
-  // allowed to be dequeued from the consumer side. It call always returns
-  // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
-  // |max_dequeued_buffers| here can be considered the same as setting queue
-  // capacity.
-  //
-  // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
-  status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
-
-  // See |IGraphicBufferProducer::setAsyncMode|
-  status_t setAsyncMode(bool async) override;
-
-  // See |IGraphicBufferProducer::dequeueBuffer|
-  status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
-                         uint32_t height, PixelFormat format, uint64_t usage,
-                         uint64_t* outBufferAge,
-                         FrameEventHistoryDelta* outTimestamps) override;
-
-  // See |IGraphicBufferProducer::detachBuffer|
-  status_t detachBuffer(int slot) override;
-
-  // See |IGraphicBufferProducer::detachNextBuffer|
-  status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer,
-                            sp<Fence>* out_fence) override;
-
-  // See |IGraphicBufferProducer::attachBuffer|
-  status_t attachBuffer(int* out_slot,
-                        const sp<GraphicBuffer>& buffer) override;
-
-  // See |IGraphicBufferProducer::queueBuffer|
-  status_t queueBuffer(int slot, const QueueBufferInput& input,
-                       QueueBufferOutput* output) override;
-
-  // See |IGraphicBufferProducer::cancelBuffer|
-  status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
-
-  // See |IGraphicBufferProducer::query|
-  status_t query(int what, int* out_value) override;
-
-  // See |IGraphicBufferProducer::connect|
-  status_t connect(const sp<IProducerListener>& listener, int api,
-                   bool producer_controlled_by_app,
-                   QueueBufferOutput* output) override;
-
-  // See |IGraphicBufferProducer::disconnect|
-  status_t disconnect(int api,
-                      DisconnectMode mode = DisconnectMode::Api) override;
-
-  // See |IGraphicBufferProducer::setSidebandStream|
-  status_t setSidebandStream(const sp<NativeHandle>& stream) override;
-
-  // See |IGraphicBufferProducer::allocateBuffers|
-  void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
-                       uint64_t usage) override;
-
-  // See |IGraphicBufferProducer::allowAllocation|
-  status_t allowAllocation(bool allow) override;
-
-  // See |IGraphicBufferProducer::setGenerationNumber|
-  status_t setGenerationNumber(uint32_t generation_number) override;
-
-  // See |IGraphicBufferProducer::getConsumerName|
-  String8 getConsumerName() const override;
-
-  // See |IGraphicBufferProducer::setSharedBufferMode|
-  status_t setSharedBufferMode(bool shared_buffer_mode) override;
-
-  // See |IGraphicBufferProducer::setAutoRefresh|
-  status_t setAutoRefresh(bool auto_refresh) override;
-
-  // See |IGraphicBufferProducer::setDequeueTimeout|
-  status_t setDequeueTimeout(nsecs_t timeout) override;
-
-  // See |IGraphicBufferProducer::getLastQueuedBuffer|
-  status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer,
-                               sp<Fence>* out_fence,
-                               float out_transform_matrix[16]) override;
-
-  // See |IGraphicBufferProducer::getFrameTimestamps|
-  void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
-
-  // See |IGraphicBufferProducer::getUniqueId|
-  status_t getUniqueId(uint64_t* out_id) const override;
-
-  // See |IGraphicBufferProducer::getConsumerUsage|
-  status_t getConsumerUsage(uint64_t* out_usage) const override;
-
- private:
-  using LocalHandle = pdx::LocalHandle;
-
-  // Private constructor to force use of |Create|.
-  BufferHubQueueProducer() {}
-
-  static uint64_t genUniqueId() {
-    static std::atomic<uint32_t> counter{0};
-    static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
-    return id | counter++;
-  }
-
-  // Allocate new buffer through BufferHub and add it into |queue_| for
-  // bookkeeping.
-  status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
-                          PixelFormat format, uint64_t usage);
-
-  // Remove a buffer via BufferHubRPC.
-  status_t RemoveBuffer(size_t slot);
-
-  // Free all buffers which are owned by the prodcuer. Note that if graphic
-  // buffers are acquired by the consumer, we can't .
-  status_t FreeAllBuffers();
-
-  // Concreate implementation backed by BufferHubBuffer.
-  std::shared_ptr<ProducerQueue> queue_;
-
-  // Mutex for thread safety.
-  std::mutex mutex_;
-
-  // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
-  int connected_api_{kNoConnectedApi};
-
-  // |max_buffer_count_| sets the capacity of the underlying buffer queue.
-  int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity};
-
-  // |max_dequeued_buffer_count_| set the maximum number of buffers that can
-  // be dequeued at the same momment.
-  int32_t max_dequeued_buffer_count_{1};
-
-  // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
-  // slot is not yet available. The timeout is stored in milliseconds.
-  int dequeue_timeout_ms_{BufferHubQueue::kNoTimeOut};
-
-  // |generation_number_| stores the current generation number of the attached
-  // producer. Any attempt to attach a buffer with a different generation
-  // number will fail.
-  // TOOD(b/38137191) Currently not used as we don't support
-  // IGraphicBufferProducer::detachBuffer.
-  uint32_t generation_number_{0};
-
-  // |buffers_| stores the buffers that have been dequeued from
-  // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
-  // filled in with the result of |Dequeue|.
-  // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
-  // requested buffer usage or geometry differs from that of the buffer
-  // allocated to a slot.
-  struct BufferHubSlot : public BufferSlot {
-    BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
-    // BufferSlot comes from android framework, using m prefix to comply with
-    // the name convention with the reset of data fields from BufferSlot.
-    std::shared_ptr<BufferProducer> mBufferProducer;
-    bool mIsReallocating;
-  };
-  BufferHubSlot buffers_[BufferHubQueue::kMaxQueueCapacity];
-
-  // A uniqueId used by IGraphicBufferProducer interface.
-  const uint64_t unique_id_{genUniqueId()};
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
diff --git a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
similarity index 84%
rename from libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
rename to libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
index 099a409..6e303a5 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
@@ -1,5 +1,5 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
 
 #include <android-base/unique_fd.h>
 #include <log/log.h>
@@ -61,4 +61,4 @@
 }  // namespace dvr
 }  // namespace android
 
-#endif  // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#endif  // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 8bd1ef1..ca1e7bd 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -6,20 +6,21 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
     "libhardware",
     "libui",
     "libutils",
+    "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
-    "libpdx_default_transport",
+    "libperformance",
 ]
 
 cc_test {
@@ -32,6 +33,9 @@
         "-DTRACE=0",
         "-O0",
         "-g",
+        "-Wall",
+        "-Werror",
+        "-Wno-error=sign-compare", // to fix later
     ],
     name: "buffer_hub_queue-test",
     tags: ["optional"],
@@ -47,6 +51,8 @@
         "-DTRACE=0",
         "-O0",
         "-g",
+        "-Wall",
+        "-Werror",
     ],
     name: "buffer_hub_queue_producer-test",
     tags: ["optional"],
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 8a72531..47a2734 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,4 +1,5 @@
 #include <base/logging.h>
+#include <binder/Parcel.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 
@@ -14,6 +15,7 @@
 namespace android {
 namespace dvr {
 
+using pdx::LocalChannelHandle;
 using pdx::LocalHandle;
 
 namespace {
@@ -23,6 +25,8 @@
 constexpr uint32_t kBufferLayerCount = 1;
 constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
 constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+constexpr int kTimeoutMs = 100;
+constexpr int kNoTimeout = 0;
 
 class BufferHubQueueTest : public ::testing::Test {
  public:
@@ -82,41 +86,49 @@
 };
 
 TEST_F(BufferHubQueueTest, TestDequeue) {
-  const size_t nb_dequeue_times = 16;
+  const int64_t nb_dequeue_times = 16;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   // Allocate only one buffer.
   AllocateBuffer();
 
   // But dequeue multiple times.
-  for (size_t i = 0; i < nb_dequeue_times; i++) {
+  for (int64_t i = 0; i < nb_dequeue_times; i++) {
     size_t slot;
     LocalHandle fence;
-    auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-    ASSERT_TRUE(p1_status.ok());
+    DvrNativeBufferMetadata mi, mo;
+
+    // Producer gains a buffer.
+    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(p1_status.ok());
     auto p1 = p1_status.take();
-    ASSERT_NE(nullptr, p1);
-    size_t mi = i;
-    ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0);
-    size_t mo;
-    auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-    ASSERT_TRUE(c1_status.ok());
+    ASSERT_NE(p1, nullptr);
+
+    // Producer posts the buffer.
+    mi.index = i;
+    EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+
+    // Consumer acquires a buffer.
+    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(c1_status.ok());
     auto c1 = c1_status.take();
-    ASSERT_NE(nullptr, c1);
-    ASSERT_EQ(mi, mo);
-    c1->Release(LocalHandle());
+    ASSERT_NE(c1, nullptr);
+    EXPECT_EQ(mi.index, i);
+    EXPECT_EQ(mo.index, i);
+
+    // Consumer releases the buffer.
+    EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
   }
 }
 
 TEST_F(BufferHubQueueTest, TestProducerConsumer) {
   const size_t kBufferCount = 16;
   size_t slot;
-  uint64_t seq;
+  DvrNativeBufferMetadata mi, mo;
+  LocalHandle fence;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   for (size_t i = 0; i < kBufferCount; i++) {
     AllocateBuffer();
@@ -131,8 +143,7 @@
     ASSERT_EQ(consumer_queue_->capacity(), i);
     // Dequeue returns timeout since no buffer is ready to consumer, but
     // this implicitly triggers buffer import and bump up |capacity|.
-    LocalHandle fence;
-    auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
     ASSERT_FALSE(status.ok());
     ASSERT_EQ(ETIMEDOUT, status.error());
     ASSERT_EQ(consumer_queue_->capacity(), i + 1);
@@ -142,37 +153,37 @@
   LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
 
   for (size_t i = 0; i < kBufferCount; i++) {
-    LocalHandle fence;
-
     // First time there is no buffer available to dequeue.
-    auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    auto consumer_status =
+        consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
     ASSERT_FALSE(consumer_status.ok());
-    ASSERT_EQ(ETIMEDOUT, consumer_status.error());
+    ASSERT_EQ(consumer_status.error(), ETIMEDOUT);
 
     // Make sure Producer buffer is POSTED so that it's ready to Accquire
     // in the consumer's Dequeue() function.
-    auto producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    auto producer_status =
+        producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     auto producer = producer_status.take();
     ASSERT_NE(nullptr, producer);
 
-    uint64_t seq_in = static_cast<uint64_t>(i);
-    ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0);
+    mi.index = static_cast<int64_t>(i);
+    ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0);
 
     // Second time the just the POSTED buffer should be dequeued.
-    uint64_t seq_out = 0;
-    consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence);
+    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(consumer_status.ok());
     EXPECT_TRUE(fence.IsValid());
 
     auto consumer = consumer_status.take();
     ASSERT_NE(nullptr, consumer);
-    ASSERT_EQ(seq_in, seq_out);
+    ASSERT_EQ(mi.index, mo.index);
   }
 }
 
 TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
   ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+  DvrNativeBufferMetadata mo;
 
   // Allocate buffers.
   const size_t kBufferCount = 4u;
@@ -201,7 +212,7 @@
   for (size_t i = 0; i < kBufferCount; i++) {
     Entry* entry = &buffers[i];
     auto producer_status = producer_queue_->Dequeue(
-        /*timeout_ms=*/100, &entry->slot, &entry->fence);
+        kTimeoutMs, &entry->slot, &mo, &entry->fence);
     ASSERT_TRUE(producer_status.ok());
     entry->buffer = producer_status.take();
     ASSERT_NE(nullptr, entry->buffer);
@@ -221,7 +232,7 @@
   buffers[0].buffer = nullptr;
 
   // Now the consumer queue should know it's gone.
-  EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100));
+  EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs));
   ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity());
 
   // Allocate a new buffer. This should take the first empty slot.
@@ -290,126 +301,156 @@
   ASSERT_NE(nullptr, silent_queue);
 
   // Check that silent queue doesn't import buffers on creation.
-  EXPECT_EQ(0, silent_queue->capacity());
+  EXPECT_EQ(silent_queue->capacity(), 0U);
 
   // Dequeue and post a buffer.
   size_t slot;
   LocalHandle fence;
+  DvrNativeBufferMetadata mi, mo;
   auto producer_status =
-      producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(producer_status.ok());
+      producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(producer_status.ok());
   auto producer_buffer = producer_status.take();
-  ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post<void>({}));
+  ASSERT_NE(producer_buffer, nullptr);
+  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
   // After post, check the number of remaining available buffers.
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   // Currently we expect no buffer to be available prior to calling
   // WaitForBuffers/HandleQueueEvents.
   // TODO(eieio): Note this behavior may change in the future.
-  EXPECT_EQ(0u, silent_queue->count());
+  EXPECT_EQ(silent_queue->count(), 0U);
   EXPECT_FALSE(silent_queue->HandleQueueEvents());
-  EXPECT_EQ(0u, silent_queue->count());
+  EXPECT_EQ(silent_queue->count(), 0U);
 
   // Build a new consumer queue to test multi-consumer queue features.
   consumer_queue_ = silent_queue->CreateConsumerQueue();
-  ASSERT_NE(nullptr, consumer_queue_);
+  ASSERT_NE(consumer_queue_, nullptr);
 
   // Check that buffers are correctly imported on construction.
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_EQ(1u, consumer_queue_->count());
+  EXPECT_EQ(consumer_queue_->capacity(), kBufferCount);
+  // Buffers are only imported, but their availability is not checked until
+  // first call to Dequeue().
+  EXPECT_EQ(consumer_queue_->count(), 0U);
 
   // Reclaim released/ignored buffers.
-  ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   usleep(10000);
-  WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100);
-  ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   // Post another buffer.
-  producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(producer_status.ok());
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(producer_status.ok());
   producer_buffer = producer_status.take();
-  ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post<void>({}));
+  ASSERT_NE(producer_buffer, nullptr);
+  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
 
   // Verify that the consumer queue receives it.
   size_t consumer_queue_count = consumer_queue_->count();
-  WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100);
-  EXPECT_LT(consumer_queue_count, consumer_queue_->count());
+  WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
+  EXPECT_GT(consumer_queue_->count(), consumer_queue_count);
 
   // Save the current consumer queue buffer count to compare after the dequeue.
   consumer_queue_count = consumer_queue_->count();
 
   // Dequeue and acquire/release (discard) buffers on the consumer end.
   auto consumer_status =
-      consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(consumer_status.ok());
+      consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(consumer_status.ok());
   auto consumer_buffer = consumer_status.take();
-  ASSERT_NE(nullptr, consumer_buffer);
+  ASSERT_NE(consumer_buffer, nullptr);
   consumer_buffer->Discard();
 
   // Buffer should be returned to the producer queue without being handled by
   // the silent consumer queue.
-  EXPECT_GT(consumer_queue_count, consumer_queue_->count());
-  EXPECT_EQ(kBufferCount - 2, producer_queue_->count());
-  EXPECT_TRUE(producer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_LT(consumer_queue_->count(), consumer_queue_count);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 2);
+
+  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 }
 
-struct TestMetadata {
+struct TestUserMetadata {
   char a;
   int32_t b;
   int64_t c;
 };
 
-TEST_F(BufferHubQueueTest, TestMetadata) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(),
-                           UsagePolicy{}));
+constexpr uint64_t kUserMetadataSize =
+    static_cast<uint64_t>(sizeof(TestUserMetadata));
+
+TEST_F(BufferHubQueueTest, TestUserMetadata) {
+  ASSERT_TRUE(CreateQueues(
+      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
 
   AllocateBuffer();
 
-  std::vector<TestMetadata> ms = {
+  std::vector<TestUserMetadata> user_metadata_list = {
       {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
 
-  for (auto mi : ms) {
+  for (auto user_metadata : user_metadata_list) {
     size_t slot;
     LocalHandle fence;
-    auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-    ASSERT_TRUE(p1_status.ok());
+    DvrNativeBufferMetadata mi, mo;
+
+    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(p1_status.ok());
     auto p1 = p1_status.take();
-    ASSERT_NE(nullptr, p1);
-    ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
-    TestMetadata mo;
-    auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-    ASSERT_TRUE(c1_status.ok());
+    ASSERT_NE(p1, nullptr);
+
+    // TODO(b/69469185): Test against metadata from consumer once we implement
+    // release metadata properly.
+    // EXPECT_EQ(mo.user_metadata_ptr, 0U);
+    // EXPECT_EQ(mo.user_metadata_size, 0U);
+
+    mi.user_metadata_size = kUserMetadataSize;
+    mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+    EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
+    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(c1_status.ok());
     auto c1 = c1_status.take();
-    ASSERT_EQ(mi.a, mo.a);
-    ASSERT_EQ(mi.b, mo.b);
-    ASSERT_EQ(mi.c, mo.c);
-    c1->Release(LocalHandle(-1));
+    ASSERT_NE(c1, nullptr);
+
+    EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize);
+    auto out_user_metadata =
+        reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr);
+    EXPECT_EQ(user_metadata.a, out_user_metadata->a);
+    EXPECT_EQ(user_metadata.b, out_user_metadata->b);
+    EXPECT_EQ(user_metadata.c, out_user_metadata->c);
+
+    // When release, empty metadata is also legit.
+    mi.user_metadata_size = 0U;
+    mi.user_metadata_ptr = 0U;
+    c1->ReleaseAsync(&mi, {});
   }
 }
 
-TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{}));
+TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) {
+  ASSERT_TRUE(CreateQueues(
+      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
 
   AllocateBuffer();
 
-  int64_t mi = 3;
+  TestUserMetadata user_metadata;
   size_t slot;
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-  ASSERT_TRUE(p1_status.ok());
+  DvrNativeBufferMetadata mi, mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_NE(nullptr, p1);
-  ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
+  ASSERT_NE(p1, nullptr);
 
-  int32_t mo;
-  // Acquire a buffer with mismatched metadata is not OK.
-  auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-  ASSERT_FALSE(c1_status.ok());
+  // Post with mismatched user metadata size will fail. But the producer buffer
+  // itself should stay untouched.
+  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+  mi.user_metadata_size = kUserMetadataSize + 1;
+  EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG);
+  // Post with the exact same user metdata size can success.
+  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+  mi.user_metadata_size = kUserMetadataSize;
+  EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
 }
 
 TEST_F(BufferHubQueueTest, TestEnqueue) {
@@ -419,32 +460,32 @@
 
   size_t slot;
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
   ASSERT_NE(nullptr, p1);
 
-  int64_t mo;
   producer_queue_->Enqueue(p1, slot, 0ULL);
-  auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
+  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_FALSE(c1_status.ok());
 }
 
 TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
-  size_t s1;
+  size_t ps1;
   AllocateBuffer();
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &s1, &fence);
+  DvrNativeBufferMetadata mi, mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_NE(nullptr, p1);
+  ASSERT_NE(p1, nullptr);
 
   // producer queue is exhausted
-  size_t s2;
-  auto p2_status = producer_queue_->Dequeue(100, &s2, &fence);
+  size_t ps2;
+  auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
   ASSERT_FALSE(p2_status.ok());
   ASSERT_EQ(ETIMEDOUT, p2_status.error());
 
@@ -454,41 +495,43 @@
   ASSERT_EQ(producer_queue_->capacity(), 2U);
 
   // now we can dequeue again
-  p2_status = producer_queue_->Dequeue(100, &s2, &fence);
+  p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
   ASSERT_TRUE(p2_status.ok());
   auto p2 = p2_status.take();
-  ASSERT_NE(nullptr, p2);
+  ASSERT_NE(p2, nullptr);
   ASSERT_EQ(producer_queue_->count(), 0U);
   // p1 and p2 should have different slot number
-  ASSERT_NE(s1, s2);
+  ASSERT_NE(ps1, ps2);
 
   // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
   // are called. So far consumer_queue_ should be empty.
   ASSERT_EQ(consumer_queue_->count(), 0U);
 
   int64_t seq = 1;
-  ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
+  mi.index = seq;
+  ASSERT_EQ(p1->PostAsync(&mi, {}), 0);
+
   size_t cs1, cs2;
-  auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence);
+  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence);
   ASSERT_TRUE(c1_status.ok());
   auto c1 = c1_status.take();
-  ASSERT_NE(nullptr, c1);
+  ASSERT_NE(c1, nullptr);
   ASSERT_EQ(consumer_queue_->count(), 0U);
   ASSERT_EQ(consumer_queue_->capacity(), 2U);
-  ASSERT_EQ(cs1, s1);
+  ASSERT_EQ(cs1, ps1);
 
-  ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
-  auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence);
+  ASSERT_EQ(p2->PostAsync(&mi, {}), 0);
+  auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence);
   ASSERT_TRUE(c2_status.ok());
   auto c2 = c2_status.take();
-  ASSERT_NE(nullptr, c2);
-  ASSERT_EQ(cs2, s2);
+  ASSERT_NE(c2, nullptr);
+  ASSERT_EQ(cs2, ps2);
 }
 
 TEST_F(BufferHubQueueTest, TestUsageSetMask) {
   const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{set_mask, 0, 0, 0}));
+  ASSERT_TRUE(
+      CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0}));
 
   // When allocation, leave out |set_mask| from usage bits on purpose.
   auto status = producer_queue_->AllocateBuffer(
@@ -498,7 +541,8 @@
 
   LocalHandle fence;
   size_t slot;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
   ASSERT_EQ(p1->usage() & set_mask, set_mask);
@@ -506,8 +550,8 @@
 
 TEST_F(BufferHubQueueTest, TestUsageClearMask) {
   const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{0, clear_mask, 0, 0}));
+  ASSERT_TRUE(
+      CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0}));
 
   // When allocation, add |clear_mask| into usage bits on purpose.
   auto status = producer_queue_->AllocateBuffer(
@@ -517,10 +561,11 @@
 
   LocalHandle fence;
   size_t slot;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_EQ(0u, p1->usage() & clear_mask);
+  ASSERT_EQ(p1->usage() & clear_mask, 0U);
 }
 
 TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
@@ -598,16 +643,15 @@
   EXPECT_EQ(producer_queue_->capacity(), num_buffers);
 
   size_t slot;
-  uint64_t seq;
   LocalHandle fence;
   pdx::Status<void> status;
   pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status;
   pdx::Status<std::shared_ptr<BufferProducer>> producer_status;
   std::shared_ptr<BufferConsumer> consumer_buffer;
   std::shared_ptr<BufferProducer> producer_buffer;
+  DvrNativeBufferMetadata mi, mo;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   // Free all buffers when buffers are avaible for dequeue.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
@@ -616,7 +660,7 @@
 
   // Free all buffers when one buffer is dequeued.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(producer_status.ok());
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
@@ -624,7 +668,7 @@
   // Free all buffers when all buffers are dequeued.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
   }
   status = producer_queue_->FreeAllBuffers();
@@ -632,22 +676,22 @@
 
   // Free all buffers when one buffer is posted.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(producer_status.ok());
   producer_buffer = producer_status.take();
   ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+  ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence));
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
 
   // Free all buffers when all buffers are posted.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     producer_buffer = producer_status.take();
-    ASSERT_NE(nullptr, producer_buffer);
-    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+    ASSERT_NE(producer_buffer, nullptr);
+    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
   }
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
@@ -655,12 +699,12 @@
   // Free all buffers when all buffers are acquired.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     producer_buffer = producer_status.take();
-    ASSERT_NE(nullptr, producer_buffer);
-    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
-    consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    ASSERT_NE(producer_buffer, nullptr);
+    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
+    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(consumer_status.ok());
   }
 
@@ -680,6 +724,156 @@
 #undef CHECK_NO_BUFFER_THEN_ALLOCATE
 }
 
+TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) {
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+                           UsagePolicy{}));
+
+  // Allocate only one buffer.
+  AllocateBuffer();
+
+  // Export should fail as the queue is not empty.
+  auto status = producer_queue_->TakeAsParcelable();
+  EXPECT_FALSE(status.ok());
+}
+
+TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+  auto s1 = producer_queue_->TakeAsParcelable();
+  EXPECT_TRUE(s1.ok());
+
+  ProducerQueueParcelable output_parcelable = s1.take();
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  Parcel parcel;
+  status_t res;
+  res = output_parcelable.writeToParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+
+  // After written into parcelable, the output_parcelable is still valid has
+  // keeps the producer channel alive.
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  // Creating producer buffer should fail.
+  auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+                                            kBufferLayerCount, kBufferFormat,
+                                            kBufferUsage);
+  ASSERT_FALSE(s2.ok());
+
+  // Reset the data position so that we can read back from the same parcel
+  // without doing actually Binder IPC.
+  parcel.setDataPosition(0);
+  producer_queue_ = nullptr;
+
+  // Recreate the producer queue from the parcel.
+  ProducerQueueParcelable input_parcelable;
+  EXPECT_FALSE(input_parcelable.IsValid());
+
+  res = input_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+  EXPECT_TRUE(input_parcelable.IsValid());
+
+  EXPECT_EQ(producer_queue_, nullptr);
+  producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle());
+  EXPECT_FALSE(input_parcelable.IsValid());
+  ASSERT_NE(producer_queue_, nullptr);
+
+  // Newly created queue from the parcel can allocate buffer, post buffer to
+  // consumer.
+  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+  EXPECT_EQ(producer_queue_->count(), 1U);
+  EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+  size_t slot;
+  DvrNativeBufferMetadata producer_meta;
+  DvrNativeBufferMetadata consumer_meta;
+  LocalHandle fence;
+  auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+  EXPECT_TRUE(s3.ok());
+
+  std::shared_ptr<BufferProducer> p1 = s3.take();
+  ASSERT_NE(p1, nullptr);
+
+  producer_meta.timestamp = 42;
+  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+  // Make sure the buffer can be dequeued from consumer side.
+  auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
+  EXPECT_TRUE(s4.ok());
+  EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+  auto consumer = s4.take();
+  ASSERT_NE(consumer, nullptr);
+  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
+TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) {
+  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+  auto s1 = producer_queue_->CreateConsumerQueueParcelable();
+  EXPECT_TRUE(s1.ok());
+  ConsumerQueueParcelable output_parcelable = s1.take();
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  // Write to a Parcel new object.
+  Parcel parcel;
+  status_t res;
+  res = output_parcelable.writeToParcel(&parcel);
+
+  // Reset the data position so that we can read back from the same parcel
+  // without doing actually Binder IPC.
+  parcel.setDataPosition(0);
+
+  // No consumer queue created yet.
+  EXPECT_EQ(consumer_queue_, nullptr);
+
+  // If the parcel contains a consumer queue, read into a
+  // ProducerQueueParcelable should fail.
+  ProducerQueueParcelable wrongly_typed_parcelable;
+  EXPECT_FALSE(wrongly_typed_parcelable.IsValid());
+  res = wrongly_typed_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, -EINVAL);
+  parcel.setDataPosition(0);
+
+  // Create the consumer queue from the parcel.
+  ConsumerQueueParcelable input_parcelable;
+  EXPECT_FALSE(input_parcelable.IsValid());
+
+  res = input_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+  EXPECT_TRUE(input_parcelable.IsValid());
+
+  consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle());
+  EXPECT_FALSE(input_parcelable.IsValid());
+  ASSERT_NE(consumer_queue_, nullptr);
+
+  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+  EXPECT_EQ(producer_queue_->count(), 1U);
+  EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+  size_t slot;
+  DvrNativeBufferMetadata producer_meta;
+  DvrNativeBufferMetadata consumer_meta;
+  LocalHandle fence;
+  auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+  EXPECT_TRUE(s2.ok());
+
+  std::shared_ptr<BufferProducer> p1 = s2.take();
+  ASSERT_NE(p1, nullptr);
+
+  producer_meta.timestamp = 42;
+  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+  // Make sure the buffer can be dequeued from consumer side.
+  auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
+  EXPECT_TRUE(s3.ok());
+  EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+  auto consumer = s3.take();
+  ASSERT_NE(consumer, nullptr);
+  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 28cd63a..4f10f83 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -1,14 +1,16 @@
-#include <private/dvr/buffer_hub_queue_producer.h>
-
 #include <base/logging.h>
+#include <gui/BufferHubProducer.h>
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+#include <pdx/default_transport/channel_parcelable.h>
 
 #include <gtest/gtest.h>
 
 namespace android {
 namespace dvr {
 
+using pdx::LocalHandle;
+
 namespace {
 
 // Default dimensions before setDefaultBufferSize is called by the consumer.
@@ -92,7 +94,11 @@
     ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
              testInfo->name());
 
-    mProducer = BufferHubQueueProducer::Create();
+    auto config = ProducerQueueConfigBuilder().Build();
+    auto queue = ProducerQueue::Create(config, UsagePolicy{});
+    ASSERT_TRUE(queue != nullptr);
+
+    mProducer = BufferHubProducer::Create(std::move(queue));
     ASSERT_TRUE(mProducer != nullptr);
     mSurface = new Surface(mProducer, true);
     ASSERT_TRUE(mSurface != nullptr);
@@ -136,7 +142,7 @@
 
   const sp<IProducerListener> kDummyListener{new DummyProducerListener};
 
-  sp<BufferHubQueueProducer> mProducer;
+  sp<BufferHubProducer> mProducer;
   sp<Surface> mSurface;
 };
 
@@ -546,6 +552,55 @@
   EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
 }
 
+TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
+  // Connected producer cannot be taken out as a parcelable.
+  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+  ProducerQueueParcelable producer_parcelable;
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
+
+  // Create a valid dummy producer parcelable.
+  auto dummy_channel_parcelable =
+      std::make_unique<pdx::default_transport::ChannelParcelable>(
+          LocalHandle(0), LocalHandle(0), LocalHandle(0));
+  EXPECT_TRUE(dummy_channel_parcelable->IsValid());
+  ProducerQueueParcelable dummy_producer_parcelable(
+      std::move(dummy_channel_parcelable));
+  EXPECT_TRUE(dummy_producer_parcelable.IsValid());
+
+  // Disconnect producer can be taken out, but only to an invalid parcelable.
+  ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR);
+  EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE);
+  EXPECT_FALSE(producer_parcelable.IsValid());
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR);
+  EXPECT_TRUE(producer_parcelable.IsValid());
+
+  // Should still be able to query buffer dimension after disconnect.
+  int32_t value = -1;
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR);
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR);
+  EXPECT_EQ(value, kDefaultFormat);
+
+  // But connect to API will fail.
+  IGraphicBufferProducer::QueueBufferOutput output;
+  EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp,
+                               &output),
+            BAD_VALUE);
+
+  // Create a new producer from the parcelable and connect to kTestApi should
+  // succeed.
+  sp<BufferHubProducer> new_producer =
+      BufferHubProducer::Create(std::move(producer_parcelable));
+  ASSERT_TRUE(new_producer != nullptr);
+  EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
+                                  kTestControlledByApp, &output),
+            NO_ERROR);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index e3ab7fa..192fb5d 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -26,6 +26,8 @@
 
 sharedLibraries = [
     "libbase",
+    "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libutils",
@@ -34,14 +36,12 @@
     "libhardware",
     "libsync",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 staticLibraries = [
     "libdvrcommon",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -57,6 +57,8 @@
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
     ],  // + [ "-UNDEBUG", "-DDEBUG", "-O0", "-g" ],
     export_include_dirs: localIncludeFiles,
     shared_libs: sharedLibraries,
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 442c82d..f67e258 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -9,7 +9,6 @@
 #include <mutex>
 
 #include <private/dvr/display_protocol.h>
-#include <private/dvr/native_buffer.h>
 
 using android::pdx::ErrorStatus;
 using android::pdx::LocalHandle;
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 9fe161d..16906f5 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -15,13 +15,15 @@
 
 cc_library_headers {
     name: "libdvr_headers",
-    owner: "google",
     export_include_dirs: ["include"],
+    vendor_available: true,
 }
 
 cflags = [
     "-DLOG_TAG=\"libdvr\"",
     "-DTRACE=0",
+    "-Wall",
+    "-Werror",
 ]
 
 srcs = [
@@ -39,8 +41,6 @@
 
 static_libs = [
     "libbroadcastring",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libvrsensor",
     "libdisplay",
     "libvirtualtouchpadclient",
@@ -48,13 +48,13 @@
     "libvr_hwc-binder",
     "libgrallocusage",
     "libperformance",
-    "libpdx_default_transport",
 ]
 
 shared_libs = [
     "android.hardware.graphics.bufferqueue@1.0",
     "android.hidl.token@1.0-utils",
     "libbase",
+    "libbufferhubqueue",
     "libbinder",
     "liblog",
     "libcutils",
@@ -62,6 +62,7 @@
     "libnativewindow",
     "libgui",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library_shared {
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 7d4e2d1..d14f040 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -41,10 +41,19 @@
     }                                                          \
   } while (0)
 
+#define DVR_V1_API_ENTRY_DEPRECATED(name)                      \
+  do {                                                         \
+    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+        clamped_struct_size) {                                 \
+      dvr_api->name = nullptr;                                 \
+    }                                                          \
+  } while (0)
+
 #include "include/dvr/dvr_api_entries.h"
 
 // Undefine macro definitions to play nice with Google3 style rules.
 #undef DVR_V1_API_ENTRY
+#undef DVR_V1_API_ENTRY_DEPRECATED
 
     return 0;
   }
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 1a99234..baf1f2f 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -38,17 +38,13 @@
 
 extern "C" {
 
-void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer) {
-  if (write_buffer)
-    *write_buffer = new DvrWriteBuffer;
-}
-
 void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
   if (write_buffer != nullptr) {
     ALOGW_IF(
         write_buffer->slot != -1,
         "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrWriteBufferGetId(write_buffer));
     delete write_buffer;
   }
 }
@@ -57,14 +53,6 @@
   return write_buffer && write_buffer->write_buffer;
 }
 
-int dvrWriteBufferClear(DvrWriteBuffer* write_buffer) {
-  if (!write_buffer)
-    return -EINVAL;
-
-  write_buffer->write_buffer = nullptr;
-  return 0;
-}
-
 int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) {
   if (!write_buffer || !write_buffer->write_buffer)
     return -EINVAL;
@@ -81,44 +69,13 @@
       write_buffer->write_buffer->buffer()->buffer().get(), hardware_buffer);
 }
 
-int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd,
-                       const void* meta, size_t meta_size_bytes) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle fence(ready_fence_fd);
-  int result = write_buffer->write_buffer->Post(fence, meta, meta_size_bytes);
-  return result;
-}
-
-int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd) {
-  if (!write_buffer || !write_buffer->write_buffer || !release_fence_fd)
-    return -EINVAL;
-
-  pdx::LocalHandle release_fence;
-  int result = write_buffer->write_buffer->Gain(&release_fence);
-  *release_fence_fd = release_fence.Release();
-  return result;
-}
-
-int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  return write_buffer->write_buffer->GainAsync();
-}
-
-void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer) {
-  if (read_buffer)
-    *read_buffer = new DvrReadBuffer;
-}
-
 void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
   if (read_buffer != nullptr) {
     ALOGW_IF(
         read_buffer->slot != -1,
         "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrReadBufferGetId(read_buffer));
     delete read_buffer;
   }
 }
@@ -127,14 +84,6 @@
   return read_buffer && read_buffer->read_buffer;
 }
 
-int dvrReadBufferClear(DvrReadBuffer* read_buffer) {
-  if (!read_buffer)
-    return -EINVAL;
-
-  read_buffer->read_buffer = nullptr;
-  return 0;
-}
-
 int dvrReadBufferGetId(DvrReadBuffer* read_buffer) {
   if (!read_buffer || !read_buffer->read_buffer)
     return -EINVAL;
@@ -151,34 +100,6 @@
       read_buffer->read_buffer->buffer()->buffer().get(), hardware_buffer);
 }
 
-int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd,
-                         void* meta, size_t meta_size_bytes) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle ready_fence;
-  int result =
-      read_buffer->read_buffer->Acquire(&ready_fence, meta, meta_size_bytes);
-  *ready_fence_fd = ready_fence.Release();
-  return result;
-}
-
-int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle fence(release_fence_fd);
-  int result = read_buffer->read_buffer->Release(fence);
-  return result;
-}
-
-int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  return read_buffer->read_buffer->ReleaseAsync();
-}
-
 void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; }
 
 int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
@@ -196,27 +117,4 @@
   return android::dvr::kSharedBufferLayoutVersion;
 }
 
-const struct native_handle* dvrWriteBufferGetNativeHandle(
-    DvrWriteBuffer* write_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return nullptr;
-
-  return write_buffer->write_buffer->native_handle();
-}
-
-const struct native_handle* dvrReadBufferGetNativeHandle(
-    DvrReadBuffer* read_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return nullptr;
-
-  return read_buffer->read_buffer->native_handle();
-}
-
-const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer) {
-  if (!buffer || !buffer->buffer)
-    return nullptr;
-
-  return buffer->buffer->handle();
-}
-
 }  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 09a49dd..74cee3f 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,7 +2,7 @@
 #include "include/dvr/dvr_buffer_queue.h"
 
 #include <android/native_window.h>
-#include <private/dvr/buffer_hub_queue_producer.h>
+#include <gui/BufferHubProducer.h>
 
 #include "dvr_internal.h"
 #include "dvr_buffer_queue_internal.h"
@@ -10,7 +10,6 @@
 using namespace android;
 using android::dvr::BufferConsumer;
 using android::dvr::BufferHubBuffer;
-using android::dvr::BufferHubQueueProducer;
 using android::dvr::BufferProducer;
 using android::dvr::ConsumerQueue;
 using android::dvr::ProducerQueue;
@@ -30,8 +29,7 @@
   if (native_window_ == nullptr) {
     // Lazy creation of |native_window|, as not everyone is using
     // DvrWriteBufferQueue as an external surface.
-    sp<IGraphicBufferProducer> gbp =
-        BufferHubQueueProducer::Create(producer_queue_);
+    sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
     native_window_ = new Surface(gbp, true);
   }
 
@@ -275,14 +273,6 @@
   return write_queue->id();
 }
 
-int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                          ANativeWindow** out_window) {
-  ALOGW(
-      "dvrWriteBufferQueueGetExternalSurface: This API has been deprecated and "
-      "renamed to dvrWriteBufferQueueGetANativeWindow.");
-  return dvrWriteBufferQueueGetANativeWindow(write_queue, out_window);
-}
-
 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
                                         ANativeWindow** out_window) {
   if (!write_queue || !out_window)
@@ -299,15 +289,6 @@
   return write_queue->CreateReadQueue(out_read_queue);
 }
 
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
-                               DvrWriteBuffer* write_buffer,
-                               int* out_fence_fd) {
-  if (!write_queue || !write_buffer || !out_fence_fd)
-    return -EINVAL;
-
-  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
-}
-
 int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
                                   DvrWriteBuffer** out_write_buffer,
                                   DvrNativeBufferMetadata* out_meta,
@@ -357,34 +338,6 @@
   return 0;
 }
 
-int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
-                                int* out_fence_fd, void* out_meta,
-                                size_t meta_size_bytes) {
-  if (meta_size_bytes != consumer_queue_->metadata_size()) {
-    ALOGE(
-        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
-        "but actual (%zu).",
-        consumer_queue_->metadata_size(), meta_size_bytes);
-    return -EINVAL;
-  }
-
-  size_t slot;
-  pdx::LocalHandle acquire_fence;
-  auto buffer_status = consumer_queue_->Dequeue(
-      timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
-  if (!buffer_status) {
-    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-             "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
-             buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  read_buffer->read_buffer = buffer_status.take();
-  *out_fence_fd = acquire_fence.Release();
-
-  return 0;
-}
-
 int DvrReadBufferQueue::AcquireBuffer(int timeout,
                                       DvrReadBuffer** out_read_buffer,
                                       DvrNativeBufferMetadata* out_meta,
@@ -436,12 +389,22 @@
     return -EINVAL;
   }
   if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
-    ALOGE(
-        "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
-        "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
-        "queue: id=%d",
-        read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
-    return -EINVAL;
+    if (consumer_queue_->GetBufferId(slot) > 0) {
+      ALOGE(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which holds a different buffer "
+          "(buffer_id=%d).",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
+    } else {
+      ALOGI(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which is empty.",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot));
+    }
   }
 
   pdx::LocalHandle fence(release_fence_fd);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 499b7c1..80ffc82 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -443,11 +443,13 @@
 struct DvrApi_v1 {
 // Defines an API entry for V1 (no version suffix).
 #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
+#define DVR_V1_API_ENTRY_DEPRECATED(name) Dvr##name##Ptr name
 
 #include "dvr_api_entries.h"
 
 // Undefine macro definitions to play nice with Google3 style rules.
 #undef DVR_V1_API_ENTRY
+#undef DVR_V1_API_ENTRY_DEPRECATED
 };
 
 int dvrGetApi(void* api, size_t struct_size, int version);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index cce8c7e..f0d8ec6 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -8,6 +8,10 @@
 #error Do not include this header directly.
 #endif
 
+#ifndef DVR_V1_API_ENTRY_DEPRECATED
+#error Do not include this header directly.
+#endif
+
 // Do not delete this line: BEGIN CODEGEN OUTPUT
 // Display manager client
 DVR_V1_API_ENTRY(DisplayManagerCreate);
@@ -32,42 +36,42 @@
 DVR_V1_API_ENTRY(SurfaceStateGetAttributes);
 
 // Write buffer
-DVR_V1_API_ENTRY(WriteBufferCreateEmpty);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferCreateEmpty);
 DVR_V1_API_ENTRY(WriteBufferDestroy);
 DVR_V1_API_ENTRY(WriteBufferIsValid);
-DVR_V1_API_ENTRY(WriteBufferClear);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferClear);
 DVR_V1_API_ENTRY(WriteBufferGetId);
 DVR_V1_API_ENTRY(WriteBufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(WriteBufferPost);
-DVR_V1_API_ENTRY(WriteBufferGain);
-DVR_V1_API_ENTRY(WriteBufferGainAsync);
-DVR_V1_API_ENTRY(WriteBufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferPost);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGain);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGainAsync);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGetNativeHandle);
 
 // Read buffer
-DVR_V1_API_ENTRY(ReadBufferCreateEmpty);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferCreateEmpty);
 DVR_V1_API_ENTRY(ReadBufferDestroy);
 DVR_V1_API_ENTRY(ReadBufferIsValid);
-DVR_V1_API_ENTRY(ReadBufferClear);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferClear);
 DVR_V1_API_ENTRY(ReadBufferGetId);
 DVR_V1_API_ENTRY(ReadBufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(ReadBufferAcquire);
-DVR_V1_API_ENTRY(ReadBufferRelease);
-DVR_V1_API_ENTRY(ReadBufferReleaseAsync);
-DVR_V1_API_ENTRY(ReadBufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferAcquire);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferRelease);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferReleaseAsync);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferGetNativeHandle);
 
 // Buffer
 DVR_V1_API_ENTRY(BufferDestroy);
 DVR_V1_API_ENTRY(BufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(BufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(BufferGetNativeHandle);
 DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet);
 
 // Write buffer queue
 DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
 DVR_V1_API_ENTRY(WriteBufferQueueGetCapacity);
 DVR_V1_API_ENTRY(WriteBufferQueueGetId);
-DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);  // deprecated
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueGetExternalSurface);
 DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
-DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueDequeue);
 DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
 
 // Read buffer queue
@@ -75,7 +79,7 @@
 DVR_V1_API_ENTRY(ReadBufferQueueGetCapacity);
 DVR_V1_API_ENTRY(ReadBufferQueueGetId);
 DVR_V1_API_ENTRY(ReadBufferQueueCreateReadQueue);
-DVR_V1_API_ENTRY(ReadBufferQueueDequeue);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferQueueDequeue);
 DVR_V1_API_ENTRY(ReadBufferQueueSetBufferAvailableCallback);
 DVR_V1_API_ENTRY(ReadBufferQueueSetBufferRemovedCallback);
 DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
index 935a7b2..4234844 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -14,20 +14,12 @@
 typedef struct AHardwareBuffer AHardwareBuffer;
 struct native_handle;
 
-// Creates an empty write buffer that may be filled with an acutal buffer by
-// other functions.
-void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer);
-
 // Destroys the write buffer.
 void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer);
 
 // Returns 1 if the given write buffer object contains a buffer, 0 otherwise.
 int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer);
 
-// Clears the contents of the buffer object. After a call to this function
-// dvrWriteBufferIsValid on the same buffer object returns 0.
-int dvrWriteBufferClear(DvrWriteBuffer* write_buffer);
-
 // Returns the global BufferHub id of this buffer.
 int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer);
 
@@ -36,34 +28,12 @@
 int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer,
                                      AHardwareBuffer** hardware_buffer);
 
-// Posts the buffer, notifying any connected read buffers. Takes ownership of
-// |ready_fence_fd|.
-int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd,
-                       const void* meta, size_t meta_size_bytes);
-
-// Gains a buffer that has been released by all connected read buffers.
-int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd);
-int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer);
-
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrWriteBufferGetNativeHandle(
-    DvrWriteBuffer* write_buffer);
-
-// Creates an empty read buffer that may be filled with and actual buffer by
-// other functions.
-void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer);
-
 // Destroys the read buffer.
 void dvrReadBufferDestroy(DvrReadBuffer* read_buffer);
 
 // Returns 1 if the given write buffer object contains a buffer, 0 otherwise.
 int dvrReadBufferIsValid(DvrReadBuffer* read_buffer);
 
-// Clears the contents of the buffer object. After a call to this function
-// dvrReadBufferIsValid on the same buffer object returns 0.
-int dvrReadBufferClear(DvrReadBuffer* read_buffer);
-
 // Returns the global BufferHub id of this buffer.
 int dvrReadBufferGetId(DvrReadBuffer* read_buffer);
 
@@ -72,21 +42,6 @@
 int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer,
                                     AHardwareBuffer** hardware_buffer);
 
-// Acquires the read buffer after it has been posted by the write buffer it is
-// connected to.
-int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd,
-                         void* meta, size_t meta_size_bytes);
-
-// Releases the read buffer, notifying the write buffer it is connected to.
-// Takes ownership of |release_fence_fd|.
-int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd);
-int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer);
-
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrReadBufferGetNativeHandle(
-    DvrReadBuffer* read_buffer);
-
 // Destroys the buffer.
 void dvrBufferDestroy(DvrBuffer* buffer);
 
@@ -98,10 +53,6 @@
 // Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
 int dvrBufferGlobalLayoutVersionGet();
 
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer);
-
 __END_DECLS
 
 #endif  // ANDROID_DVR_BUFFER_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index bf695c7..ac789da 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -76,10 +76,6 @@
 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
                                         ANativeWindow** out_window);
 
-// @deprecated Please use dvrWriteBufferQueueGetANativeWindow instead.
-int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                          ANativeWindow** out_window);
-
 // Create a read buffer queue from an existing write buffer queue.
 //
 // @param write_queue The DvrWriteBufferQueue of interest.
@@ -89,10 +85,6 @@
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
 
-// @deprecated Please use dvrWriteBufferQueueGainBuffer instead.
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
-                               DvrWriteBuffer* out_buffer, int* out_fence_fd);
-
 // Gains a buffer to write into.
 //
 // @param write_queue The DvrWriteBufferQueue to gain buffer from.
@@ -176,11 +168,6 @@
 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                       DvrReadBufferQueue** out_read_queue);
 
-// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead.
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* out_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes);
-
 // Dequeues a buffer to read from.
 //
 // @param read_queue The DvrReadBufferQueue to acquire buffer from.
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_types.h b/libs/vr/libdvr/include/dvr/dvr_display_types.h
index 25364d8..fd69843 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_types.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_types.h
@@ -13,7 +13,7 @@
 #ifndef __FLOAT32X4T_86
 #define __FLOAT32X4T_86
 typedef float float32x4_t __attribute__((__vector_size__(16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; };
+typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
 #endif
 #endif
 
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 887766a..1ae75fb 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -15,6 +15,7 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
@@ -22,22 +23,19 @@
     "libui",
     "libutils",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
     "libdvr_static",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
     "libdisplay",
-    "libpdx_default_transport",
     "libbroadcastring",
 ]
 
 cc_test {
     srcs: [
-        "dvr_buffer_queue-test.cpp",
         "dvr_display_manager-test.cpp",
         "dvr_named_buffer-test.cpp",
     ],
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
new file mode 100644
index 0000000..0f3840d
--- /dev/null
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -0,0 +1,73 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# TODO(b/73133405): Currently, building cc_test against NDK using Android.bp
+# doesn't work well. Migrate to use Android.bp once b/73133405 gets fixed.
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= dvr_buffer_queue-test
+
+# Includes the dvr_api.h header. Tests should only include "dvr_api.h",
+# and shall only get access to |dvrGetApi|, as other symbols are hidden from the
+# library.
+LOCAL_C_INCLUDES := \
+    frameworks/native/libs/vr/libdvr/include \
+
+LOCAL_SANITIZE := thread
+
+LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid \
+    liblog \
+
+LOCAL_CFLAGS := \
+    -DTRACE=0 \
+    -O2 \
+    -g \
+
+# DTS Should only link to NDK libraries.
+LOCAL_SDK_VERSION := 26
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_NATIVE_TEST)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= dvr_display-test
+
+LOCAL_C_INCLUDES := \
+    frameworks/native/libs/vr/libdvr/include \
+    frameworks/native/libs/nativewindow/include
+
+LOCAL_SANITIZE := thread
+
+LOCAL_SRC_FILES := dvr_display-test.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid \
+    liblog
+
+LOCAL_CFLAGS := \
+    -DTRACE=0 \
+    -O2 \
+    -g
+
+# DTS Should only link to NDK libraries.
+LOCAL_SDK_VERSION := 26
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_NATIVE_TEST)
\ No newline at end of file
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
new file mode 100644
index 0000000..d8359e7
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_api_test.h
@@ -0,0 +1,36 @@
+#include <dlfcn.h>
+#include <dvr/dvr_api.h>
+
+#include <gtest/gtest.h>
+
+/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
+class DvrApiTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    int flags = RTLD_NOW | RTLD_LOCAL;
+
+    // Here we need to ensure that libdvr is loaded with RTLD_NODELETE flag set
+    // (so that calls to `dlclose` don't actually unload the library). This is a
+    // workaround for an Android NDK bug. See more detail:
+    // https://github.com/android-ndk/ndk/issues/360
+    flags |= RTLD_NODELETE;
+    platform_handle_ = dlopen("libdvr.so", flags);
+    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
+
+    auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
+        dlsym(platform_handle_, "dvrGetApi"));
+    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
+
+    ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
+        << "Unable to find compatible Dvr API.";
+  }
+
+  void TearDown() override {
+    if (platform_handle_ != nullptr) {
+      dlclose(platform_handle_);
+    }
+  }
+
+  void* platform_handle_ = nullptr;
+  DvrApi_v1 api_;
+};
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 62cd8d4..2d5f004 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,6 +1,5 @@
 #include <android/log.h>
 #include <android/native_window.h>
-#include <android-base/unique_fd.h>
 #include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer_queue.h>
 
@@ -9,6 +8,10 @@
 #include <array>
 #include <unordered_map>
 
+#include "dvr_api_test.h"
+
+#define LOG_TAG "dvr_buffer_queue-test"
+
 #ifndef ALOGD
 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #endif
@@ -27,7 +30,7 @@
 static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
 static constexpr size_t kQueueCapacity = 3;
 
-class DvrBufferQueueTest : public ::testing::Test {
+class DvrBufferQueueTest : public DvrApiTest {
  public:
   static void BufferAvailableCallback(void* context) {
     DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
@@ -42,9 +45,10 @@
  protected:
   void TearDown() override {
     if (write_queue_ != nullptr) {
-      dvrWriteBufferQueueDestroy(write_queue_);
+      api_.WriteBufferQueueDestroy(write_queue_);
       write_queue_ = nullptr;
     }
+    DvrApiTest::TearDown();
   }
 
   void HandleBufferAvailable() {
@@ -64,85 +68,85 @@
 };
 
 TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  dvrWriteBufferQueueDestroy(write_queue_);
+  api_.WriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
 TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+  size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_);
 
   ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue1);
 
-  ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+  ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue2);
   ASSERT_NE(read_queue1, read_queue2);
 
-  dvrReadBufferQueueDestroy(read_queue1);
-  dvrReadBufferQueueDestroy(read_queue2);
+  api_.ReadBufferQueueDestroy(read_queue1);
+  api_.ReadBufferQueueDestroy(read_queue2);
 }
 
 TEST_F(DvrBufferQueueTest, GainBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
 
   DvrWriteBuffer* wb = nullptr;
-  EXPECT_FALSE(dvrWriteBufferIsValid(wb));
+  EXPECT_FALSE(api_.WriteBufferIsValid(wb));
 
   DvrNativeBufferMetadata meta;
   int fence_fd = -1;
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+                                        &fence_fd);
   ASSERT_EQ(ret, 0);
   EXPECT_EQ(fence_fd, -1);
   EXPECT_NE(wb, nullptr);
-  EXPECT_TRUE(dvrWriteBufferIsValid(wb));
+  EXPECT_TRUE(api_.WriteBufferIsValid(wb));
 }
 
 TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
@@ -154,40 +158,40 @@
   DvrNativeBufferMetadata meta2;
   int fence_fd = -1;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(ret, 0);
   ASSERT_NE(read_queue, nullptr);
 
-  dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
-                                               &BufferAvailableCallback, this);
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
 
   // Gain buffer for writing.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(wb, nullptr);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb));
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
            wb, fence_fd);
-  android::base::unique_fd release_fence(fence_fd);
+  close(fence_fd);
 
   // Post buffer to the read_queue.
   meta1.timestamp = 42;
-  ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrWriteBufferIsValid(wb));
+  ASSERT_FALSE(api_.WriteBufferIsValid(wb));
   wb = nullptr;
 
   // Acquire buffer for reading.
-  ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2,
-                                        &fence_fd);
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(rb, nullptr);
 
   // Dequeue is successfully, BufferAvailableCallback should be fired once.
   ASSERT_EQ(buffer_available_count_, 1);
-  ASSERT_TRUE(dvrReadBufferIsValid(rb));
+  ASSERT_TRUE(api_.ReadBufferIsValid(rb));
 
   // Metadata should be passed along from producer to consumer properly.
   ASSERT_EQ(meta1.timestamp, meta2.timestamp);
@@ -195,34 +199,34 @@
   ALOGD_IF(TRACE,
            "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
            fence_fd);
-  android::base::unique_fd acquire_fence(fence_fd);
+  close(fence_fd);
 
   // Release buffer to the write_queue.
-  ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
-                                        /*release_fence_fd=*/-1);
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrReadBufferIsValid(rb));
+  ASSERT_FALSE(api_.ReadBufferIsValid(rb));
   rb = nullptr;
 
   // TODO(b/34387835) Currently buffer allocation has to happen after all queues
   // are initialized.
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
 
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, GetANativeWindow) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+      /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, write_queue_);
 
   ANativeWindow* window = nullptr;
-  ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
+  ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, window);
 
@@ -238,7 +242,7 @@
 // Before each dequeue operation, we resize the buffer queue and expect the
 // queue always return buffer with desired dimension.
 TEST_F(DvrBufferQueueTest, ResizeBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
@@ -255,37 +259,37 @@
   AHardwareBuffer* ahb3 = nullptr;
   AHardwareBuffer_Desc buffer_desc;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
-                                             this);
+  api_.ReadBufferQueueSetBufferRemovedCallback(read_queue,
+                                               &BufferRemovedCallback, this);
 
   // Handle all pending events on the read queue.
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
   ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
   // Resize before dequeuing.
   constexpr uint32_t w1 = 10;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // Gain first buffer for writing. All buffers will be resized.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb1));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
-  android::base::unique_fd release_fence1(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension.
-  ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb1, &buffer_desc);
   ASSERT_EQ(w1, buffer_desc.width);
@@ -294,26 +298,26 @@
 
   // For the first resize, all buffers are reallocated.
   int expected_buffer_removed_count = kQueueCapacity;
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue. We are testing with blob format, keep height to be 1.
   constexpr uint32_t w2 = 20;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb2));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
            fence_fd);
-  android::base::unique_fd release_fence2(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb2, &buffer_desc);
   ASSERT_EQ(w2, buffer_desc.width);
@@ -321,26 +325,26 @@
 
   // For the second resize, all but one buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 1);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue for the third time.
   constexpr uint32_t w3 = 30;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb3));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
            fence_fd);
-  android::base::unique_fd release_fence3(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb3, &buffer_desc);
   ASSERT_EQ(w3, buffer_desc.width);
@@ -348,26 +352,26 @@
 
   // For the third resize, all but two buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 2);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+  int event_fd = api_.ReadBufferQueueGetEventFd(read_queue);
   ASSERT_GT(event_fd, 0);
 }
 
@@ -375,14 +379,14 @@
 // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
 // the corresponding AHardwareBuffer handle stays the same.
 TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   int fence_fd = -1;
   DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+  EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
 
   // Read buffers.
   std::array<DvrReadBuffer*, kQueueCapacity> rbs;
@@ -400,16 +404,16 @@
   // This test runs the following operations many many times. Thus we prefer to
   // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
   std::function<void(size_t i)> Gain = [&](size_t i) {
-    int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
-                                            &wbs[i], &metas[i], &fence_fd);
+    int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
+                                              &wbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
-    int buffer_id = dvrWriteBufferGetId(wbs[i]);
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
+    int buffer_id = api_.WriteBufferGetId(wbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb));
+    ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb));
 
     auto whb_it = whbs.find(buffer_id);
     if (whb_it == whbs.end()) {
@@ -425,26 +429,26 @@
   };
 
   std::function<void(size_t i)> Post = [&](size_t i) {
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
 
     metas[i].timestamp++;
-    int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
-                                            /*fence=*/-1);
+    int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+                                              /*fence=*/-1);
     ASSERT_EQ(ret, 0);
   };
 
   std::function<void(size_t i)> Acquire = [&](size_t i) {
-    int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
-                                              &rbs[i], &metas[i], &fence_fd);
+    int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
+                                                &rbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int buffer_id = dvrReadBufferGetId(rbs[i]);
+    int buffer_id = api_.ReadBufferGetId(rbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb));
+    ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb));
 
     auto rhb_it = rhbs.find(buffer_id);
     if (rhb_it == rhbs.end()) {
@@ -460,10 +464,10 @@
   };
 
   std::function<void(size_t i)> Release = [&](size_t i) {
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
-                                              /*release_fence_fd=*/-1);
+    int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+                                                /*release_fence_fd=*/-1);
     ASSERT_EQ(ret, 0);
   };
 
@@ -521,4 +525,55 @@
   }
 }
 
+TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
+  int ret = api_.WriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(ret, 0);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  DvrNativeBufferMetadata meta1;
+  DvrNativeBufferMetadata meta2;
+  int fence_fd = -1;
+
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ASSERT_EQ(ret, 0);
+
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
+
+  // Gain buffer for writing.
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Post buffer to the read_queue.
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ASSERT_EQ(ret, 0);
+  wb = nullptr;
+
+  // Acquire buffer for reading.
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Destroy the write buffer queue and make sure the reader queue is picking
+  // these events up.
+  api_.WriteBufferQueueDestroy(write_queue_);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+
+  // Release buffer to the write_queue.
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
+  ASSERT_EQ(ret, 0);
+  rb = nullptr;
+
+  api_.ReadBufferQueueDestroy(read_queue);
+}
+
 }  // namespace
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
new file mode 100644
index 0000000..c72f940
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_display-test.cpp
@@ -0,0 +1,351 @@
+#include <android/hardware_buffer.h>
+#include <android/log.h>
+#include <dvr/dvr_api.h>
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_surface.h>
+
+#include <gtest/gtest.h>
+
+#include "dvr_api_test.h"
+
+#define LOG_TAG "dvr_display-test"
+
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+class DvrDisplayTest : public DvrApiTest {
+ protected:
+  void SetUp() override {
+    DvrApiTest::SetUp();
+    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
+                                           &display_metrics_);
+    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
+    ALOGD(
+        "display_width: %d, display_height: %d, display_x_dpi: %d, "
+        "display_y_dpi: %d, vsync_period_ns: %d.",
+        display_metrics_.display_width, display_metrics_.display_height,
+        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
+        display_metrics_.vsync_period_ns);
+  }
+
+  void TearDown() override {
+    if (write_queue_ != nullptr) {
+      api_.WriteBufferQueueDestroy(write_queue_);
+      write_queue_ = nullptr;
+    }
+    if (direct_surface_ != nullptr) {
+      api_.SurfaceDestroy(direct_surface_);
+      direct_surface_ = nullptr;
+    }
+    DvrApiTest::TearDown();
+  }
+
+  /* Convert a write buffer to an android hardware buffer and fill in
+   * color_textures evenly to the buffer.
+   * AssertionError if the width of the buffer is not equal to the input width,
+   * AssertionError if the height of the buffer is not equal to the input
+   * height.
+   */
+  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
+                       const std::vector<uint32_t>& color_textures,
+                       uint32_t width, uint32_t height);
+
+  // Write buffer queue properties.
+  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+  static constexpr size_t kMetadataSize = 0;
+  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
+  uint32_t kLayerCount = 1;
+  DvrWriteBufferQueue* write_queue_ = nullptr;
+  DvrSurface* direct_surface_ = nullptr;
+
+  // Device display properties.
+  DvrNativeDisplayMetrics display_metrics_;
+};
+
+TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  // Get buffer from WriteBufferQueue.
+  DvrWriteBuffer* write_buffer = nullptr;
+  DvrNativeBufferMetadata out_meta;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
+                                        &out_meta, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
+
+  // Color the write buffer.
+  FillWriteBuffer(write_buffer,
+                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
+                  width, height);
+
+  // Post buffer.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                        ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three primary colors on the screen center.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 2;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
+  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
+  int bufferhub_id_prev_write_buffer = -1;
+  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
+    // Get a buffer from the WriteBufferQueue.
+    DvrWriteBuffer* write_buffer = nullptr;
+    DvrNativeBufferMetadata out_meta;
+    int out_fence_fd = -1;
+    ret = api_.WriteBufferQueueGainBuffer(
+        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
+    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
+
+    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
+    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
+          bufferhub_id);
+    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
+        << "Double buffering should be using the two buffers in turns, not "
+           "reusing the same write buffer.";
+    bufferhub_id_prev_write_buffer = bufferhub_id;
+
+    // Color the write buffer.
+    if (i % 2) {
+      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                      height);
+    } else {
+      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
+                      height);
+    }
+
+    // Post the write buffer.
+    int ready_fence_fd = -1;
+    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                          ready_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+  }
+  // Should observe blinking screen in secondary colors
+  // although it is actually displaying primary colors.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
+  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
+  // order 11.
+  DvrSurface* direct_surface_0 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_0_attributes.data(),
+                         direct_surface_0_attributes.size(), &direct_surface_0);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  DvrSurface* direct_surface_1 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 11},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  ret =
+      api_.SurfaceCreate(direct_surface_1_attributes.data(),
+                         direct_surface_1_attributes.size(), &direct_surface_1);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue for each of the direct surfaces.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+
+  DvrWriteBufferQueue* write_queue_0 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_0);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
+
+  DvrWriteBufferQueue* write_queue_1 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_1);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
+
+  // Get a buffer from each of the write buffer queues.
+  DvrWriteBuffer* write_buffer_0 = nullptr;
+  DvrNativeBufferMetadata out_meta_0;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
+
+  DvrWriteBuffer* write_buffer_1 = nullptr;
+  DvrNativeBufferMetadata out_meta_1;
+  out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
+
+  // Color the write buffers.
+  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                  height);
+  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
+                  height);
+
+  // Post buffers.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
+                                        &out_meta_0, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
+                                        &out_meta_1, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three secondary colors.
+
+  // Test finished. Clean up buffers and surfaces.
+  if (write_queue_0 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_0);
+    write_queue_0 = nullptr;
+  }
+  if (write_queue_1 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_1);
+    write_queue_1 = nullptr;
+  }
+  if (direct_surface_0 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_0);
+  }
+  if (direct_surface_1 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_1);
+  }
+}
+
+void DvrDisplayTest::FillWriteBuffer(
+    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
+    uint32_t width, uint32_t height) {
+  uint32_t num_colors = color_textures.size();
+  // Convert the first write buffer to an android hardware buffer.
+  AHardwareBuffer* ah_buffer = nullptr;
+  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
+  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
+  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
+  AHardwareBuffer_Desc ah_buffer_describe;
+  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
+  ASSERT_EQ(ah_buffer_describe.format, kFormat)
+      << "The format of the android hardware buffer is wrong.";
+  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
+      << "The obtained android hardware buffer should have 2 layers.";
+  ASSERT_EQ(ah_buffer_describe.width, width)
+      << "The obtained android hardware buffer width is wrong.";
+  ASSERT_EQ(ah_buffer_describe.height, height)
+      << "The obtained android hardware buffer height is wrong.";
+  // Change the content of the android hardware buffer.
+  void* buffer_data = nullptr;
+  int32_t fence = -1;
+  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                             fence, nullptr, &buffer_data);
+  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
+  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
+
+  uint32_t num_pixels = width * height / num_colors;
+  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
+    uint32_t color_texture = color_textures[color_index];
+    for (uint32_t i = 0; i < num_pixels; ++i) {
+      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                     (i + num_pixels * color_index) *
+                                         sizeof(color_texture)),
+             &color_texture, sizeof(color_texture));
+    }
+  }
+  uint32_t color_texture = color_textures[num_colors - 1];
+  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
+  num_pixels = width * height - num_colored_pixels;
+  for (uint32_t i = 0; i < num_pixels; ++i) {
+    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                   (i + num_colored_pixels) *
+                                       sizeof(color_texture)),
+           &color_texture, sizeof(color_texture));
+  }
+  fence = -1;
+  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
+  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
+
+  // Release the android hardware buffer.
+  AHardwareBuffer_release(ah_buffer);
+}
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index f83b26e..c9a5c09 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -845,10 +845,10 @@
   ASSERT_NE(nullptr, write_queue.get());
 
   DvrWriteBuffer* buffer = nullptr;
-  dvrWriteBufferCreateEmpty(&buffer);
+  DvrNativeBufferMetadata metadata;
   int fence_fd = -1;
-  int error =
-      dvrWriteBufferQueueDequeue(write_queue.get(), 1000, buffer, &fence_fd);
+  int error = dvrWriteBufferQueueGainBuffer(write_queue.get(), /*timeout=*/1000,
+                                            &buffer, &metadata, &fence_fd);
   ASSERT_EQ(0, error);
 
   AHardwareBuffer* hardware_buffer = nullptr;
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index c21deb0..5c837e7 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -5,7 +5,6 @@
 #include <dvr/dvr_surface.h>
 #include <system/graphics.h>
 
-#include <base/logging.h>
 #include <gtest/gtest.h>
 
 namespace android {
@@ -22,7 +21,7 @@
 
   DvrBuffer* buffer2 = nullptr;
   int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
-  ASSERT_EQ(0, ret1);
+  ASSERT_EQ(0, ret2);
   ASSERT_NE(nullptr, buffer2);
 
   AHardwareBuffer* hardware_buffer1 = nullptr;
@@ -159,7 +158,7 @@
     ASSERT_EQ(0, e3);
     ASSERT_NE(nullptr, buffer);
     // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
     uint64_t* data = static_cast<uint64_t*>(buffer);
     constexpr size_t num_values = size / sizeof(uint64_t);
@@ -192,7 +191,7 @@
     ASSERT_EQ(0, e3);
     ASSERT_NE(nullptr, buffer);
     // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
     uint64_t* data = static_cast<uint64_t*>(buffer);
     constexpr size_t num_values = size / sizeof(uint64_t);
@@ -233,7 +232,7 @@
   ASSERT_EQ(0, e3);
   ASSERT_NE(nullptr, buffer);
   // Verify that the buffer pointer is at least 16 byte aligned.
-  ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
   uint64_t* data = static_cast<uint64_t*>(buffer);
   constexpr size_t num_values = size / sizeof(uint64_t);
@@ -241,7 +240,7 @@
   for (size_t i = 0; i < num_values; ++i) {
     zero |= data[i];
   }
-  ASSERT_EQ(0, zero);
+  ASSERT_EQ(0U, zero);
 
   int32_t fence = -1;
   int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 62aeb79..32b793a 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -26,9 +26,10 @@
     "libui",
     "libgui",
     "libhardware",
+    "libpdx_default_transport",
 ]
 
-staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
+staticLibraries = ["libbroadcastring"]
 
 headerLibraries = [
     "libeigen",
@@ -40,6 +41,8 @@
     cflags: [
         "-DLOG_TAG=\"libdvrcommon\"",
         "-DTRACE=0",
+        "-Wall",
+        "-Werror",
     ],
     export_include_dirs: localIncludeFiles,
 
@@ -59,6 +62,11 @@
     tags: ["optional"],
 
     srcs: testFiles,
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
 
     shared_libs: sharedLibraries,
 
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 10c0b31..1a9d727 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -1,3 +1,9 @@
+cc_library_headers {
+    name: "libpdx_headers",
+    export_include_dirs: ["private"],
+    vendor_available: true,
+}
+
 cc_library_static {
     name: "libpdx",
     clang: true,
@@ -8,14 +14,20 @@
         "-DLOG_TAG=\"libpdx\"",
         "-DTRACE=0",
     ],
-    export_include_dirs: ["private"],
-    local_include_dirs: ["private"],
+    header_libs: ["libpdx_headers"],
+    export_header_lib_headers: ["libpdx_headers"],
     srcs: [
         "client.cpp",
         "service.cpp",
         "service_dispatcher.cpp",
         "status.cpp",
     ],
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+    ],
 }
 
 cc_test {
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index a01c4d6..3c66a40 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -119,6 +119,10 @@
   return channel_->GetChannelHandle();
 }
 
+const LocalChannelHandle& Client::GetChannelHandle() const {
+  return channel_->GetChannelHandle();
+}
+
 ///////////////////////////// Transaction implementation //////////////////////
 
 Transaction::Transaction(Client& client) : client_{client} {}
diff --git a/libs/vr/libpdx/private/pdx/channel_parcelable.h b/libs/vr/libpdx/private/pdx/channel_parcelable.h
new file mode 100644
index 0000000..59ef9d3
--- /dev/null
+++ b/libs/vr/libpdx/private/pdx/channel_parcelable.h
@@ -0,0 +1,31 @@
+#ifndef ANDROID_PDX_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_CHANNEL_PARCELABLE_H_
+
+#include <binder/Parcelable.h>
+#include <pdx/channel_handle.h>
+
+namespace android {
+namespace pdx {
+
+/**
+ * A parcelable object holds all necessary objects to recreate a ClientChannel.
+ * In addition to the android::Parcelable interface, this interface exposees
+ * more PDX-related interface.
+ */
+class ChannelParcelable : public Parcelable {
+ public:
+  virtual ~ChannelParcelable() = default;
+
+  // Returns whether the parcelable object holds a valid client channel.
+  virtual bool IsValid() const = 0;
+
+  // Returns a channel handle constructed from this parcelable object and takes
+  // the ownership of all resources from the parcelable object. In another word,
+  // the parcelable object will become invalid after TakeChannelHandle returns.
+  virtual LocalChannelHandle TakeChannelHandle() = 0;
+};
+
+}  // namespace pdx
+}  // namespace android
+
+#endif  // ANDROID_PDX_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h
index 656de7e..c35dabd 100644
--- a/libs/vr/libpdx/private/pdx/client.h
+++ b/libs/vr/libpdx/private/pdx/client.h
@@ -49,6 +49,7 @@
 
   // Returns a reference to IPC channel handle.
   LocalChannelHandle& GetChannelHandle();
+  const LocalChannelHandle& GetChannelHandle() const;
 
  protected:
   friend Transaction;
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h
index 10a49bb..f33a60e 100644
--- a/libs/vr/libpdx/private/pdx/client_channel.h
+++ b/libs/vr/libpdx/private/pdx/client_channel.h
@@ -4,6 +4,7 @@
 #include <vector>
 
 #include <pdx/channel_handle.h>
+#include <pdx/channel_parcelable.h>
 #include <pdx/file_handle.h>
 #include <pdx/status.h>
 
@@ -32,6 +33,7 @@
   virtual std::vector<EventSource> GetEventSources() const = 0;
 
   virtual LocalChannelHandle& GetChannelHandle() = 0;
+  virtual const LocalChannelHandle& GetChannelHandle() const = 0;
   virtual void* AllocateTransactionState() = 0;
   virtual void FreeTransactionState(void* state) = 0;
 
@@ -61,6 +63,11 @@
                              LocalHandle* handle) const = 0;
   virtual bool GetChannelHandle(void* transaction_state, ChannelReference ref,
                                 LocalChannelHandle* handle) const = 0;
+
+  // Returns the internal state of the channel as a parcelable object. The
+  // ClientChannel is invalidated however, the channel is kept alive by the
+  // parcelable object and may be transferred to another process.
+  virtual std::unique_ptr<ChannelParcelable> TakeChannelParcelable() = 0;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h
index 49e0682..b1a1299 100644
--- a/libs/vr/libpdx/private/pdx/mock_client_channel.h
+++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h
@@ -14,6 +14,7 @@
   MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>());
   MOCK_METHOD1(GetEventMask, Status<int>(int));
   MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&());
+  MOCK_CONST_METHOD0(GetChannelHandle, const LocalChannelHandle&());
   MOCK_METHOD0(AllocateTransactionState, void*());
   MOCK_METHOD1(FreeTransactionState, void(void* state));
   MOCK_METHOD3(SendImpulse,
@@ -49,6 +50,7 @@
   MOCK_CONST_METHOD3(GetChannelHandle,
                      bool(void* transaction_state, ChannelReference ref,
                           LocalChannelHandle* handle));
+  MOCK_METHOD0(TakeChannelParcelable, std::unique_ptr<ChannelParcelable>());
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 80b1769..2cc9664 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -450,12 +450,19 @@
   Variant(Variant&& other)
       : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
 
+// Recent Clang versions has a regression that produces bogus
+// unused-lambda-capture warning. Suppress the warning as a temporary
+// workaround. http://b/71356631
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-lambda-capture"
   // Copy and move construction from Variant types. Each element of OtherTypes
   // must be convertible to an element of Types.
   template <typename... OtherTypes>
   explicit Variant(const Variant<OtherTypes...>& other) {
     other.Visit([this](const auto& value) { Construct(value); });
   }
+#pragma clang diagnostic pop
+
   template <typename... OtherTypes>
   explicit Variant(Variant<OtherTypes...>&& other) {
     other.Visit([this](auto&& value) { Construct(std::move(value)); });
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 0d30614..13aa3e9 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -589,6 +589,14 @@
   }
 
   /*
+   * Return true if a channel with the given ID exists in the Channel map.
+   */
+  bool HasChannelId(int channel_id) const {
+    std::lock_guard<std::mutex> autolock(channels_mutex_);
+    return channels_.find(channel_id) != channels_.end();
+  }
+
+  /*
    * Subclasses of Service may override this method to provide a text string
    * describing the state of the service. This method is called by
    * HandleSystemMessage in response to the standard
diff --git a/libs/vr/libpdx/service_tests.cpp b/libs/vr/libpdx/service_tests.cpp
index c7412b7..e623abf 100644
--- a/libs/vr/libpdx/service_tests.cpp
+++ b/libs/vr/libpdx/service_tests.cpp
@@ -180,8 +180,8 @@
   EXPECT_EQ(kTestTid, message.GetThreadId());
   EXPECT_EQ(kTestCid, message.GetChannelId());
   EXPECT_EQ(kTestMid, message.GetMessageId());
-  EXPECT_EQ(kTestEuid, message.GetEffectiveUserId());
-  EXPECT_EQ(kTestEgid, message.GetEffectiveGroupId());
+  EXPECT_EQ((unsigned) kTestEuid, message.GetEffectiveUserId());
+  EXPECT_EQ((unsigned) kTestEgid, message.GetEffectiveGroupId());
   EXPECT_EQ(kTestOp, message.GetOp());
   EXPECT_EQ(service_, message.GetService());
   EXPECT_EQ(test_channel, message.GetChannel());
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index f891c59..74b8c8b 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -26,13 +26,21 @@
     whole_static_libs: ["libpdx_uds"],
 }
 
-cc_library_static {
+cc_library_shared {
     name: "libpdx_default_transport",
     defaults: [
         "pdx_default_transport_compiler_defaults",
         "pdx_default_transport_lib_defaults",
         "pdx_use_transport_uds",
     ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libcrypto",
+    ],
 }
 
 cc_binary {
@@ -42,10 +50,9 @@
         "pdx_tool.cpp",
     ],
     shared_libs: [
+        "libbinder",
         "libcutils",
         "liblog",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
@@ -59,12 +66,11 @@
     ],
     shared_libs: [
         "libbase",
+        "libbinder",
         "libchrome",
         "libcutils",
         "liblog",
         "libutils",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..a8623b2
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+
+#include <servicefs/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::servicefs::ChannelParcelable;
+
+}  // namespace default_transport
+}  // namespace pdx
+}  // namespace android
+
+
+#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..bcd74e6
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+
+#include <uds/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::uds::ChannelParcelable;
+
+}  // namespace default_transport
+}  // namespace pdx
+}  // namespace android
+
+
+#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index d0b7cab..d640950 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "channel_event_set.cpp",
         "channel_manager.cpp",
+        "channel_parcelable.cpp",
         "client_channel_factory.cpp",
         "client_channel.cpp",
         "ipc_helper.cpp",
@@ -23,6 +24,9 @@
         "libbase",
         "libpdx",
     ],
+    shared_libs: [
+        "libbinder",
+    ],
     whole_static_libs: [
         "libselinux",
     ],
@@ -52,5 +56,6 @@
         "libcutils",
         "liblog",
         "libutils",
+        "libbinder",
     ],
 }
diff --git a/libs/vr/libpdx_uds/channel_parcelable.cpp b/libs/vr/libpdx_uds/channel_parcelable.cpp
new file mode 100644
index 0000000..e7bce27
--- /dev/null
+++ b/libs/vr/libpdx_uds/channel_parcelable.cpp
@@ -0,0 +1,125 @@
+#include "uds/channel_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <uds/channel_manager.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+namespace {
+
+static constexpr uint32_t kUdsMagicParcelHeader = 0x7564736d;  // 'udsm'.
+
+}  // namespace
+
+ChannelParcelable::ChannelParcelable(LocalHandle data_fd,
+                                     LocalHandle pollin_event_fd,
+                                     LocalHandle pollhup_event_fd)
+    : data_fd_{std::move(data_fd)},
+      pollin_event_fd_{std::move(pollin_event_fd)},
+      pollhup_event_fd_{std::move(pollhup_event_fd)} {}
+
+bool ChannelParcelable::IsValid() const {
+  return !!data_fd_ && !!pollin_event_fd_ && !!pollhup_event_fd_;
+}
+
+LocalChannelHandle ChannelParcelable::TakeChannelHandle() {
+  if (!IsValid()) {
+    ALOGE("ChannelParcelable::TakeChannelHandle: Invalid channel parcel.");
+    return {};  // Returns an empty channel handle.
+  }
+
+  return ChannelManager::Get().CreateHandle(std::move(data_fd_),
+                                            std::move(pollin_event_fd_),
+                                            std::move(pollhup_event_fd_));
+}
+
+status_t ChannelParcelable::writeToParcel(Parcel* parcel) const {
+  status_t res = NO_ERROR;
+
+  if (!IsValid()) {
+    ALOGE("ChannelParcelable::writeToParcel: Invalid channel parcel.");
+    return BAD_VALUE;
+  }
+
+  res = parcel->writeUint32(kUdsMagicParcelHeader);
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::writeToParcel: Cannot write magic: res=%d.", res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(data_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::writeToParcel: Cannot write data fd: res=%d.",
+          res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(pollin_event_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE(
+        "ChannelParcelable::writeToParcel: Cannot write pollin event fd: "
+        "res=%d.",
+        res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(pollhup_event_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE(
+        "ChannelParcelable::writeToParcel: Cannot write pollhup event fd: "
+        "res=%d.",
+        res);
+    return res;
+  }
+
+  return res;
+}
+
+status_t ChannelParcelable::readFromParcel(const Parcel* parcel) {
+  uint32_t magic = 0;
+  status_t res = NO_ERROR;
+
+  if (IsValid()) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: This channel parcel is already "
+        "initailzied.");
+    return ALREADY_EXISTS;
+  }
+
+  res = parcel->readUint32(&magic);
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::readFromParcel: Failed to read magic: res=%d.",
+          res);
+    return res;
+  }
+
+  if (magic != kUdsMagicParcelHeader) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: Unknown magic: 0x%x, epxected: "
+        "0x%x",
+        magic, kUdsMagicParcelHeader);
+    return BAD_VALUE;
+  }
+
+  // TODO(b/69010509): We have to dup() the FD from android::Parcel as it
+  // doesn't support taking out the FD's ownership. We can remove the dup() here
+  // once android::Parcel support such operation.
+  data_fd_.Reset(dup(parcel->readFileDescriptor()));
+  pollin_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+  pollhup_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+  if (!IsValid()) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: Cannot read fd from parcel: "
+        "data_fd=%d, pollin_event_fd=%d, pollhup_event_fd=%d.",
+        data_fd_.Get(), pollin_event_fd_.Get(), pollhup_event_fd_.Get());
+    return DEAD_OBJECT;
+  }
+
+  return res;
+}
+
+}  // namespace uds
+}  // namespace pdx
+}  // namespace android
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 2e9c1de..6073c3c 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -1,3 +1,4 @@
+#include "uds/channel_parcelable.h"
 #include "uds/client_channel.h"
 
 #include <errno.h>
@@ -292,6 +293,29 @@
   return state->GetLocalChannelHandle(ref, handle);
 }
 
+std::unique_ptr<pdx::ChannelParcelable> ClientChannel::TakeChannelParcelable()
+    {
+  if (!channel_handle_)
+    return nullptr;
+
+  if (auto* channel_data =
+          ChannelManager::Get().GetChannelData(channel_handle_.value())) {
+    auto fds = channel_data->TakeFds();
+    auto parcelable = std::make_unique<ChannelParcelable>(
+        std::move(std::get<0>(fds)), std::move(std::get<1>(fds)),
+        std::move(std::get<2>(fds)));
+
+    // Here we need to explicitly close the channel handle so that the channel
+    // won't get shutdown in the destructor, while the FDs in ChannelParcelable
+    // can keep the channel alive so that new client can be created from it
+    // later.
+    channel_handle_.Close();
+    return parcelable;
+  } else {
+    return nullptr;
+  }
+}
+
 }  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
index 99e7502..e960740 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
@@ -54,6 +54,14 @@
   BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
   BorrowedHandle data_fd() const { return data_fd_.Borrow(); }
 
+  // Moves file descriptors out of ChannelEventReceiver. Note these operations
+  // immediately invalidates the receiver.
+  std::tuple<LocalHandle, LocalHandle, LocalHandle> TakeFds() {
+    epoll_fd_.Close();
+    return {std::move(data_fd_), std::move(pollin_event_fd_),
+            std::move(pollhup_event_fd_)};
+  }
+
   Status<int> GetPendingEvents() const;
   Status<int> PollPendingEvents(int timeout_ms) const;
 
diff --git a/libs/vr/libpdx_uds/private/uds/channel_parcelable.h b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
new file mode 100644
index 0000000..1c3fae9
--- /dev/null
+++ b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
@@ -0,0 +1,35 @@
+#ifndef ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+
+#include <pdx/channel_parcelable.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+class ChannelParcelable : public pdx::ChannelParcelable {
+ public:
+  ChannelParcelable() = default;
+  ChannelParcelable(LocalHandle data_fd, LocalHandle pollin_event_fd,
+                    LocalHandle pollhup_event_fd);
+
+  // Implements pdx::ChannelParcelable interface.
+  bool IsValid() const override;
+  LocalChannelHandle TakeChannelHandle() override;
+
+  // Implements android::Parcelable interface.
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  LocalHandle data_fd_;
+  LocalHandle pollin_event_fd_;
+  LocalHandle pollhup_event_fd_;
+};
+
+}  // namespace uds
+}  // namespace pdx
+}  // namespace android
+
+#endif  // ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 7a5ddf4..3561c6f 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -41,6 +41,9 @@
   }
 
   LocalChannelHandle& GetChannelHandle() override { return channel_handle_; }
+  const LocalChannelHandle& GetChannelHandle() const override {
+    return channel_handle_;
+  }
   void* AllocateTransactionState() override;
   void FreeTransactionState(void* state) override;
 
@@ -74,6 +77,8 @@
   bool GetChannelHandle(void* transaction_state, ChannelReference ref,
                         LocalChannelHandle* handle) const override;
 
+  std::unique_ptr<pdx::ChannelParcelable> TakeChannelParcelable() override;
+
  private:
   explicit ClientChannel(LocalChannelHandle channel_handle);
 
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 0ee77f4..32d40e8 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -594,9 +594,10 @@
 
   if (socket_fd_ && event.data.fd == socket_fd_.Get()) {
     auto status = AcceptConnection(message);
-    if (!status)
-      return status;
-    return ReenableEpollEvent(socket_fd_.Borrow());
+    auto reenable_status = ReenableEpollEvent(socket_fd_.Borrow());
+    if (!reenable_status)
+      return reenable_status;
+    return status;
   }
 
   BorrowedHandle channel_fd{event.data.fd};
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 364873d..35d3dea 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -19,23 +19,24 @@
 
 includeFiles = [ "include" ]
 
-staticLibraries = ["libpdx_default_transport"]
-
 sharedLibraries = [
     "libbase",
+    "libbinder",
     "libcutils",
     "liblog",
     "libutils",
+    "libpdx_default_transport",
 ]
 
 cc_library {
     srcs: sourceFiles,
     cflags: [
         "-DLOG_TAG=\"libperformance\"",
-	"-DTRACE=0"
+        "-DTRACE=0",
+        "-Wall",
+        "-Werror",
     ],
     export_include_dirs: includeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     name: "libperformance",
 }
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 0fb2d84..4dc669b 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -26,16 +26,11 @@
 includeFiles = [ "include" ]
 
 staticLibraries = [
-    "libsurfaceflingerincludes",
-    "libhwcomposer-command-buffer",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdisplay",
     "libdvrcommon",
     "libperformance",
     "libvrsensor",
     "libbroadcastring",
-    "libpdx_default_transport",
     "libvr_manager",
     "libbroadcastring",
 ]
@@ -44,8 +39,10 @@
     "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.composer@2.1",
+    "android.hardware.graphics.composer@2.2",
     "libbinder",
     "libbase",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libhardware",
@@ -61,22 +58,34 @@
     "libhidlbase",
     "libhidltransport",
     "libfmq",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
-    "libdvr_headers"
+    "android.hardware.graphics.composer@2.1-command-buffer",
+    "android.hardware.graphics.composer@2.2-command-buffer",
+    "libdvr_headers",
+    "libsurfaceflinger_headers",
 ]
 
 cc_library_static {
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
 
+    clang: true,
     cflags: [
         "-DLOG_TAG=\"vr_flinger\"",
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+        "-Wno-error=sign-compare", // to fix later
+        "-Wno-unused-variable",
+    ],
+    cppflags: [
+        "-std=c++1z"
     ],
     shared_libs: sharedLibraries,
     whole_static_libs: staticLibraries,
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index ef8cca3..34b3b0a 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -45,6 +45,14 @@
   const int user_id = message.GetEffectiveUserId();
   const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
 
+  // Check if the display_manager_ has a defunct channel.
+  if (display_manager_ && !HasChannelId(display_manager_->channel_id())) {
+    ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with "
+          "no OnChannelClose, clearing prior display manager.",
+          display_manager_->channel_id());
+    display_manager_ = nullptr;
+  }
+
   // Prevent more than one display manager from registering at a time or
   // untrusted UIDs from connecting.
   if (display_manager_ || !trusted) {
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index ac68a5e..87162c0 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -38,10 +38,12 @@
 namespace dvr {
 
 DisplayService::DisplayService(Hwc2::Composer* hidl,
+                               hwc2_display_t primary_display_id,
                                RequestDisplayCallback request_display_callback)
     : BASE("DisplayService",
            Endpoint::Create(display::DisplayProtocol::kClientPath)) {
-  hardware_composer_.Initialize(hidl, request_display_callback);
+    hardware_composer_.Initialize(
+        hidl, primary_display_id, request_display_callback);
 }
 
 bool DisplayService::IsInitialized() const {
@@ -175,12 +177,12 @@
 
 Status<display::Metrics> DisplayService::OnGetMetrics(
     pdx::Message& /*message*/) {
-  return {{static_cast<uint32_t>(GetDisplayMetrics().width),
-           static_cast<uint32_t>(GetDisplayMetrics().height),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.x),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.y),
-           static_cast<uint32_t>(
-               hardware_composer_.native_display_metrics().vsync_period_ns),
+  const auto& params = hardware_composer_.GetPrimaryDisplayParams();
+  return {{static_cast<uint32_t>(params.width),
+           static_cast<uint32_t>(params.height),
+           static_cast<uint32_t>(params.dpi.x),
+           static_cast<uint32_t>(params.dpi.y),
+           static_cast<uint32_t>(params.vsync_period_ns),
            0,
            0,
            0,
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 55e33ab..3090bd1 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -65,12 +65,9 @@
     hardware_composer_.SetVSyncCallback(callback);
   }
 
-  HWCDisplayMetrics GetDisplayMetrics() {
-    return hardware_composer_.display_metrics();
-  }
-
   void GrantDisplayOwnership() { hardware_composer_.Enable(); }
   void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
+  void OnBootFinished() { hardware_composer_.OnBootFinished(); }
 
  private:
   friend BASE;
@@ -81,6 +78,7 @@
   using RequestDisplayCallback = std::function<void(bool)>;
 
   DisplayService(android::Hwc2::Composer* hidl,
+                 hwc2_display_t primary_display_id,
                  RequestDisplayCallback request_display_callback);
 
   pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer(
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index b3da120..44ce78c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -45,14 +45,22 @@
 
 namespace {
 
-const char kBacklightBrightnessSysFile[] =
-    "/sys/class/leds/lcd-backlight/brightness";
-
 const char kDvrPerformanceProperty[] = "sys.dvr.performance";
 const char kDvrStandaloneProperty[] = "ro.boot.vr";
 
 const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
 
+const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
+
+// How long to wait after boot finishes before we turn the display off.
+constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
+
+constexpr int kDefaultDisplayWidth = 1920;
+constexpr int kDefaultDisplayHeight = 1080;
+constexpr int64_t kDefaultVsyncPeriodNs = 16666667;
+// Hardware composer reports dpi as dots per thousand inches (dpi * 1000).
+constexpr int kDefaultDpi = 400000;
+
 // Get time offset from a vsync to when the pose for that vsync should be
 // predicted out to. For example, if scanout gets halfway through the frame
 // at the halfway point between vsyncs, then this could be half the period.
@@ -109,6 +117,11 @@
 #define TRACE_FORMAT(format, ...) \
   TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
 
+// Returns "primary" or "external". Useful for writing more readable logs.
+const char* GetDisplayName(bool is_primary) {
+  return is_primary ? "primary" : "external";
+}
+
 }  // anonymous namespace
 
 HardwareComposer::HardwareComposer()
@@ -121,7 +134,8 @@
 }
 
 bool HardwareComposer::Initialize(
-    Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) {
+    Hwc2::Composer* composer, hwc2_display_t primary_display_id,
+    RequestDisplayCallback request_display_callback) {
   if (initialized_) {
     ALOGE("HardwareComposer::Initialize: already initialized.");
     return false;
@@ -131,42 +145,7 @@
 
   request_display_callback_ = request_display_callback;
 
-  HWC::Error error = HWC::Error::None;
-
-  Hwc2::Config config;
-  error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
-
-  if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer: Failed to get current display config : %d",
-          config);
-    return false;
-  }
-
-  error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config,
-                            &native_display_metrics_);
-
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer: Failed to get display attributes for current "
-        "configuration : %d",
-        error.value);
-    return false;
-  }
-
-  ALOGI(
-      "HardwareComposer: primary display attributes: width=%d height=%d "
-      "vsync_period_ns=%d DPI=%dx%d",
-      native_display_metrics_.width, native_display_metrics_.height,
-      native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
-      native_display_metrics_.dpi.y);
-
-  // Set the display metrics but never use rotation to avoid the long latency of
-  // rotation processing in hwc.
-  display_transform_ = HWC_TRANSFORM_NONE;
-  display_metrics_ = native_display_metrics_;
-
-  // Setup the display metrics used by all Layer instances.
-  Layer::SetDisplayMetrics(native_display_metrics_);
+  primary_display_ = GetDisplayParams(composer, primary_display_id, true);
 
   post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   LOG_ALWAYS_FATAL_IF(
@@ -187,6 +166,21 @@
 
 void HardwareComposer::Disable() {
   UpdatePostThreadState(PostThreadState::Suspended, true);
+
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  post_thread_ready_.wait(lock, [this] {
+    return !post_thread_resumed_;
+  });
+}
+
+void HardwareComposer::OnBootFinished() {
+  std::lock_guard<std::mutex> lock(post_thread_mutex_);
+  if (boot_finished_)
+    return;
+  boot_finished_ = true;
+  post_thread_wait_.notify_one();
+  if (is_standalone_device_)
+    request_display_callback_(true);
 }
 
 // Update the post thread quiescent state based on idle and suspended inputs.
@@ -218,59 +212,65 @@
     eventfd_read(post_thread_event_fd_.Get(), &value);
     post_thread_wait_.notify_one();
   }
+}
 
-  // Wait until the post thread is in the requested state.
-  post_thread_ready_.wait(lock, [this, effective_suspend] {
-    return effective_suspend != post_thread_resumed_;
-  });
+void HardwareComposer::CreateComposer() {
+  if (composer_)
+    return;
+  composer_.reset(new Hwc2::impl::Composer("default"));
+  composer_callback_ = new ComposerCallback;
+  composer_->registerCallback(composer_callback_);
+  LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
+      "Registered composer callback but didn't get hotplug for primary"
+      " display");
 }
 
 void HardwareComposer::OnPostThreadResumed() {
-  // Phones create a new composer client on resume and destroy it on pause.
-  // Standalones only create the composer client once and then use SetPowerMode
-  // to control the screen on pause/resume.
-  if (!is_standalone_device_ || !composer_) {
-    composer_.reset(new Hwc2::Composer(false));
-    composer_callback_ = new ComposerCallback;
-    composer_->registerCallback(composer_callback_);
-    Layer::SetComposer(composer_.get());
-  } else {
-    SetPowerMode(true);
-  }
-
-  EnableVsync(true);
-
-  // TODO(skiazyk): We need to do something about accessing this directly,
-  // supposedly there is a backlight service on the way.
-  // TODO(steventhomas): When we change the backlight setting, will surface
-  // flinger (or something else) set it back to its original value once we give
-  // control of the display back to surface flinger?
-  SetBacklightBrightness(255);
+  ALOGI("OnPostThreadResumed");
+  EnableDisplay(*target_display_, true);
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "performance");
 }
 
 void HardwareComposer::OnPostThreadPaused() {
+  ALOGI("OnPostThreadPaused");
   retire_fence_fds_.clear();
   layers_.clear();
 
-  if (composer_) {
-    EnableVsync(false);
-  }
-
+  // Phones create a new composer client on resume and destroy it on pause.
+  // Standalones only create the composer client once and then use SetPowerMode
+  // to control the screen on pause/resume.
   if (!is_standalone_device_) {
     composer_callback_ = nullptr;
     composer_.reset(nullptr);
-    Layer::SetComposer(nullptr);
   } else {
-    SetPowerMode(false);
+    EnableDisplay(*target_display_, false);
   }
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "idle");
 }
 
+bool HardwareComposer::PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+                                          int timeout_sec,
+                                          const std::function<bool()>& pred) {
+  auto pred_with_quit = [&] {
+    return pred() || (post_thread_state_ & PostThreadState::Quit);
+  };
+  if (timeout_sec >= 0) {
+    post_thread_wait_.wait_for(lock, std::chrono::seconds(timeout_sec),
+                               pred_with_quit);
+  } else {
+    post_thread_wait_.wait(lock, pred_with_quit);
+  }
+  if (post_thread_state_ & PostThreadState::Quit) {
+    ALOGI("HardwareComposer::PostThread: Quitting.");
+    return true;
+  }
+  return false;
+}
+
 HWC::Error HardwareComposer::Validate(hwc2_display_t display) {
   uint32_t num_types;
   uint32_t num_requests;
@@ -278,27 +278,55 @@
       composer_->validateDisplay(display, &num_types, &num_requests);
 
   if (error == HWC2_ERROR_HAS_CHANGES) {
-    // TODO(skiazyk): We might need to inspect the requested changes first, but
-    // so far it seems like we shouldn't ever hit a bad state.
-    // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
-    //                                               display);
+    ALOGE("Hardware composer has requested composition changes, "
+          "which we don't support.");
+    // Accept the changes anyway and see if we can get something on the screen.
     error = composer_->acceptDisplayChanges(display);
   }
 
   return error;
 }
 
-HWC::Error HardwareComposer::EnableVsync(bool enabled) {
-  return composer_->setVsyncEnabled(
-      HWC_DISPLAY_PRIMARY,
+bool HardwareComposer::EnableVsync(const DisplayParams& display, bool enabled) {
+  HWC::Error error = composer_->setVsyncEnabled(display.id,
       (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
                                              : HWC2_VSYNC_DISABLE));
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to %s vsync on %s display: %s",
+        enabled ? "enable" : "disable", GetDisplayName(display.is_primary),
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
 }
 
-HWC::Error HardwareComposer::SetPowerMode(bool active) {
+bool HardwareComposer::SetPowerMode(const DisplayParams& display, bool active) {
+  ALOGI("Turning %s display %s", GetDisplayName(display.is_primary),
+      active ? "on" : "off");
   HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
-  return composer_->setPowerMode(
-      HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+  HWC::Error error = composer_->setPowerMode(display.id,
+      power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to turn %s display %s: %s",
+          GetDisplayName(display.is_primary), active ? "on" : "off",
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
+}
+
+bool HardwareComposer::EnableDisplay(const DisplayParams& display,
+                                     bool enabled) {
+  bool power_result;
+  bool vsync_result;
+  // When turning a display on, we set the power state then set vsync. When
+  // turning a display off we do it in the opposite order.
+  if (enabled) {
+    power_result = SetPowerMode(display, enabled);
+    vsync_result = EnableVsync(display, enabled);
+  } else {
+    vsync_result = EnableVsync(display, enabled);
+    power_result = SetPowerMode(display, enabled);
+  }
+  return power_result && vsync_result;
 }
 
 HWC::Error HardwareComposer::Present(hwc2_display_t display) {
@@ -317,78 +345,105 @@
   return error;
 }
 
-HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
-                                                 hwc2_display_t display,
-                                                 hwc2_config_t config,
-                                                 hwc2_attribute_t attribute,
-                                                 int32_t* out_value) const {
-  return composer->getDisplayAttribute(
-      display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
-}
+DisplayParams HardwareComposer::GetDisplayParams(
+    Hwc2::Composer* composer, hwc2_display_t display, bool is_primary) {
+  DisplayParams params;
+  params.id = display;
+  params.is_primary = is_primary;
 
-HWC::Error HardwareComposer::GetDisplayMetrics(
-    Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
-    HWCDisplayMetrics* out_metrics) const {
-  HWC::Error error;
+  Hwc2::Config config;
+  HWC::Error error = composer->getActiveConfig(display, &config);
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
-                              &out_metrics->width);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display width: %s",
-        error.to_string().c_str());
-    return error;
+  if (error == HWC::Error::None) {
+    auto get_attr = [&](hwc2_attribute_t attr, const char* attr_name)
+        -> std::optional<int32_t> {
+      int32_t val;
+      HWC::Error error = composer->getDisplayAttribute(
+          display, config, (Hwc2::IComposerClient::Attribute)attr, &val);
+      if (error != HWC::Error::None) {
+        ALOGE("Failed to get %s display attr %s: %s",
+            GetDisplayName(is_primary), attr_name,
+            error.to_string().c_str());
+        return std::nullopt;
+      }
+      return val;
+    };
+
+    auto width = get_attr(HWC2_ATTRIBUTE_WIDTH, "width");
+    auto height = get_attr(HWC2_ATTRIBUTE_HEIGHT, "height");
+
+    if (width && height) {
+      params.width = *width;
+      params.height = *height;
+    } else {
+      ALOGI("Failed to get width and/or height for %s display. Using default"
+          " size %dx%d.", GetDisplayName(is_primary), kDefaultDisplayWidth,
+          kDefaultDisplayHeight);
+      params.width = kDefaultDisplayWidth;
+      params.height = kDefaultDisplayHeight;
+    }
+
+    auto vsync_period = get_attr(HWC2_ATTRIBUTE_VSYNC_PERIOD, "vsync period");
+    if (vsync_period) {
+      params.vsync_period_ns = *vsync_period;
+    } else {
+      ALOGI("Failed to get vsync period for %s display. Using default vsync"
+          " period %.2fms", GetDisplayName(is_primary),
+          static_cast<float>(kDefaultVsyncPeriodNs) / 1000000);
+      params.vsync_period_ns = kDefaultVsyncPeriodNs;
+    }
+
+    auto dpi_x = get_attr(HWC2_ATTRIBUTE_DPI_X, "DPI X");
+    auto dpi_y = get_attr(HWC2_ATTRIBUTE_DPI_Y, "DPI Y");
+    if (dpi_x && dpi_y) {
+      params.dpi.x = *dpi_x;
+      params.dpi.y = *dpi_y;
+    } else {
+      ALOGI("Failed to get dpi_x and/or dpi_y for %s display. Using default"
+          " dpi %d.", GetDisplayName(is_primary), kDefaultDpi);
+      params.dpi.x = kDefaultDpi;
+      params.dpi.y = kDefaultDpi;
+    }
+  } else {
+    ALOGE("HardwareComposer: Failed to get current %s display config: %d."
+        " Using default display values.",
+        GetDisplayName(is_primary), error.value);
+    params.width = kDefaultDisplayWidth;
+    params.height = kDefaultDisplayHeight;
+    params.dpi.x = kDefaultDpi;
+    params.dpi.y = kDefaultDpi;
+    params.vsync_period_ns = kDefaultVsyncPeriodNs;
   }
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
-                              &out_metrics->height);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
+  ALOGI(
+      "HardwareComposer: %s display attributes: width=%d height=%d "
+      "vsync_period_ns=%d DPI=%dx%d",
+      GetDisplayName(is_primary),
+      params.width,
+      params.height,
+      params.vsync_period_ns,
+      params.dpi.x,
+      params.dpi.y);
 
-  error = GetDisplayAttribute(composer, display, config,
-                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
-                              &out_metrics->vsync_period_ns);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
-                              &out_metrics->dpi.x);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI X: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
-                              &out_metrics->dpi.y);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI Y: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  return HWC::Error::None;
+  return params;
 }
 
 std::string HardwareComposer::Dump() {
   std::unique_lock<std::mutex> lock(post_thread_mutex_);
   std::ostringstream stream;
 
-  stream << "Display metrics:     " << display_metrics_.width << "x"
-         << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
-         << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
-         << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
-         << std::endl;
+  auto print_display_metrics = [&](const DisplayParams& params) {
+    stream << GetDisplayName(params.is_primary)
+           << " display metrics:     " << params.width << "x"
+           << params.height << " " << (params.dpi.x / 1000.0)
+           << "x" << (params.dpi.y / 1000.0) << " dpi @ "
+           << (1000000000.0 / params.vsync_period_ns) << " Hz"
+           << std::endl;
+  };
+
+  print_display_metrics(primary_display_);
+  if (external_display_)
+    print_display_metrics(*external_display_);
 
   stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
   stream << "Active layers:       " << layers_.size() << std::endl;
@@ -411,7 +466,7 @@
   return stream.str();
 }
 
-void HardwareComposer::PostLayers() {
+void HardwareComposer::PostLayers(hwc2_display_t display) {
   ATRACE_NAME("HardwareComposer::PostLayers");
 
   // Setup the hardware composer layers with current buffers.
@@ -419,13 +474,6 @@
     layer.Prepare();
   }
 
-  HWC::Error error = Validate(HWC_DISPLAY_PRIMARY);
-  if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer::PostLayers: Validate failed: %s",
-          error.to_string().c_str());
-    return;
-  }
-
   // Now that we have taken in a frame from the application, we have a chance
   // to drop the frame before passing the frame along to HWC.
   // If the display driver has become backed up, we detect it here and then
@@ -466,7 +514,14 @@
   }
 #endif
 
-  error = Present(HWC_DISPLAY_PRIMARY);
+  HWC::Error error = Validate(display);
+  if (error != HWC::Error::None) {
+    ALOGE("HardwareComposer::PostLayers: Validate failed: %s display=%" PRIu64,
+          error.to_string().c_str(), display);
+    return;
+  }
+
+  error = Present(display);
   if (error != HWC::Error::None) {
     ALOGE("HardwareComposer::PostLayers: Present failed: %s",
           error.to_string().c_str());
@@ -475,8 +530,8 @@
 
   std::vector<Hwc2::Layer> out_layers;
   std::vector<int> out_fences;
-  error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
-                                      &out_fences);
+  error = composer_->getReleaseFences(display,
+                                      &out_layers, &out_fences);
   ALOGE_IF(error != HWC::Error::None,
            "HardwareComposer::PostLayers: Failed to get release fences: %s",
            error.to_string().c_str());
@@ -499,10 +554,11 @@
   const bool display_idle = surfaces.size() == 0;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    pending_surfaces_ = std::move(surfaces);
+    surfaces_ = std::move(surfaces);
+    surfaces_changed_ = true;
   }
 
-  if (request_display_callback_ && (!is_standalone_device_ || !composer_))
+  if (request_display_callback_ && !is_standalone_device_)
     request_display_callback_(!display_idle);
 
   // Set idle state based on whether there are any surfaces to handle.
@@ -570,6 +626,9 @@
   // Copy from latest record in shared_config_ring_ to local copy.
   DvrConfig record;
   if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+    ALOGI("DvrConfig updated: sequence %u, post offset %d",
+          shared_config_ring_sequence_, record.frame_post_offset_ns);
+    ++shared_config_ring_sequence_;
     post_thread_config_ = record;
   }
 }
@@ -612,21 +671,11 @@
   }
 }
 
-Status<int64_t> HardwareComposer::GetVSyncTime() {
-  auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
-  ALOGE_IF(!status,
-           "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
-           status.GetErrorMessage().c_str());
-  return status;
-}
-
-// Waits for the next vsync and returns the timestamp of the vsync event. If
-// vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking.
-Status<int64_t> HardwareComposer::WaitForVSync() {
-  const int64_t predicted_vsync_time =
-      last_vsync_timestamp_ +
-      display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+// Sleep until the next predicted vsync, returning the predicted vsync
+// timestamp.
+Status<int64_t> HardwareComposer::WaitForPredictedVSync() {
+  const int64_t predicted_vsync_time = last_vsync_timestamp_ +
+      (target_display_->vsync_period_ns * vsync_prediction_interval_);
   const int error = SleepUntil(predicted_vsync_time);
   if (error < 0) {
     ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
@@ -665,16 +714,6 @@
   bool thread_policy_setup =
       SetThreadPolicy("graphics:high", "/system/performance");
 
-#if ENABLE_BACKLIGHT_BRIGHTNESS
-  // TODO(hendrikw): This isn't required at the moment. It's possible that there
-  //                 is another method to access this when needed.
-  // Open the backlight brightness control sysfs node.
-  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
-  ALOGW_IF(!backlight_brightness_fd_,
-           "HardwareComposer: Failed to open backlight brightness control: %s",
-           strerror(errno));
-#endif  // ENABLE_BACKLIGHT_BRIGHTNESS
-
   // Create a timerfd based on CLOCK_MONOTINIC.
   vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
   LOG_ALWAYS_FATAL_IF(
@@ -682,20 +721,50 @@
       "HardwareComposer: Failed to create vsync sleep timerfd: %s",
       strerror(errno));
 
-  const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
-  const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
-
-  // TODO(jbates) Query vblank time from device, when such an API is available.
-  // This value (6.3%) was measured on A00 in low persistence mode.
-  int64_t vblank_ns = ns_per_frame * 63 / 1000;
-  int64_t right_eye_photon_offset_ns = (ns_per_frame - vblank_ns) / 2;
-
-  // Check property for overriding right eye offset value.
-  right_eye_photon_offset_ns =
-      property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
-
+  struct VsyncEyeOffsets { int64_t left_ns, right_ns; };
   bool was_running = false;
 
+  auto get_vsync_eye_offsets = [this]() -> VsyncEyeOffsets {
+    VsyncEyeOffsets offsets;
+    offsets.left_ns =
+        GetPosePredictionTimeOffset(target_display_->vsync_period_ns);
+
+    // TODO(jbates) Query vblank time from device, when such an API is
+    // available. This value (6.3%) was measured on A00 in low persistence mode.
+    int64_t vblank_ns = target_display_->vsync_period_ns * 63 / 1000;
+    offsets.right_ns = (target_display_->vsync_period_ns - vblank_ns) / 2;
+
+    // Check property for overriding right eye offset value.
+    offsets.right_ns =
+        property_get_int64(kRightEyeOffsetProperty, offsets.right_ns);
+
+    return offsets;
+  };
+
+  VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets();
+
+  if (is_standalone_device_) {
+    // First, wait until boot finishes.
+    std::unique_lock<std::mutex> lock(post_thread_mutex_);
+    if (PostThreadCondWait(lock, -1, [this] { return boot_finished_; })) {
+      return;
+    }
+
+    // Then, wait until we're either leaving the quiescent state, or the boot
+    // finished display off timeout expires.
+    if (PostThreadCondWait(lock, kBootFinishedDisplayOffTimeoutSec,
+                           [this] { return !post_thread_quiescent_; })) {
+      return;
+    }
+
+    LOG_ALWAYS_FATAL_IF(post_thread_state_ & PostThreadState::Suspended,
+                        "Vr flinger should own the display by now.");
+    post_thread_resumed_ = true;
+    post_thread_ready_.notify_all();
+    if (!composer_)
+      CreateComposer();
+  }
+
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
@@ -706,31 +775,36 @@
       std::unique_lock<std::mutex> lock(post_thread_mutex_);
       ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
 
-      // Tear down resources if necessary.
-      if (was_running)
-        OnPostThreadPaused();
-
+      // Tear down resources.
+      OnPostThreadPaused();
       was_running = false;
       post_thread_resumed_ = false;
       post_thread_ready_.notify_all();
 
-      if (post_thread_state_ & PostThreadState::Quit) {
-        ALOGI("HardwareComposer::PostThread: Quitting.");
+      if (PostThreadCondWait(lock, -1,
+                             [this] { return !post_thread_quiescent_; })) {
+        // A true return value means we've been asked to quit.
         return;
       }
 
-      post_thread_wait_.wait(lock, [this] { return !post_thread_quiescent_; });
-
       post_thread_resumed_ = true;
       post_thread_ready_.notify_all();
 
       ALOGI("HardwareComposer::PostThread: Exiting quiescent state.");
     }
 
-    if (!was_running) {
-      // Setup resources.
+    if (!composer_)
+      CreateComposer();
+
+    bool target_display_changed = UpdateTargetDisplay();
+    bool just_resumed_running = !was_running;
+    was_running = true;
+
+    if (target_display_changed)
+      vsync_eye_offsets = get_vsync_eye_offsets();
+
+    if (just_resumed_running) {
       OnPostThreadResumed();
-      was_running = true;
 
       // Try to setup the scheduler policy if it failed during startup. Only
       // attempt to do this on transitions from inactive to active to avoid
@@ -739,12 +813,16 @@
         thread_policy_setup =
             SetThreadPolicy("graphics:high", "/system/performance");
       }
+    }
 
+    if (target_display_changed || just_resumed_running) {
       // Initialize the last vsync timestamp with the current time. The
       // predictor below uses this time + the vsync interval in absolute time
       // units for the initial delay. Once the driver starts reporting vsync the
       // predictor will sync up with the real vsync.
       last_vsync_timestamp_ = GetSystemClockNs();
+      vsync_prediction_interval_ = 1;
+      retire_fence_fds_.clear();
     }
 
     int64_t vsync_timestamp = 0;
@@ -754,7 +832,7 @@
                    vsync_count_ + 1, last_vsync_timestamp_,
                    vsync_prediction_interval_);
 
-      auto status = WaitForVSync();
+      auto status = WaitForPredictedVSync();
       ALOGE_IF(
           !status,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
@@ -775,16 +853,16 @@
     if (vsync_prediction_interval_ == 1)
       ++vsync_count_;
 
-    const bool layer_config_changed = UpdateLayerConfig();
+    UpdateLayerConfig();
 
     // Publish the vsync event.
     if (vsync_ring_) {
       DvrVsync vsync;
       vsync.vsync_count = vsync_count_;
       vsync.vsync_timestamp_ns = vsync_timestamp;
-      vsync.vsync_left_eye_offset_ns = photon_offset_ns;
-      vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns;
-      vsync.vsync_period_ns = ns_per_frame;
+      vsync.vsync_left_eye_offset_ns = vsync_eye_offsets.left_ns;
+      vsync.vsync_right_eye_offset_ns = vsync_eye_offsets.right_ns;
+      vsync.vsync_period_ns = target_display_->vsync_period_ns;
 
       vsync_ring_->Publish(vsync);
     }
@@ -792,14 +870,14 @@
     // Signal all of the vsync clients. Because absolute time is used for the
     // wakeup time below, this can take a little time if necessary.
     if (vsync_callback_)
-      vsync_callback_(HWC_DISPLAY_PRIMARY, vsync_timestamp,
-                      /*frame_time_estimate*/ 0, vsync_count_);
+      vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_);
 
     {
       // Sleep until shortly before vsync.
       ATRACE_NAME("sleep");
 
-      const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
+      const int64_t display_time_est_ns =
+          vsync_timestamp + target_display_->vsync_period_ns;
       const int64_t now_ns = GetSystemClockNs();
       const int64_t sleep_time_ns = display_time_est_ns - now_ns -
                                     post_thread_config_.frame_post_offset_ns;
@@ -809,26 +887,18 @@
       ATRACE_INT64("sleep_time_ns", sleep_time_ns);
       if (sleep_time_ns > 0) {
         int error = SleepUntil(wakeup_time_ns);
-        ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
+        ALOGE_IF(error < 0 && error != kPostThreadInterrupted,
+                 "HardwareComposer::PostThread: Failed to sleep: %s",
                  strerror(-error));
-        if (error == kPostThreadInterrupted) {
-          if (layer_config_changed) {
-            // If the layer config changed we need to validateDisplay() even if
-            // we're going to drop the frame, to flush the Composer object's
-            // internal command buffer and apply our layer changes.
-            Validate(HWC_DISPLAY_PRIMARY);
-          }
-          continue;
-        }
+        // If the sleep was interrupted (error == kPostThreadInterrupted),
+        // we still go through and present this frame because we may have set
+        // layers earlier and we want to flush the Composer's internal command
+        // buffer by continuing through to validate and present.
       }
     }
 
     {
-      auto status = GetVSyncTime();
-      if (!status) {
-        ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
-              status.GetErrorMessage().c_str());
-      }
+      auto status = composer_callback_->GetVsyncTime(target_display_->id);
 
       // If we failed to read vsync there might be a problem with the driver.
       // Since there's nothing we can do just behave as though we didn't get an
@@ -855,20 +925,84 @@
       }
     }
 
-    PostLayers();
+    PostLayers(target_display_->id);
   }
 }
 
+bool HardwareComposer::UpdateTargetDisplay() {
+  bool target_display_changed = false;
+  auto displays = composer_callback_->GetDisplays();
+  if (displays.external_display_was_hotplugged) {
+    bool was_using_external_display = !target_display_->is_primary;
+    if (was_using_external_display) {
+      // The external display was hotplugged, so make sure to ignore any bad
+      // display errors as we destroy the layers.
+      for (auto& layer: layers_)
+        layer.IgnoreBadDisplayErrorsOnDestroy(true);
+    }
+
+    if (displays.external_display) {
+      // External display was connected
+      external_display_ = GetDisplayParams(composer_.get(),
+          *displays.external_display, /*is_primary*/ false);
+
+      if (property_get_bool(kUseExternalDisplayProperty, false)) {
+        ALOGI("External display connected. Switching to external display.");
+        target_display_ = &(*external_display_);
+        target_display_changed = true;
+      } else {
+        ALOGI("External display connected, but sysprop %s is unset, so"
+              " using primary display.", kUseExternalDisplayProperty);
+        if (was_using_external_display) {
+          target_display_ = &primary_display_;
+          target_display_changed = true;
+        }
+      }
+    } else {
+      // External display was disconnected
+      external_display_ = std::nullopt;
+      if (was_using_external_display) {
+        ALOGI("External display disconnected. Switching to primary display.");
+        target_display_ = &primary_display_;
+        target_display_changed = true;
+      }
+    }
+  }
+
+  if (target_display_changed) {
+    // If we're switching to the external display, turn the primary display off.
+    if (!target_display_->is_primary) {
+      EnableDisplay(primary_display_, false);
+    }
+    // If we're switching to the primary display, and the external display is
+    // still connected, turn the external display off.
+    else if (target_display_->is_primary && external_display_) {
+      EnableDisplay(*external_display_, false);
+    }
+
+    // Turn the new target display on.
+    EnableDisplay(*target_display_, true);
+
+    // When we switch displays we need to recreate all the layers, so clear the
+    // current list, which will trigger layer recreation.
+    layers_.clear();
+  }
+
+  return target_display_changed;
+}
+
 // Checks for changes in the surface stack and updates the layer config to
 // accomodate the new stack.
-bool HardwareComposer::UpdateLayerConfig() {
+void HardwareComposer::UpdateLayerConfig() {
   std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    if (pending_surfaces_.empty())
-      return false;
 
-    surfaces = std::move(pending_surfaces_);
+    if (!surfaces_changed_ && (!layers_.empty() || surfaces_.empty()))
+      return;
+
+    surfaces = surfaces_;
+    surfaces_changed_ = false;
   }
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
@@ -905,8 +1039,8 @@
       layers_.erase(search);
     } else {
       // Insert a layer for the new surface.
-      layers.emplace_back(surface, blending, display_transform_,
-                          HWC::Composition::Device, layer_index);
+      layers.emplace_back(composer_.get(), *target_display_, surface, blending,
+          HWC::Composition::Device, layer_index);
     }
 
     ALOGI_IF(
@@ -927,26 +1061,36 @@
 
   ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
            layers_.size());
-  return true;
 }
 
 void HardwareComposer::SetVSyncCallback(VSyncCallback callback) {
   vsync_callback_ = callback;
 }
 
-void HardwareComposer::SetBacklightBrightness(int brightness) {
-  if (backlight_brightness_fd_) {
-    std::array<char, 32> text;
-    const int length = snprintf(text.data(), text.size(), "%d", brightness);
-    write(backlight_brightness_fd_.Get(), text.data(), length);
-  }
-}
-
 Return<void> HardwareComposer::ComposerCallback::onHotplug(
-    Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
-  // See if the driver supports the vsync_event node in sysfs.
-  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
-      !displays_[display].driver_vsync_event_fd) {
+    Hwc2::Display display, IComposerCallback::Connection conn) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  ALOGI("onHotplug display=%" PRIu64 " conn=%d", display, conn);
+
+  bool is_primary = !got_first_hotplug_ || display == primary_display_.id;
+
+  // Our first onHotplug callback is always for the primary display.
+  if (!got_first_hotplug_) {
+    LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED,
+        "Initial onHotplug callback should be primary display connected");
+    got_first_hotplug_ = true;
+  } else if (is_primary) {
+    ALOGE("Ignoring unexpected onHotplug() call for primary display");
+    return Void();
+  }
+
+  if (conn == IComposerCallback::Connection::CONNECTED) {
+    if (!is_primary)
+      external_display_ = DisplayInfo();
+    DisplayInfo& display_info = is_primary ?
+        primary_display_ : *external_display_;
+    display_info.id = display;
+
     std::array<char, 1024> buffer;
     snprintf(buffer.data(), buffer.size(),
              "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
@@ -955,15 +1099,20 @@
           "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
           "vsync_event node for display %" PRIu64,
           display);
-      displays_[display].driver_vsync_event_fd = std::move(handle);
+      display_info.driver_vsync_event_fd = std::move(handle);
     } else {
       ALOGI(
           "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
           "support vsync_event node for display %" PRIu64,
           display);
     }
+  } else if (conn == IComposerCallback::Connection::DISCONNECTED) {
+    external_display_ = std::nullopt;
   }
 
+  if (!is_primary)
+    external_display_was_hotplugged_ = true;
+
   return Void();
 }
 
@@ -974,36 +1123,45 @@
 
 Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
                                                          int64_t timestamp) {
-  TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
-               display, timestamp);
-  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-    displays_[display].callback_vsync_timestamp = timestamp;
-  } else {
-    ALOGW(
-        "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
-        "non-physical display: display=%" PRId64,
-        display);
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (display_info) {
+    TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+                 display, timestamp);
+    display_info->callback_vsync_timestamp = timestamp;
   }
+
   return Void();
 }
 
+HardwareComposer::ComposerCallback::Displays
+HardwareComposer::ComposerCallback::GetDisplays() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  Displays displays;
+  displays.primary_display = primary_display_.id;
+  if (external_display_)
+    displays.external_display = external_display_->id;
+  if (external_display_was_hotplugged_) {
+    external_display_was_hotplugged_ = false;
+    displays.external_display_was_hotplugged = true;
+  }
+  return displays;
+}
+
 Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
-    Hwc2::Display display) {
-  if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-    ALOGE(
-        "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
-        "display requested: display=%" PRIu64,
-        display);
+    hwc2_display_t display) {
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (!display_info) {
+    ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
     return ErrorStatus(EINVAL);
   }
 
   // See if the driver supports direct vsync events.
-  LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+  LocalHandle& event_fd = display_info->driver_vsync_event_fd;
   if (!event_fd) {
     // Fall back to returning the last timestamp returned by the vsync
     // callback.
-    std::lock_guard<std::mutex> autolock(vsync_mutex_);
-    return displays_[display].callback_vsync_timestamp;
+    std::lock_guard<std::mutex> autolock(mutex_);
+    return display_info->callback_vsync_timestamp;
   }
 
   // When the driver supports the vsync_event sysfs node we can use it to
@@ -1051,18 +1209,32 @@
   return {timestamp};
 }
 
-Hwc2::Composer* Layer::composer_{nullptr};
-HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
+HardwareComposer::ComposerCallback::DisplayInfo*
+HardwareComposer::ComposerCallback::GetDisplayInfo(hwc2_display_t display) {
+  if (display == primary_display_.id) {
+    return &primary_display_;
+  } else if (external_display_ && display == external_display_->id) {
+    return &(*external_display_);
+  }
+  return nullptr;
+}
 
 void Layer::Reset() {
   if (hardware_composer_layer_) {
-    composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+    HWC::Error error =
+        composer_->destroyLayer(display_params_.id, hardware_composer_layer_);
+    if (error != HWC::Error::None &&
+        (!ignore_bad_display_errors_on_destroy_ ||
+         error != HWC::Error::BadDisplay)) {
+      ALOGE("destroyLayer() failed for display %" PRIu64 ", layer %" PRIu64
+          ". error: %s", display_params_.id, hardware_composer_layer_,
+          error.to_string().c_str());
+    }
     hardware_composer_layer_ = 0;
   }
 
   z_order_ = 0;
   blending_ = HWC::BlendMode::None;
-  transform_ = HWC::Transform::None;
   composition_type_ = HWC::Composition::Invalid;
   target_composition_type_ = composition_type_;
   source_ = EmptyVariant{};
@@ -1070,25 +1242,29 @@
   surface_rect_functions_applied_ = false;
   pending_visibility_settings_ = true;
   cached_buffer_map_.clear();
+  ignore_bad_display_errors_on_destroy_ = false;
 }
 
-Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-             HWC::BlendMode blending, HWC::Transform transform,
-             HWC::Composition composition_type, size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<DirectDisplaySurface>& surface,
+             HWC::BlendMode blending, HWC::Composition composition_type,
+             size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceSurface{surface}} {
   CommonLayerSetup();
 }
 
-Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-             HWC::Transform transform, HWC::Composition composition_type,
-             size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+             HWC::Composition composition_type, size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceBuffer{buffer}} {
   CommonLayerSetup();
@@ -1102,10 +1278,11 @@
   if (this != &other) {
     Reset();
     using std::swap;
+    swap(composer_, other.composer_);
+    swap(display_params_, other.display_params_);
     swap(hardware_composer_layer_, other.hardware_composer_layer_);
     swap(z_order_, other.z_order_);
     swap(blending_, other.blending_);
-    swap(transform_, other.transform_);
     swap(composition_type_, other.composition_type_);
     swap(target_composition_type_, other.target_composition_type_);
     swap(source_, other.source_);
@@ -1114,6 +1291,8 @@
          other.surface_rect_functions_applied_);
     swap(pending_visibility_settings_, other.pending_visibility_settings_);
     swap(cached_buffer_map_, other.cached_buffer_map_);
+    swap(ignore_bad_display_errors_on_destroy_,
+         other.ignore_bad_display_errors_on_destroy_);
   }
   return *this;
 }
@@ -1151,17 +1330,16 @@
     pending_visibility_settings_ = false;
 
     HWC::Error error;
-    hwc2_display_t display = HWC_DISPLAY_PRIMARY;
 
     error = composer_->setLayerBlendMode(
-        display, hardware_composer_layer_,
+        display_params_.id, hardware_composer_layer_,
         blending_.cast<Hwc2::IComposerClient::BlendMode>());
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
              error.to_string().c_str());
 
-    error =
-        composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+    error = composer_->setLayerZOrder(display_params_.id,
+        hardware_composer_layer_, z_order_);
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting z_ order: %s",
              error.to_string().c_str());
@@ -1170,36 +1348,35 @@
 
 void Layer::UpdateLayerSettings() {
   HWC::Error error;
-  hwc2_display_t display = HWC_DISPLAY_PRIMARY;
 
   UpdateVisibilitySettings();
 
   // TODO(eieio): Use surface attributes or some other mechanism to control
   // the layer display frame.
   error = composer_->setLayerDisplayFrame(
-      display, hardware_composer_layer_,
-      {0, 0, display_metrics_.width, display_metrics_.height});
+      display_params_.id, hardware_composer_layer_,
+      {0, 0, display_params_.width, display_params_.height});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer display frame: %s",
            error.to_string().c_str());
 
   error = composer_->setLayerVisibleRegion(
-      display, hardware_composer_layer_,
-      {{0, 0, display_metrics_.width, display_metrics_.height}});
+      display_params_.id, hardware_composer_layer_,
+      {{0, 0, display_params_.width, display_params_.height}});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer visible region: %s",
            error.to_string().c_str());
 
-  error =
-      composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+  error = composer_->setLayerPlaneAlpha(display_params_.id,
+      hardware_composer_layer_, 1.0f);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
            error.to_string().c_str());
 }
 
 void Layer::CommonLayerSetup() {
-  HWC::Error error =
-      composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+  HWC::Error error = composer_->createLayer(display_params_.id,
+                                            &hardware_composer_layer_);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::CommonLayerSetup: Failed to create layer on primary "
            "display: %s",
@@ -1243,10 +1420,10 @@
     if (composition_type_ == HWC::Composition::Invalid) {
       composition_type_ = HWC::Composition::SolidColor;
       composer_->setLayerCompositionType(
-          HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
       Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
-      composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+      composer_->setLayerColor(display_params_.id, hardware_composer_layer_,
                                layer_color);
     } else {
       // The composition type is already set. Nothing else to do until a
@@ -1256,7 +1433,7 @@
     if (composition_type_ != target_composition_type_) {
       composition_type_ = target_composition_type_;
       composer_->setLayerCompositionType(
-          HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
     }
 
@@ -1267,7 +1444,7 @@
 
     HWC::Error error{HWC::Error::None};
     error =
-        composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+        composer_->setLayerBuffer(display_params_.id, hardware_composer_layer_,
                                   slot, handle, acquire_fence_.Get());
 
     ALOGE_IF(error != HWC::Error::None,
@@ -1277,7 +1454,7 @@
     if (!surface_rect_functions_applied_) {
       const float float_right = right;
       const float float_bottom = bottom;
-      error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+      error = composer_->setLayerSourceCrop(display_params_.id,
                                             hardware_composer_layer_,
                                             {0, 0, float_right, float_bottom});
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 7010db9..1d8d463 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -13,6 +13,7 @@
 #include <condition_variable>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <thread>
 #include <tuple>
 #include <vector>
@@ -35,16 +36,19 @@
 namespace android {
 namespace dvr {
 
-// Basic display metrics for physical displays. Dimensions and densities are
-// relative to the physical display orientation, which may be different from the
-// logical display orientation exposed to applications.
-struct HWCDisplayMetrics {
+// Basic display metrics for physical displays.
+struct DisplayParams {
+  hwc2_display_t id;
+  bool is_primary;
+
   int width;
   int height;
+
   struct {
     int x;
     int y;
   } dpi;
+
   int vsync_period_ns;
 };
 
@@ -58,26 +62,29 @@
   // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
   // every frame.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
   // |index| is the index of this surface in the DirectDisplaySurface array.
-  Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-        HWC::BlendMode blending, HWC::Transform transform,
-        HWC::Composition composition_type, size_t z_roder);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<DirectDisplaySurface>& surface,
+        HWC::BlendMode blending, HWC::Composition composition_type,
+        size_t z_order);
 
   // Sets up the layer to use a direct buffer as its content source. No special
   // handling of the buffer is performed; responsibility for updating or
   // changing the buffer each frame is on the caller.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
-  Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-        HWC::Transform transform, HWC::Composition composition_type,
-        size_t z_order);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+        HWC::Composition composition_type, size_t z_order);
 
   Layer(Layer&&);
   Layer& operator=(Layer&&);
@@ -144,12 +151,8 @@
   }
   bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
 
-  // Sets the composer instance used by all Layer instances.
-  static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
-
-  // Sets the display metrics used by all Layer instances.
-  static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
-    display_metrics_ = display_metrics;
+  void IgnoreBadDisplayErrorsOnDestroy(bool ignore) {
+    ignore_bad_display_errors_on_destroy_ = ignore;
   }
 
  private:
@@ -169,16 +172,11 @@
   // associated and always returns false.
   bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
 
-  // Composer instance shared by all instances of Layer. This must be set
-  // whenever a new instance of the Composer is created. This may be set to
-  // nullptr as long as there are no instances of Layer that might need to use
-  // it.
-  static Hwc2::Composer* composer_;
+  // Composer instance.
+  Hwc2::Composer* composer_ = nullptr;
 
-  // Display metrics shared by all instances of Layer. This must be set at least
-  // once during VrFlinger initialization and is expected to remain constant
-  // thereafter.
-  static HWCDisplayMetrics display_metrics_;
+  // Parameters of the display to use for this layer.
+  DisplayParams display_params_;
 
   // The hardware composer layer and metrics to use during the prepare cycle.
   hwc2_layer_t hardware_composer_layer_ = 0;
@@ -187,7 +185,6 @@
   // Prepare phase.
   size_t z_order_ = 0;
   HWC::BlendMode blending_ = HWC::BlendMode::None;
-  HWC::Transform transform_ = HWC::Transform::None;
   HWC::Composition composition_type_ = HWC::Composition::Invalid;
   HWC::Composition target_composition_type_ = HWC::Composition::Device;
 
@@ -283,6 +280,12 @@
   // importing a buffer HWC already knows about.
   std::map<std::size_t, int> cached_buffer_map_;
 
+  // When calling destroyLayer() on an external display that's been removed we
+  // typically get HWC2_ERROR_BAD_DISPLAY errors. If
+  // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display
+  // errors, since they're expected.
+  bool ignore_bad_display_errors_on_destroy_ = false;
+
   Layer(const Layer&) = delete;
   void operator=(const Layer&) = delete;
 };
@@ -298,13 +301,14 @@
 class HardwareComposer {
  public:
   // Type for vsync callback.
-  using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>;
+  using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>;
   using RequestDisplayCallback = std::function<void(bool)>;
 
   HardwareComposer();
   ~HardwareComposer();
 
   bool Initialize(Hwc2::Composer* composer,
+                  hwc2_display_t primary_display_id,
                   RequestDisplayCallback request_display_callback);
 
   bool IsInitialized() const { return initialized_; }
@@ -316,22 +320,15 @@
   // it's paused. This should only be called from surface flinger's main thread.
   void Disable();
 
-  // Get the HMD display metrics for the current display.
-  display::Metrics GetHmdDisplayMetrics() const;
+  // Called on a binder thread.
+  void OnBootFinished();
 
   std::string Dump();
 
   void SetVSyncCallback(VSyncCallback callback);
 
-  // Metrics of the logical display, which is always landscape.
-  int DisplayWidth() const { return display_metrics_.width; }
-  int DisplayHeight() const { return display_metrics_.height; }
-  HWCDisplayMetrics display_metrics() const { return display_metrics_; }
-
-  // Metrics of the native display, which depends on the specific hardware
-  // implementation of the display.
-  HWCDisplayMetrics native_display_metrics() const {
-    return native_display_metrics_;
+  const DisplayParams& GetPrimaryDisplayParams() const {
+    return primary_display_;
   }
 
   // Sets the display surfaces to compose the hardware layer stack.
@@ -342,16 +339,16 @@
   void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
 
  private:
-  HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
-                                 hwc2_display_t display, hwc2_config_t config,
-                                 hwc2_attribute_t attributes,
-                                 int32_t* out_value) const;
-  HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
-                               hwc2_config_t config,
-                               HWCDisplayMetrics* out_metrics) const;
+  DisplayParams GetDisplayParams(Hwc2::Composer* composer,
+      hwc2_display_t display, bool is_primary);
 
-  HWC::Error EnableVsync(bool enabled);
-  HWC::Error SetPowerMode(bool active);
+  // Turn display vsync on/off. Returns true on success, false on failure.
+  bool EnableVsync(const DisplayParams& display, bool enabled);
+  // Turn display power on/off. Returns true on success, false on failure.
+  bool SetPowerMode(const DisplayParams& display, bool active);
+  // Convenience function to turn a display on/off. Turns both power and vsync
+  // on/off. Returns true on success, false on failure.
+  bool EnableDisplay(const DisplayParams& display, bool enabled);
 
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
@@ -362,24 +359,38 @@
     hardware::Return<void> onVsync(Hwc2::Display display,
                                    int64_t timestamp) override;
 
-    pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
+    bool GotFirstHotplug() { return got_first_hotplug_; }
+
+    struct Displays {
+      hwc2_display_t primary_display = 0;
+      std::optional<hwc2_display_t> external_display;
+      bool external_display_was_hotplugged = false;
+    };
+
+    Displays GetDisplays();
+    pdx::Status<int64_t> GetVsyncTime(hwc2_display_t display);
 
    private:
-    std::mutex vsync_mutex_;
-
-    struct Display {
+    struct DisplayInfo {
+      hwc2_display_t id = 0;
       pdx::LocalHandle driver_vsync_event_fd;
       int64_t callback_vsync_timestamp{0};
     };
-    std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
+
+    DisplayInfo* GetDisplayInfo(hwc2_display_t display);
+
+    std::mutex mutex_;
+
+    bool got_first_hotplug_ = false;
+    DisplayInfo primary_display_;
+    std::optional<DisplayInfo> external_display_;
+    bool external_display_was_hotplugged_ = false;
   };
 
   HWC::Error Validate(hwc2_display_t display);
   HWC::Error Present(hwc2_display_t display);
 
-  void SetBacklightBrightness(int brightness);
-
-  void PostLayers();
+  void PostLayers(hwc2_display_t display);
   void PostThread();
 
   // The post thread has two controlling states:
@@ -407,23 +418,40 @@
   int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
                                   int requested_events, int timeout_ms);
 
-  // WaitForVSync and SleepUntil are blocking calls made on the post thread that
-  // can be interrupted by a control thread. If interrupted, these calls return
-  // kPostThreadInterrupted.
+  // WaitForPredictedVSync and SleepUntil are blocking calls made on the post
+  // thread that can be interrupted by a control thread. If interrupted, these
+  // calls return kPostThreadInterrupted.
   int ReadWaitPPState();
-  pdx::Status<int64_t> WaitForVSync();
-  pdx::Status<int64_t> GetVSyncTime();
+  pdx::Status<int64_t> WaitForPredictedVSync();
   int SleepUntil(int64_t wakeup_timestamp);
 
+  // Initialize any newly connected displays, and set target_display_ to the
+  // display we should render to. Returns true if target_display_
+  // changed. Called only from the post thread.
+  bool UpdateTargetDisplay();
+
   // Reconfigures the layer stack if the display surfaces changed since the last
   // frame. Called only from the post thread.
-  bool UpdateLayerConfig();
+  void UpdateLayerConfig();
+
+  // Called on the post thread to create the Composer instance.
+  void CreateComposer();
 
   // Called on the post thread when the post thread is resumed.
   void OnPostThreadResumed();
   // Called on the post thread when the post thread is paused or quits.
   void OnPostThreadPaused();
 
+  // Use post_thread_wait_ to wait for a specific condition, specified by pred.
+  // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout
+  // in seconds.
+  // The lock must be held when this function is called.
+  // Returns true if the wait was interrupted because the post thread was asked
+  // to quit.
+  bool PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+                          int timeout_sec,
+                          const std::function<bool()>& pred);
+
   // Map the given shared memory buffer to our broadcast ring to track updates
   // to the config parameters.
   int MapConfigBuffer(IonBuffer& ion_buffer);
@@ -438,18 +466,19 @@
   sp<ComposerCallback> composer_callback_;
   RequestDisplayCallback request_display_callback_;
 
-  // Display metrics of the physical display.
-  HWCDisplayMetrics native_display_metrics_;
-  // Display metrics of the logical display, adjusted so that orientation is
-  // landscape.
-  HWCDisplayMetrics display_metrics_;
-  // Transform required to get from native to logical display orientation.
-  HWC::Transform display_transform_ = HWC::Transform::None;
+  DisplayParams primary_display_;
+  std::optional<DisplayParams> external_display_;
+  DisplayParams* target_display_ = &primary_display_;
 
-  // Pending surface list. Set by the display service when DirectSurfaces are
-  // added, removed, or change visibility. Written by the message dispatch
-  // thread and read by the post thread.
-  std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
+  // The list of surfaces we should draw. Set by the display service when
+  // DirectSurfaces are added, removed, or change visibility. Written by the
+  // message dispatch thread and read by the post thread.
+  std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces_;
+  // Set to true by the dispatch thread whenever surfaces_ changes. Set to false
+  // by the post thread when the new list of surfaces is processed.
+  bool surfaces_changed_ = false;
+
+  std::vector<std::shared_ptr<DirectDisplaySurface>> current_surfaces_;
 
   // Layer set for handling buffer flow into hardware composer layers. This
   // vector must be sorted by surface_id in ascending order.
@@ -472,8 +501,9 @@
   std::condition_variable post_thread_wait_;
   std::condition_variable post_thread_ready_;
 
-  // Backlight LED brightness sysfs node.
-  pdx::LocalHandle backlight_brightness_fd_;
+  // When boot is finished this will be set to true and the post thread will be
+  // notified via post_thread_wait_.
+  bool boot_finished_ = false;
 
   // VSync sleep timerfd.
   pdx::LocalHandle vsync_sleep_timer_fd_;
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 33cbc84..c740dde 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,6 +4,12 @@
 #include <thread>
 #include <memory>
 
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
 #include <pdx/service_dispatcher.h>
 #include <vr/vr_manager/vr_manager.h>
 
@@ -21,7 +27,9 @@
  public:
   using RequestDisplayCallback = std::function<void(bool)>;
   static std::unique_ptr<VrFlinger> Create(
-      Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
+      Hwc2::Composer* hidl,
+      hwc2_display_t primary_display_id,
+      RequestDisplayCallback request_display_callback);
   ~VrFlinger();
 
   // These functions are all called on surface flinger's main thread.
@@ -35,6 +43,7 @@
  private:
   VrFlinger();
   bool Init(Hwc2::Composer* hidl,
+            hwc2_display_t primary_display_id,
             RequestDisplayCallback request_display_callback);
 
   // Needs to be a separate class for binder's ref counting
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 85dc586..26aed4f 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -29,9 +29,10 @@
 namespace dvr {
 
 std::unique_ptr<VrFlinger> VrFlinger::Create(
-    Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
+    Hwc2::Composer* hidl, hwc2_display_t primary_display_id,
+    RequestDisplayCallback request_display_callback) {
   std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
-  if (vr_flinger->Init(hidl, request_display_callback))
+  if (vr_flinger->Init(hidl, primary_display_id, request_display_callback))
     return vr_flinger;
   else
     return nullptr;
@@ -56,6 +57,7 @@
 }
 
 bool VrFlinger::Init(Hwc2::Composer* hidl,
+                     hwc2_display_t primary_display_id,
                      RequestDisplayCallback request_display_callback) {
   if (!hidl || !request_display_callback)
     return false;
@@ -74,8 +76,8 @@
   dispatcher_ = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
 
-  display_service_ =
-      android::dvr::DisplayService::Create(hidl, request_display_callback);
+  display_service_ = android::dvr::DisplayService::Create(
+      hidl, primary_display_id, request_display_callback);
   CHECK_ERROR(!display_service_, error, "Failed to create display service.");
   dispatcher_->AddService(display_service_);
 
@@ -91,7 +93,7 @@
       std::bind(&android::dvr::VSyncService::VSyncEvent,
                 std::static_pointer_cast<android::dvr::VSyncService>(service),
                 std::placeholders::_1, std::placeholders::_2,
-                std::placeholders::_3, std::placeholders::_4));
+                std::placeholders::_3));
 
   dispatcher_thread_ = std::thread([this]() {
     prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
@@ -113,6 +115,7 @@
 }
 
 void VrFlinger::OnBootFinished() {
+  display_service_->OnBootFinished();
   sp<IVrManager> vr_manager = interface_cast<IVrManager>(
       defaultServiceManager()->checkService(String16("vrmanager")));
   if (vr_manager.get()) {
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index fdeb899..b8d8b08 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -32,21 +32,19 @@
 
 VSyncService::~VSyncService() {}
 
-void VSyncService::VSyncEvent(int display, int64_t timestamp_ns,
+void VSyncService::VSyncEvent(int64_t timestamp_ns,
                               int64_t compositor_time_ns,
                               uint32_t vsync_count) {
   ATRACE_NAME("VSyncService::VSyncEvent");
   std::lock_guard<std::mutex> autolock(mutex_);
 
-  if (display == HWC_DISPLAY_PRIMARY) {
-    last_vsync_ = current_vsync_;
-    current_vsync_ = timestamp_ns;
-    compositor_time_ns_ = compositor_time_ns;
-    current_vsync_count_ = vsync_count;
+  last_vsync_ = current_vsync_;
+  current_vsync_ = timestamp_ns;
+  compositor_time_ns_ = compositor_time_ns;
+  current_vsync_count_ = vsync_count;
 
-    NotifyWaiters();
-    UpdateClients();
-  }
+  NotifyWaiters();
+  UpdateClients();
 }
 
 std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) {
diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h
index 215948e..822f02b 100644
--- a/libs/vr/libvrflinger/vsync_service.h
+++ b/libs/vr/libvrflinger/vsync_service.h
@@ -63,9 +63,10 @@
                       const std::shared_ptr<pdx::Channel>& channel) override;
 
   // Called by the hardware composer HAL, or similar, whenever a vsync event
-  // occurs. |compositor_time_ns| is the number of ns before the next vsync when
-  // the compositor will preempt the GPU to do EDS and lens warp.
-  void VSyncEvent(int display, int64_t timestamp_ns, int64_t compositor_time_ns,
+  // occurs on the primary display. |compositor_time_ns| is the number of ns
+  // before the next vsync when the compositor will preempt the GPU to do EDS
+  // and lens warp.
+  void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns,
                   uint32_t vsync_count);
 
  private:
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index d022adf..8542790 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -14,7 +14,6 @@
 
 sourceFiles = [
     "pose_client.cpp",
-    "sensor_client.cpp",
     "latency_model.cpp",
 ]
 
@@ -24,24 +23,29 @@
 
 staticLibraries = [
     "libdisplay",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdvrcommon",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
     "libbase",
+    "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libhardware",
     "liblog",
     "libutils",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library {
     srcs: sourceFiles,
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-macro-redefined",
+    ],
     export_include_dirs: includeFiles,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index bb25f1d..b663a67 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -7,7 +7,7 @@
 #ifndef __FLOAT32X4T_86
 #define __FLOAT32X4T_86
 typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; };
+typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
 #endif
 #endif
 
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h b/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h
deleted file mode 100644
index b2ebd95..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_IPC_H_
-#define ANDROID_DVR_SENSOR_IPC_H_
-
-#define DVR_SENSOR_SERVICE_BASE "system/vr/sensors"
-
-#define DVR_SENSOR_SERVICE_CLIENT (DVR_SENSOR_SERVICE_BASE "/client")
-
-/*
- * Endpoint ops
- */
-enum {
-  DVR_SENSOR_START = 0,
-  DVR_SENSOR_STOP,
-  DVR_SENSOR_POLL,
-};
-
-#endif  // ANDROID_DVR_SENSOR_IPC_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h b/libs/vr/libvrsensor/include/private/dvr/sensor_client.h
deleted file mode 100644
index 15a9b8f..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_CLIENT_H_
-#define ANDROID_DVR_SENSOR_CLIENT_H_
-
-#include <hardware/sensors.h>
-#include <pdx/client.h>
-#include <poll.h>
-
-namespace android {
-namespace dvr {
-
-// SensorClient is a remote interface to the sensor service in sensord.
-class SensorClient : public pdx::ClientBase<SensorClient> {
- public:
-  ~SensorClient();
-
-  int StartSensor();
-  int StopSensor();
-  int Poll(sensors_event_t* events, int max_count);
-
- private:
-  friend BASE;
-
-  // Set up a channel associated with the sensor of the indicated type.
-  // NOTE(segal): If our hardware ends up with multiple sensors of the same
-  // type, we'll have to change this.
-  explicit SensorClient(int sensor_type);
-
-  int sensor_type_;
-
-  SensorClient(const SensorClient&);
-  SensorClient& operator=(const SensorClient&);
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SENSOR_CLIENT_H_
diff --git a/libs/vr/libvrsensor/sensor_client.cpp b/libs/vr/libvrsensor/sensor_client.cpp
deleted file mode 100644
index 04e88cc..0000000
--- a/libs/vr/libvrsensor/sensor_client.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#define LOG_TAG "SensorClient"
-#include <private/dvr/sensor_client.h>
-
-#include <log/log.h>
-#include <poll.h>
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/sensor-ipc.h>
-
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-
-SensorClient::SensorClient(int sensor_type)
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-          DVR_SENSOR_SERVICE_CLIENT)),
-      sensor_type_(sensor_type) {}
-
-SensorClient::~SensorClient() {}
-
-int SensorClient::StartSensor() {
-  Transaction trans{*this};
-  auto status = trans.Send<int>(DVR_SENSOR_START, &sensor_type_,
-                                sizeof(sensor_type_), nullptr, 0);
-  ALOGE_IF(!status, "startSensor() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return ReturnStatusOrError(status);
-}
-
-int SensorClient::StopSensor() {
-  Transaction trans{*this};
-  auto status = trans.Send<int>(DVR_SENSOR_STOP);
-  ALOGE_IF(!status, "stopSensor() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return ReturnStatusOrError(status);
-}
-
-int SensorClient::Poll(sensors_event_t* events, int max_events) {
-  int num_events = 0;
-  struct iovec rvec[] = {
-      {.iov_base = &num_events, .iov_len = sizeof(int)},
-      {.iov_base = events, .iov_len = max_events * sizeof(sensors_event_t)},
-  };
-  Transaction trans{*this};
-  auto status = trans.SendVector<int>(DVR_SENSOR_POLL, nullptr, rvec);
-  ALOGE_IF(!status, "Sensor poll() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return !status ? -status.error() : num_events;
-}
-
-}  // namespace dvr
-}  // namespace android
-
-// Entrypoints to simplify using the library when programmatically dynamicly
-// loading it.
-// Allows us to call this library without linking it, as, for instance,
-// when compiling GVR in Google3.
-// NOTE(segal): It's kind of a hack.
-
-extern "C" uint64_t dvrStartSensor(int type) {
-  android::dvr::SensorClient* service =
-      android::dvr::SensorClient::Create(type).release();
-  service->StartSensor();
-  return (uint64_t)service;
-}
-
-extern "C" void dvrStopSensor(uint64_t service) {
-  android::dvr::SensorClient* iss =
-      reinterpret_cast<android::dvr::SensorClient*>(service);
-  iss->StopSensor();
-  delete iss;
-}
-
-extern "C" int dvrPollSensor(uint64_t service, int max_count,
-                             sensors_event_t* events) {
-  return reinterpret_cast<android::dvr::SensorClient*>(service)->Poll(
-      events, max_count);
-}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 466768a..44f4dbc 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -33,12 +33,12 @@
 ** used to make the header, and the header can be found at
 **   http://www.khronos.org/registry/egl
 **
-** Khronos $Git commit SHA1: a732b061e7 $ on $Git commit date: 2017-06-17 23:27:53 +0100 $
+** Khronos $Git commit SHA1: feaaeb19e1 $ on $Git commit date: 2018-02-26 20:49:02 -0800 $
 */
 
 #include <EGL/eglplatform.h>
 
-#define EGL_EGLEXT_VERSION 20170627
+#define EGL_EGLEXT_VERSION 20180228
 
 /* Generated C header for:
  * API: egl
@@ -495,24 +495,52 @@
 #define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
 #endif /* EGL_ANDROID_front_buffer_auto_refresh */
 
-#ifndef EGL_ANDROID_image_crop
-#define EGL_ANDROID_image_crop 1
-#define EGL_IMAGE_CROP_LEFT_ANDROID       0x3148
-#define EGL_IMAGE_CROP_TOP_ANDROID        0x3149
-#define EGL_IMAGE_CROP_RIGHT_ANDROID      0x314A
-#define EGL_IMAGE_CROP_BOTTOM_ANDROID     0x314B
+#ifndef EGL_ANDROID_get_frame_timestamps
+#define EGL_ANDROID_get_frame_timestamps 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+#define EGL_TIMESTAMP_PENDING_ANDROID     EGL_CAST(EGLnsecsANDROID,-2)
+#define EGL_TIMESTAMP_INVALID_ANDROID     EGL_CAST(EGLnsecsANDROID,-1)
+#define EGL_TIMESTAMPS_ANDROID            0x3430
+#define EGL_COMPOSITE_DEADLINE_ANDROID    0x3431
+#define EGL_COMPOSITE_INTERVAL_ANDROID    0x3432
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
+#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID  0x343A
+#define EGL_DEQUEUE_READY_TIME_ANDROID    0x343B
+#define EGL_READS_DONE_TIME_ANDROID       0x343C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps,  const EGLint *names, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,  const EGLint *timestamps, EGLnsecsANDROID *values);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingANDROID (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps,  const EGLint *names, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetNextFrameIdANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampsANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,  const EGLint *timestamps, EGLnsecsANDROID *values);
 #endif
+#endif /* EGL_ANDROID_get_frame_timestamps */
+
+#ifndef EGL_ANDROID_get_native_client_buffer
+#define EGL_ANDROID_get_native_client_buffer 1
+struct AHardwareBuffer;
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) (const struct AHardwareBuffer *buffer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
+#endif
+#endif /* EGL_ANDROID_get_native_client_buffer */
 
 #ifndef EGL_ANDROID_image_native_buffer
 #define EGL_ANDROID_image_native_buffer 1
 #define EGL_NATIVE_BUFFER_ANDROID         0x3140
 #endif /* EGL_ANDROID_image_native_buffer */
 
-#ifndef EGL_KHR_mutable_render_buffer
-#define EGL_KHR_mutable_render_buffer 1
-#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
-#endif
-
 #ifndef EGL_ANDROID_native_fence_sync
 #define EGL_ANDROID_native_fence_sync 1
 #define EGL_SYNC_NATIVE_FENCE_ANDROID     0x3144
@@ -527,45 +555,12 @@
 
 #ifndef EGL_ANDROID_presentation_time
 #define EGL_ANDROID_presentation_time 1
-typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
 #endif
 #endif /* EGL_ANDROID_presentation_time */
 
-#ifndef EGL_ANDROID_get_frame_timestamps
-#define EGL_ANDROID_get_frame_timestamps 1
-#define EGL_TIMESTAMPS_ANDROID 0x3430
-#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431
-#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432
-#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
-#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
-#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
-#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
-#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
-#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
-#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B
-#define EGL_READS_DONE_TIME_ANDROID 0x343C
-#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID, -2)
-#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID, -1)
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
-EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
-EGLAPI EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name);
-EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-EGLAPI EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
-#else
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint name);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
-#endif
-#endif
-
 #ifndef EGL_ANDROID_recordable
 #define EGL_ANDROID_recordable 1
 #define EGL_RECORDABLE_ANDROID            0x3142
@@ -768,6 +763,11 @@
 #endif
 #endif /* EGL_EXT_image_dma_buf_import_modifiers */
 
+#ifndef EGL_EXT_image_gl_colorspace
+#define EGL_EXT_image_gl_colorspace 1
+#define EGL_GL_COLORSPACE_DEFAULT_EXT     0x314D
+#endif /* EGL_EXT_image_gl_colorspace */
+
 #ifndef EGL_EXT_image_implicit_sync_control
 #define EGL_EXT_image_implicit_sync_control 1
 #define EGL_IMPORT_SYNC_TYPE_EXT          0x3470
@@ -978,6 +978,7 @@
 #define EGL_DRM_BUFFER_STRIDE_MESA        0x31D4
 #define EGL_DRM_BUFFER_USE_SCANOUT_MESA   0x00000001
 #define EGL_DRM_BUFFER_USE_SHARE_MESA     0x00000002
+#define EGL_DRM_BUFFER_USE_CURSOR_MESA    0x00000004
 typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
 #ifdef EGL_EGLEXT_PROTOTYPES
@@ -986,16 +987,6 @@
 #endif
 #endif /* EGL_MESA_drm_image */
 
-#ifndef EGL_ANDROID_get_native_client_buffer
-#define EGL_ANDROID_get_native_client_buffer 1
-struct AHardwareBuffer;
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
-#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
-#endif
-#endif
-
 #ifndef EGL_MESA_image_dma_buf_export
 #define EGL_MESA_image_dma_buf_export 1
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
@@ -1042,6 +1033,11 @@
 #define EGL_AUTO_STEREO_NV                0x3136
 #endif /* EGL_NV_3dvision_surface */
 
+#ifndef EGL_NV_context_priority_realtime
+#define EGL_NV_context_priority_realtime 1
+#define EGL_CONTEXT_PRIORITY_REALTIME_NV  0x3357
+#endif /* EGL_NV_context_priority_realtime */
+
 #ifndef EGL_NV_coverage_sample
 #define EGL_NV_coverage_sample 1
 #define EGL_COVERAGE_BUFFERS_NV           0x30E0
@@ -1109,9 +1105,9 @@
 #define EGL_YUV_PLANE0_TEXTURE_UNIT_NV    0x332C
 #define EGL_YUV_PLANE1_TEXTURE_UNIT_NV    0x332D
 #define EGL_YUV_PLANE2_TEXTURE_UNIT_NV    0x332E
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
 #ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
 #endif
 #endif /* EGL_NV_stream_consumer_gltexture_yuv */
 
@@ -1289,6 +1285,17 @@
 #define EGL_NATIVE_SURFACE_TIZEN          0x32A1
 #endif /* EGL_TIZEN_image_native_surface */
 
+/* This is a private Android extension that does not exist in the EGL registry,
+ * formerly used to work around a hardware issue on Nexus 4. It is deprecated
+ * and unimplemented. It has been added to this header manually. */
+#ifndef EGL_ANDROID_image_crop
+#define EGL_ANDROID_image_crop 1
+#define EGL_IMAGE_CROP_LEFT_ANDROID       0x3148
+#define EGL_IMAGE_CROP_TOP_ANDROID        0x3149
+#define EGL_IMAGE_CROP_RIGHT_ANDROID      0x314A
+#define EGL_IMAGE_CROP_BOTTOM_ANDROID     0x314B
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/include/GLES/gl.h b/opengl/include/GLES/gl.h
index 36acff9..25033f2 100644
--- a/opengl/include/GLES/gl.h
+++ b/opengl/include/GLES/gl.h
@@ -51,6 +51,7 @@
 #ifndef GL_VERSION_ES_CM_1_0
 #define GL_VERSION_ES_CM_1_0 1
 typedef void GLvoid;
+typedef char GLchar;
 typedef unsigned int GLenum;
 #include <KHR/khrplatform.h>
 typedef khronos_float_t GLfloat;
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index b6fe620..1a150e3 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -104,7 +104,6 @@
 
 #ifndef GL_OES_byte_coordinates
 #define GL_OES_byte_coordinates 1
-typedef khronos_int8_t GLbyte;
 #endif /* GL_OES_byte_coordinates */
 
 #ifndef GL_OES_compressed_ETC1_RGB8_sub_texture
@@ -128,7 +127,6 @@
 
 #ifndef GL_OES_draw_texture
 #define GL_OES_draw_texture 1
-typedef short GLshort;
 #define GL_TEXTURE_CROP_RECT_OES          0x8B9D
 typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
 typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
@@ -409,7 +407,6 @@
 
 #ifndef GL_OES_single_precision
 #define GL_OES_single_precision 1
-typedef khronos_float_t GLclampf;
 typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
 typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
 typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index b5eb723..e8d7515 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -1,5 +1,5 @@
-#ifndef __gl2ext_h_
-#define __gl2ext_h_ 1
+#ifndef __gles2_gl2ext_h_
+#define __gles2_gl2ext_h_ 1
 
 #ifdef __cplusplus
 extern "C" {
@@ -38,7 +38,7 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
-/* Generated on date 20170613 */
+/* Generated on date 20180316 */
 
 /* Generated C header for:
  * API: gles2
@@ -159,6 +159,16 @@
 #define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR  0x00000008
 #endif /* GL_KHR_no_error */
 
+#ifndef GL_KHR_parallel_shader_compile
+#define GL_KHR_parallel_shader_compile 1
+#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0
+#define GL_COMPLETION_STATUS_KHR          0x91B1
+typedef void (GL_APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) (GLuint count);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count);
+#endif
+#endif /* GL_KHR_parallel_shader_compile */
+
 #ifndef GL_KHR_robust_buffer_access_behavior
 #define GL_KHR_robust_buffer_access_behavior 1
 #endif /* GL_KHR_robust_buffer_access_behavior */
@@ -324,12 +334,12 @@
 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL void GL_APIENTRY glDrawElementsBaseVertexOES (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 GL_APICALL void GL_APIENTRY glDrawRangeElementsBaseVertexOES (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertexOES (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
-GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexOES (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
 #endif
 #endif /* GL_OES_draw_elements_base_vertex */
 
@@ -1055,6 +1065,16 @@
 #define GL_EXT_EGL_image_array 1
 #endif /* GL_EXT_EGL_image_array */
 
+#ifndef GL_EXT_EGL_image_storage
+#define GL_EXT_EGL_image_storage 1
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) (GLenum target, GLeglImageOES image, const GLint* attrib_list);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) (GLuint texture, GLeglImageOES image, const GLint* attrib_list);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexStorageEXT (GLenum target, GLeglImageOES image, const GLint* attrib_list);
+GL_APICALL void GL_APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImageOES image, const GLint* attrib_list);
+#endif
+#endif /* GL_EXT_EGL_image_storage */
+
 #ifndef GL_EXT_YUV_target
 #define GL_EXT_YUV_target 1
 #define GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT    0x8BE7
@@ -1126,6 +1146,20 @@
 #endif
 #endif /* GL_EXT_clear_texture */
 
+#ifndef GL_EXT_clip_control
+#define GL_EXT_clip_control 1
+#define GL_LOWER_LEFT_EXT                 0x8CA1
+#define GL_UPPER_LEFT_EXT                 0x8CA2
+#define GL_NEGATIVE_ONE_TO_ONE_EXT        0x935E
+#define GL_ZERO_TO_ONE_EXT                0x935F
+#define GL_CLIP_ORIGIN_EXT                0x935C
+#define GL_CLIP_DEPTH_MODE_EXT            0x935D
+typedef void (GL_APIENTRYP PFNGLCLIPCONTROLEXTPROC) (GLenum origin, GLenum depth);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glClipControlEXT (GLenum origin, GLenum depth);
+#endif
+#endif /* GL_EXT_clip_control */
+
 #ifndef GL_EXT_clip_cull_distance
 #define GL_EXT_clip_cull_distance 1
 #define GL_MAX_CLIP_DISTANCES_EXT         0x0D32
@@ -1311,12 +1345,10 @@
 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 typedef void (GL_APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL void GL_APIENTRY glDrawElementsBaseVertexEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 GL_APICALL void GL_APIENTRY glDrawRangeElementsBaseVertexEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 GL_APICALL void GL_APIENTRY glDrawElementsInstancedBaseVertexEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
-GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
 #endif
 #endif /* GL_EXT_draw_elements_base_vertex */
 
@@ -1682,6 +1714,8 @@
 #define GL_LAYOUT_SHADER_READ_ONLY_EXT    0x9591
 #define GL_LAYOUT_TRANSFER_SRC_EXT        0x9592
 #define GL_LAYOUT_TRANSFER_DST_EXT        0x9593
+#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530
+#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531
 typedef void (GL_APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores);
 typedef void (GL_APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores);
 typedef GLboolean (GL_APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore);
@@ -1825,6 +1859,14 @@
 #define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
 #endif /* GL_EXT_shader_framebuffer_fetch */
 
+#ifndef GL_EXT_shader_framebuffer_fetch_non_coherent
+#define GL_EXT_shader_framebuffer_fetch_non_coherent 1
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glFramebufferFetchBarrierEXT (void);
+#endif
+#endif /* GL_EXT_shader_framebuffer_fetch_non_coherent */
+
 #ifndef GL_EXT_shader_group_vote
 #define GL_EXT_shader_group_vote 1
 #endif /* GL_EXT_shader_group_vote */
@@ -2012,18 +2054,42 @@
 #define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69
 #endif /* GL_EXT_texture_compression_astc_decode_mode */
 
+#ifndef GL_EXT_texture_compression_bptc
+#define GL_EXT_texture_compression_bptc 1
+#define GL_COMPRESSED_RGBA_BPTC_UNORM_EXT 0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F
+#endif /* GL_EXT_texture_compression_bptc */
+
 #ifndef GL_EXT_texture_compression_dxt1
 #define GL_EXT_texture_compression_dxt1 1
 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
 #endif /* GL_EXT_texture_compression_dxt1 */
 
+#ifndef GL_EXT_texture_compression_rgtc
+#define GL_EXT_texture_compression_rgtc 1
+#define GL_COMPRESSED_RED_RGTC1_EXT       0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
+#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
+#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
+#endif /* GL_EXT_texture_compression_rgtc */
+
 #ifndef GL_EXT_texture_compression_s3tc
 #define GL_EXT_texture_compression_s3tc 1
 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3
 #endif /* GL_EXT_texture_compression_s3tc */
 
+#ifndef GL_EXT_texture_compression_s3tc_srgb
+#define GL_EXT_texture_compression_s3tc_srgb 1
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#endif /* GL_EXT_texture_compression_s3tc_srgb */
+
 #ifndef GL_EXT_texture_cube_map_array
 #define GL_EXT_texture_cube_map_array 1
 #define GL_TEXTURE_CUBE_MAP_ARRAY_EXT     0x9009
@@ -2045,12 +2111,24 @@
 
 #ifndef GL_EXT_texture_filter_minmax
 #define GL_EXT_texture_filter_minmax 1
+#define GL_TEXTURE_REDUCTION_MODE_EXT     0x9366
+#define GL_WEIGHTED_AVERAGE_EXT           0x9367
 #endif /* GL_EXT_texture_filter_minmax */
 
 #ifndef GL_EXT_texture_format_BGRA8888
 #define GL_EXT_texture_format_BGRA8888 1
 #endif /* GL_EXT_texture_format_BGRA8888 */
 
+#ifndef GL_EXT_texture_format_sRGB_override
+#define GL_EXT_texture_format_sRGB_override 1
+#define GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT 0x8FBF
+#endif /* GL_EXT_texture_format_sRGB_override */
+
+#ifndef GL_EXT_texture_mirror_clamp_to_edge
+#define GL_EXT_texture_mirror_clamp_to_edge 1
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743
+#endif /* GL_EXT_texture_mirror_clamp_to_edge */
+
 #ifndef GL_EXT_texture_norm16
 #define GL_EXT_texture_norm16 1
 #define GL_R16_EXT                        0x822A
@@ -2253,6 +2331,11 @@
 #define GL_CUBIC_MIPMAP_LINEAR_IMG        0x913B
 #endif /* GL_IMG_texture_filter_cubic */
 
+#ifndef GL_INTEL_blackhole_render
+#define GL_INTEL_blackhole_render 1
+#define GL_BLACKHOLE_RENDER_INTEL         0x83FC
+#endif /* GL_INTEL_blackhole_render */
+
 #ifndef GL_INTEL_conservative_rasterization
 #define GL_INTEL_conservative_rasterization 1
 #define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE
@@ -2295,7 +2378,7 @@
 typedef void (GL_APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId);
 typedef void (GL_APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId);
 typedef void (GL_APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
-typedef void (GL_APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten);
+typedef void (GL_APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);
 typedef void (GL_APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId);
 typedef void (GL_APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
 #ifdef GL_GLEXT_PROTOTYPES
@@ -2306,12 +2389,17 @@
 GL_APICALL void GL_APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId);
 GL_APICALL void GL_APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId);
 GL_APICALL void GL_APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
-GL_APICALL void GL_APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten);
+GL_APICALL void GL_APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);
 GL_APICALL void GL_APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId);
 GL_APICALL void GL_APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
 #endif
 #endif /* GL_INTEL_performance_query */
 
+#ifndef GL_MESA_program_binary_formats
+#define GL_MESA_program_binary_formats 1
+#define GL_PROGRAM_BINARY_FORMAT_MESA     0x875F
+#endif /* GL_MESA_program_binary_formats */
+
 #ifndef GL_MESA_shader_integer_functions
 #define GL_MESA_shader_integer_functions 1
 #endif /* GL_MESA_shader_integer_functions */
@@ -2416,6 +2504,23 @@
 #define GL_BLEND_ADVANCED_COHERENT_NV     0x9285
 #endif /* GL_NV_blend_equation_advanced_coherent */
 
+#ifndef GL_NV_blend_minmax_factor
+#define GL_NV_blend_minmax_factor 1
+#define GL_FACTOR_MIN_AMD                 0x901C
+#define GL_FACTOR_MAX_AMD                 0x901D
+#endif /* GL_NV_blend_minmax_factor */
+
+#ifndef GL_NV_clip_space_w_scaling
+#define GL_NV_clip_space_w_scaling 1
+#define GL_VIEWPORT_POSITION_W_SCALE_NV   0x937C
+#define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D
+#define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E
+typedef void (GL_APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
+#endif
+#endif /* GL_NV_clip_space_w_scaling */
+
 #ifndef GL_NV_conditional_render
 #define GL_NV_conditional_render 1
 #define GL_QUERY_WAIT_NV                  0x8E13
@@ -2442,6 +2547,11 @@
 #endif
 #endif /* GL_NV_conservative_raster */
 
+#ifndef GL_NV_conservative_raster_pre_snap
+#define GL_NV_conservative_raster_pre_snap 1
+#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV 0x9550
+#endif /* GL_NV_conservative_raster_pre_snap */
+
 #ifndef GL_NV_conservative_raster_pre_snap_triangles
 #define GL_NV_conservative_raster_pre_snap_triangles 1
 #define GL_CONSERVATIVE_RASTER_MODE_NV    0x954D
@@ -2813,6 +2923,7 @@
 
 #ifndef GL_NV_path_rendering
 #define GL_NV_path_rendering 1
+typedef double GLdouble;
 #define GL_PATH_FORMAT_SVG_NV             0x9070
 #define GL_PATH_FORMAT_PS_NV              0x9071
 #define GL_STANDARD_FONT_NAME_NV          0x9072
@@ -3023,6 +3134,25 @@
 typedef GLenum (GL_APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
 typedef void (GL_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
 typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (GL_APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode);
+typedef void (GL_APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (GL_APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (GL_APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode);
+typedef void (GL_APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode);
+typedef void (GL_APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+typedef void (GL_APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+typedef void (GL_APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL GLuint GL_APIENTRY glGenPathsNV (GLsizei range);
 GL_APICALL void GL_APIENTRY glDeletePathsNV (GLuint path, GLsizei range);
@@ -3081,6 +3211,25 @@
 GL_APICALL GLenum GL_APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
 GL_APICALL void GL_APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
 GL_APICALL void GL_APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params);
+GL_APICALL void GL_APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GL_APICALL void GL_APIENTRY glMatrixLoadIdentityEXT (GLenum mode);
+GL_APICALL void GL_APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m);
+GL_APICALL void GL_APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m);
+GL_APICALL void GL_APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m);
+GL_APICALL void GL_APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m);
+GL_APICALL void GL_APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m);
+GL_APICALL void GL_APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m);
+GL_APICALL void GL_APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m);
+GL_APICALL void GL_APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m);
+GL_APICALL void GL_APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GL_APICALL void GL_APIENTRY glMatrixPopEXT (GLenum mode);
+GL_APICALL void GL_APIENTRY glMatrixPushEXT (GLenum mode);
+GL_APICALL void GL_APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+GL_APICALL void GL_APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+GL_APICALL void GL_APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
 #endif
 #endif /* GL_NV_path_rendering */
 
@@ -3089,6 +3238,14 @@
 #define GL_SHARED_EDGE_NV                 0xC0
 #endif /* GL_NV_path_rendering_shared_edge */
 
+#ifndef GL_NV_pixel_buffer_object
+#define GL_NV_pixel_buffer_object 1
+#define GL_PIXEL_PACK_BUFFER_NV           0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_NV         0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_NV   0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_NV 0x88EF
+#endif /* GL_NV_pixel_buffer_object */
+
 #ifndef GL_NV_polygon_mode
 #define GL_NV_polygon_mode 1
 #define GL_POLYGON_MODE_NV                0x0B40
@@ -3184,6 +3341,10 @@
 #define GL_SAMPLER_CUBE_SHADOW_NV         0x8DC5
 #endif /* GL_NV_shadow_samplers_cube */
 
+#ifndef GL_NV_stereo_view_rendering
+#define GL_NV_stereo_view_rendering 1
+#endif /* GL_NV_stereo_view_rendering */
+
 #ifndef GL_NV_texture_border_clamp
 #define GL_NV_texture_border_clamp 1
 #define GL_TEXTURE_BORDER_COLOR_NV        0x1004
@@ -3386,6 +3547,19 @@
 #endif
 #endif /* GL_QCOM_shader_framebuffer_fetch_noncoherent */
 
+#ifndef GL_QCOM_texture_foveated
+#define GL_QCOM_texture_foveated 1
+#define GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM 0x8BFB
+#define GL_TEXTURE_FOVEATED_MIN_PIXEL_DENSITY_QCOM 0x8BFC
+#define GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM 0x8BFD
+#define GL_TEXTURE_FOVEATED_NUM_FOCAL_POINTS_QUERY_QCOM 0x8BFE
+#define GL_FRAMEBUFFER_INCOMPLETE_FOVEATION_QCOM 0x8BFF
+typedef void (GL_APIENTRYP PFNGLTEXTUREFOVEATIONPARAMETERSQCOMPROC) (GLuint texture, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea);
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTextureFoveationParametersQCOM (GLuint texture, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea);
+#endif
+#endif /* GL_QCOM_texture_foveated */
+
 #ifndef GL_QCOM_tiled_rendering
 #define GL_QCOM_tiled_rendering 1
 #define GL_COLOR_BUFFER_BIT0_QCOM         0x00000001
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index c7635e2..15a12e4 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -38,6 +38,8 @@
 # The graphics code can generate division by zero
 LOCAL_CFLAGS_mips += -mno-check-zero-division
 
+LOCAL_CFLAGS += -Wall -Werror
+
 # we need to access the private Bionic header <bionic_tls.h>
 LOCAL_C_INCLUDES += bionic/libc/private
 
diff --git a/opengl/libagl/BufferObjectManager.cpp b/opengl/libagl/BufferObjectManager.cpp
index 6bf28ee..3d93c19 100644
--- a/opengl/libagl/BufferObjectManager.cpp
+++ b/opengl/libagl/BufferObjectManager.cpp
@@ -18,7 +18,7 @@
 #include <stddef.h>
 #include <sys/types.h>
 
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
 #include <utils/Errors.h>
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index de9e03e..9cf8771 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -21,7 +21,7 @@
 #include <stddef.h>
 #include <sys/types.h>
 
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
 #include <utils/threads.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 54207fa..2d36c61 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -136,9 +136,6 @@
 static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
     memcpy(v, c->current.color.v, sizeof(vec4_t));
 }
-static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
-    memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
-}
 static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
     memcpy(v, c->currentNormal.v, sizeof(vec3_t));
 }
@@ -349,6 +346,7 @@
 {
     // make sure the size of vertex_t allows cache-line alignment
     CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
+    (void)assertAlignedSize; // suppress unused warning.
 
     const int align = 32;
     const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index b79051c..be43705 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -81,7 +81,9 @@
 
 const unsigned int NUM_DISPLAYS = 1;
 
+#ifndef __ANDROID__
 static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
 static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t gEGLErrorKey = -1;
 #ifndef __ANDROID__
@@ -1776,7 +1778,6 @@
         // if we're detaching, we need the current context
         current_ctx = (EGLContext)getGlThreadSpecific();
     } else {
-        egl_context_t* c = egl_context_t::context(ctx);
         egl_surface_t* d = (egl_surface_t*)draw;
         egl_surface_t* r = (egl_surface_t*)read;
         if ((d && d->ctx && d->ctx != ctx) ||
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index e7fe9d7..216c725 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -467,7 +467,6 @@
     }
 
     light_t& light = c->lighting.lights[i-GL_LIGHT0];
-    const GLfixed kDegToRad = GLfixed((M_PI * gglIntToFixed(1)) / 180.0f);
     switch (pname) {
     case GL_SPOT_EXPONENT:
         if (GGLfixed(param) >= gglIntToFixed(128)) {
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index 034c857..edd474d 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -51,7 +51,6 @@
 static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
 static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
 static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
-static void normal__nop(transform_t const*, vec4_t* c, vec4_t const* o);
 static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
 static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
 static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
@@ -524,16 +523,6 @@
     }
 }
 
-static inline 
-GLfloat det22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
-    return a*d - b*c;
-}
-
-static inline
-GLfloat ndet22(GLfloat a, GLfloat b, GLfloat c, GLfloat d) {
-    return b*c - a*d;
-}
-
 static __attribute__((noinline))
 void invert(GLfloat* inverse, const GLfloat* src)
 {
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index 57a798d..d3b19e8 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -241,6 +241,7 @@
     m_dx20 = v0->window.x - v2->window.x;
     m_dy02 = v2->window.y - v0->window.y;
     m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
+    (void)m_reserved; // suppress unused warning
 }
 
 void compute_iterators_t::initLine(
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 3fe5ed0..aae8e05 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -356,10 +356,6 @@
         GLenum format, GLenum type, GLsizei width, GLsizei height,
         GLenum compressedFormat = 0)
 {
-    // find out which texture is bound to the current unit
-    const int active = c->textures.active;
-    const GLuint name = c->textures.tmu[active].name;
-
     // convert the pixelformat to one we can handle
     const int32_t formatIdx = convertGLPixelFormat(format, type);
     if (formatIdx == 0) { // we don't know what to do with this
@@ -1192,7 +1188,6 @@
         const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
         const int32_t align = c->textures.unpackAlignment-1;
         const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
-        const size_t size = bpr * height;
         const int32_t stride = bpr / pixelFormat.size;
 
         GGLSurface userSurface;
@@ -1276,7 +1271,6 @@
     const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
     const int32_t align = c->textures.unpackAlignment-1;
     const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
-    const size_t size = bpr * height;
     const int32_t stride = bpr / pixelFormat.size;
     GGLSurface userSurface;
     userSurface.version = sizeof(userSurface);
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 802b3b4..d43c164 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -3,6 +3,7 @@
     name: "libETC1",
     srcs: ["ETC1/etc1.cpp"],
     host_supported: true,
+    cflags: ["-Wall", "-Werror"],
 
     target: {
         android: {
@@ -56,6 +57,9 @@
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
         "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-variable",
     ],
     shared_libs: [
         // ***** DO NOT ADD NEW DEPENDENCIES HERE *****
@@ -87,6 +91,11 @@
     defaults: ["gl_libs_defaults"],
     cflags: [
         "-DLOG_TAG=\"libEGL\"",
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-register",
+        "-Wno-error=unknown-attributes",
+        "-Wno-unused-variable",
     ],
     shared_libs: [
         // ***** DO NOT ADD NEW DEPENDENCIES HERE *****
@@ -113,6 +122,16 @@
     },
 }
 
+cc_library_static {
+    name: "libEGL_blobCache",
+    defaults: ["egl_libs_defaults"],
+    srcs: [
+        "EGL/BlobCache.cpp",
+        "EGL/FileBlobCache.cpp",
+    ],
+    export_include_dirs: ["EGL"],
+}
+
 cc_library_shared {
     name: "libEGL",
     defaults: ["egl_libs_defaults"],
@@ -124,7 +143,6 @@
         "EGL/egl.cpp",
         "EGL/eglApi.cpp",
         "EGL/Loader.cpp",
-        "EGL/BlobCache.cpp",
     ],
     shared_libs: [
         "libvndksupport",
@@ -134,7 +152,10 @@
         "libhidltransport",
         "libutils",
     ],
-    static_libs: ["libEGL_getProcAddress"],
+    static_libs: [
+        "libEGL_getProcAddress",
+        "libEGL_blobCache",
+    ],
     ldflags: ["-Wl,--exclude-libs=ALL"],
     export_include_dirs: ["EGL/include"],
 }
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index f1b30c7..b3752f5 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -18,6 +18,7 @@
 
 #include "BlobCache.h"
 
+#include <errno.h>
 #include <inttypes.h>
 
 #include <cutils/properties.h>
@@ -36,9 +37,9 @@
 static const uint32_t blobCacheDeviceVersion = 1;
 
 BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+        mMaxTotalSize(maxTotalSize),
         mMaxKeySize(maxKeySize),
         mMaxValueSize(maxValueSize),
-        mMaxTotalSize(maxTotalSize),
         mTotalSize(0) {
     int64_t now = std::chrono::steady_clock::now().time_since_epoch().count();
 #ifdef _WIN32
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index a0a270a..1f5d535 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -97,6 +97,14 @@
     //
     int unflatten(void const* buffer, size_t size);
 
+protected:
+    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+    // includes space for both keys and values. When a call to BlobCache::set
+    // would otherwise cause this limit to be exceeded, either the key/value
+    // pair passed to BlobCache::set will not be cached or other cache entries
+    // will be evicted from the cache to make room for the new entry.
+    const size_t mMaxTotalSize;
+
 private:
     // Copying is disallowed.
     BlobCache(const BlobCache&);
@@ -220,13 +228,6 @@
     // simply not add the key/value pair to the cache.
     const size_t mMaxValueSize;
 
-    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
-    // includes space for both keys and values. When a call to BlobCache::set
-    // would otherwise cause this limit to be exceeded, either the key/value
-    // pair passed to BlobCache::set will not be cached or other cache entries
-    // will be evicted from the cache to make room for the new entry.
-    const size_t mMaxTotalSize;
-
     // mTotalSize is the total combined size of all keys and values currently in
     // the cache.
     size_t mTotalSize;
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
new file mode 100644
index 0000000..7923715
--- /dev/null
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -0,0 +1,186 @@
+/*
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "FileBlobCache.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+
+// Cache file header
+static const char* cacheFileMagic = "EGL$";
+static const size_t cacheFileHeaderSize = 8;
+
+namespace android {
+
+static uint32_t crc32c(const uint8_t* buf, size_t len) {
+    const uint32_t polyBits = 0x82F63B78;
+    uint32_t r = 0;
+    for (size_t i = 0; i < len; i++) {
+        r ^= buf[i];
+        for (int j = 0; j < 8; j++) {
+            if (r & 1) {
+                r = (r >> 1) ^ polyBits;
+            } else {
+                r >>= 1;
+            }
+        }
+    }
+    return r;
+}
+
+FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
+        const std::string& filename)
+        : BlobCache(maxKeySize, maxValueSize, maxTotalSize)
+        , mFilename(filename) {
+    if (mFilename.length() > 0) {
+        size_t headerSize = cacheFileHeaderSize;
+
+        int fd = open(mFilename.c_str(), O_RDONLY, 0);
+        if (fd == -1) {
+            if (errno != ENOENT) {
+                ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
+                        strerror(errno), errno);
+            }
+            return;
+        }
+
+        struct stat statBuf;
+        if (fstat(fd, &statBuf) == -1) {
+            ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
+            close(fd);
+            return;
+        }
+
+        // Sanity check the size before trying to mmap it.
+        size_t fileSize = statBuf.st_size;
+        if (fileSize > mMaxTotalSize * 2) {
+            ALOGE("cache file is too large: %#" PRIx64,
+                  static_cast<off64_t>(statBuf.st_size));
+            close(fd);
+            return;
+        }
+
+        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+                PROT_READ, MAP_PRIVATE, fd, 0));
+        if (buf == MAP_FAILED) {
+            ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
+                    errno);
+            close(fd);
+            return;
+        }
+
+        // Check the file magic and CRC
+        size_t cacheSize = fileSize - headerSize;
+        if (memcmp(buf, cacheFileMagic, 4) != 0) {
+            ALOGE("cache file has bad mojo");
+            close(fd);
+            return;
+        }
+        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+        if (crc32c(buf + headerSize, cacheSize) != *crc) {
+            ALOGE("cache file failed CRC check");
+            close(fd);
+            return;
+        }
+
+        int err = unflatten(buf + headerSize, cacheSize);
+        if (err < 0) {
+            ALOGE("error reading cache contents: %s (%d)", strerror(-err),
+                    -err);
+            munmap(buf, fileSize);
+            close(fd);
+            return;
+        }
+
+        munmap(buf, fileSize);
+        close(fd);
+    }
+}
+
+void FileBlobCache::writeToFile() {
+    if (mFilename.length() > 0) {
+        size_t cacheSize = getFlattenedSize();
+        size_t headerSize = cacheFileHeaderSize;
+        const char* fname = mFilename.c_str();
+
+        // Try to create the file with no permissions so we can write it
+        // without anyone trying to read it.
+        int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+        if (fd == -1) {
+            if (errno == EEXIST) {
+                // The file exists, delete it and try again.
+                if (unlink(fname) == -1) {
+                    // No point in retrying if the unlink failed.
+                    ALOGE("error unlinking cache file %s: %s (%d)", fname,
+                            strerror(errno), errno);
+                    return;
+                }
+                // Retry now that we've unlinked the file.
+                fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+            }
+            if (fd == -1) {
+                ALOGE("error creating cache file %s: %s (%d)", fname,
+                        strerror(errno), errno);
+                return;
+            }
+        }
+
+        size_t fileSize = headerSize + cacheSize;
+
+        uint8_t* buf = new uint8_t [fileSize];
+        if (!buf) {
+            ALOGE("error allocating buffer for cache contents: %s (%d)",
+                    strerror(errno), errno);
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        int err = flatten(buf + headerSize, cacheSize);
+        if (err < 0) {
+            ALOGE("error writing cache contents: %s (%d)", strerror(-err),
+                    -err);
+            delete [] buf;
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        // Write the file magic and CRC
+        memcpy(buf, cacheFileMagic, 4);
+        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+        *crc = crc32c(buf + headerSize, cacheSize);
+
+        if (write(fd, buf, fileSize) == -1) {
+            ALOGE("error writing cache file: %s (%d)", strerror(errno),
+                    errno);
+            delete [] buf;
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        delete [] buf;
+        fchmod(fd, S_IRUSR);
+        close(fd);
+    }
+}
+
+}
diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h
new file mode 100644
index 0000000..393703f
--- /dev/null
+++ b/opengl/libs/EGL/FileBlobCache.h
@@ -0,0 +1,43 @@
+/*
+ ** Copyright 2017, 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 ANDROID_FILE_BLOB_CACHE_H
+#define ANDROID_FILE_BLOB_CACHE_H
+
+#include "BlobCache.h"
+#include <string>
+
+namespace android {
+
+class FileBlobCache : public BlobCache {
+public:
+    // FileBlobCache attempts to load the saved cache contents from disk into
+    // BlobCache.
+    FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
+            const std::string& filename);
+
+    // writeToFile attempts to save the current contents of BlobCache to
+    // disk.
+    void writeToFile();
+
+private:
+    // mFilename is the name of the file for storing cache contents.
+    std::string mFilename;
+};
+
+} // namespace android
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 371239d..91a3455 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -340,6 +340,14 @@
                     result = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
 #endif
                     return result;
+                case 2:
+                    // Use guest side swiftshader library
+#if defined(__LP64__)
+                    result = std::string("/vendor/lib64/egl/lib") + kind + "_swiftshader.so";
+#else
+                    result = std::string("/vendor/lib/egl/lib") + kind + "_swiftshader.so";
+#endif
+                    return result;
                 default:
                     // Not in emulator, or use other guest-side implementation
                     break;
@@ -389,7 +397,7 @@
         static bool find(std::string& result,
                 const std::string& pattern, const char* const search, bool exact) {
             if (exact) {
-                std::string absolutePath = std::string(search) + "/" + pattern;
+                std::string absolutePath = std::string(search) + "/" + pattern + ".so";
                 if (!access(absolutePath.c_str(), R_OK)) {
                     result = absolutePath;
                     return true;
@@ -399,9 +407,8 @@
 
             DIR* d = opendir(search);
             if (d != NULL) {
-                struct dirent cur;
                 struct dirent* e;
-                while (readdir_r(d, &cur, &e) == 0 && e) {
+                while ((e = readdir(d)) != NULL) {
                     if (e->d_type == DT_DIR) {
                         continue;
                     }
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 94dfe6a..c65bddf 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -80,6 +80,7 @@
 extern char const * const gExtensionString;
 
 // clang-format off
+// Extensions implemented by the EGL wrapper.
 char const * const gBuiltinExtensionString =
         "EGL_KHR_get_all_proc_addresses "
         "EGL_ANDROID_presentation_time "
@@ -87,11 +88,15 @@
         "EGL_ANDROID_get_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
         "EGL_ANDROID_get_frame_timestamps "
+        "EGL_EXT_surface_SMPTE2086_metadata "
+        "EGL_EXT_surface_CTA861_3_metadata "
         ;
 
+// Whitelist of extensions exposed to applications if implemented in the vendor driver.
 char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
         "EGL_KHR_image_base "                   // mandatory
+        "EGL_EXT_image_gl_colorspace "
         "EGL_KHR_image_pixmap "
         "EGL_KHR_lock_surface "
         "EGL_KHR_gl_colorspace "
@@ -240,8 +245,6 @@
          !strcmp((procname), "eglHibernateProcessIMG")      ||    \
          !strcmp((procname), "eglAwakenProcessIMG"))
 
-
-
 // accesses protected by sExtensionMapMutex
 static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
 
@@ -450,12 +453,8 @@
 // surfaces
 // ----------------------------------------------------------------------------
 
-// Turn linear formats into corresponding sRGB formats when colorspace is
-// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
-// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
-// the modification isn't possible, the original dataSpace is returned.
-static android_dataspace modifyBufferDataspace(android_dataspace dataSpace,
-                                               EGLint colorspace) {
+// Translates EGL color spaces to Android data spaces.
+static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
     if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
         return HAL_DATASPACE_SRGB_LINEAR;
     } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
@@ -468,144 +467,147 @@
         return HAL_DATASPACE_V0_SCRGB;
     } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
         return HAL_DATASPACE_V0_SCRGB_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
+        return HAL_DATASPACE_BT2020_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
+        return HAL_DATASPACE_BT2020_PQ;
     }
-    return dataSpace;
+    return HAL_DATASPACE_UNKNOWN;
 }
 
-// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
-static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
-                                           EGLint format,
-                                           std::vector<EGLint>& stripped_attrib_list) {
-    std::vector<EGLint> allowedColorSpaces;
-    switch (format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-            // driver okay with linear & sRGB for 8888, but can't handle
-            // Display-P3 or other spaces.
-            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
-            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
-            break;
+// Get the colorspace value that should be reported from queries. When the colorspace
+// is unknown (no attribute passed), default to reporting LINEAR.
+static EGLint getReportedColorSpace(EGLint colorspace) {
+    return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace;
+}
 
-        case HAL_PIXEL_FORMAT_RGBA_FP16:
-        case HAL_PIXEL_FORMAT_RGBA_1010102:
-        default:
-            // driver does not want to see colorspace attributes for 1010102 or fp16.
-            // Future: if driver supports XXXX extension, we can pass down that colorspace
-            break;
-    }
+// Returns a list of color spaces understood by the vendor EGL driver.
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
+                                                android_pixel_format format) {
+    std::vector<EGLint> colorSpaces;
+    if (!dp->hasColorSpaceSupport) return colorSpaces;
 
-    bool stripped = false;
-    if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
-        for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
-            if (attr[0] == EGL_GL_COLORSPACE_KHR) {
-                EGLint colorSpace = attr[1];
-                bool found = false;
-                // Verify that color space is allowed
-                for (auto it : allowedColorSpaces) {
-                    if (colorSpace == it) {
-                        found = true;
-                    }
-                }
-                if (!found) {
-                    stripped = true;
-                } else {
-                    stripped_attrib_list.push_back(attr[0]);
-                    stripped_attrib_list.push_back(attr[1]);
-                }
-            } else {
-                stripped_attrib_list.push_back(attr[0]);
-                stripped_attrib_list.push_back(attr[1]);
-            }
+    // OpenGL drivers only support sRGB encoding with 8-bit formats.
+    // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
+    const bool formatSupportsSRGBEncoding =
+        format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
+        format == HAL_PIXEL_FORMAT_RGB_888;
+    const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+
+    if (formatSupportsSRGBEncoding) {
+        // sRGB and linear are always supported when color space support is present.
+        colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+        colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+        // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
+        if (findExtension(dp->disp.queryString.extensions,
+                              "EGL_EXT_gl_colorspace_display_p3")) {
+            colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
         }
     }
-    if (stripped) {
-        stripped_attrib_list.push_back(EGL_NONE);
-        stripped_attrib_list.push_back(EGL_NONE);
+
+    // According to the spec, scRGB is only supported for floating point formats.
+    // For non-linear scRGB, the application is responsible for applying the
+    // transfer function.
+    if (formatIsFloatingPoint) {
+        if (findExtension(dp->disp.queryString.extensions,
+                  "EGL_EXT_gl_colorspace_scrgb")) {
+            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
+        }
+        if (findExtension(dp->disp.queryString.extensions,
+                  "EGL_EXT_gl_colorspace_scrgb_linear")) {
+            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+        }
     }
-    return stripped;
+
+    // BT2020 can be used with any pixel format. PQ encoding must be applied by the
+    // application and does not affect the behavior of OpenGL.
+    if (findExtension(dp->disp.queryString.extensions,
+                          "EGL_EXT_gl_colorspace_bt2020_linear")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
+    }
+    if (findExtension(dp->disp.queryString.extensions,
+                          "EGL_EXT_gl_colorspace_bt2020_pq")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+    }
+
+    // Linear DCI-P3 simply uses different primaries than standard RGB and thus
+    // can be used with any pixel format.
+    if (findExtension(dp->disp.queryString.extensions,
+                          "EGL_EXT_gl_colorspace_display_p3_linear")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
+    }
+    return colorSpaces;
 }
 
-static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
-                                         const EGLint* attrib_list, EGLint& colorSpace,
-                                         android_dataspace& dataSpace) {
-    colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
-    dataSpace = HAL_DATASPACE_UNKNOWN;
+// Cleans up color space related parameters that the driver does not understand.
+// If there is no color space attribute in attrib_list, colorSpace is left
+// unmodified.
+static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window,
+                                    android_pixel_format format, const EGLint* attrib_list,
+                                    EGLint* colorSpace,
+                                    std::vector<EGLint>* strippedAttribList) {
+    for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
+        bool copyAttribute = true;
+        if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+            // Fail immediately if the driver doesn't have color space support at all.
+            if (!dp->hasColorSpaceSupport) return false;
+            *colorSpace = attr[1];
 
-    if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
-        for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
-            if (*attr == EGL_GL_COLORSPACE_KHR) {
-                colorSpace = attr[1];
-                bool found = false;
-                bool verify = true;
-                // Verify that color space is allowed
-                if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
-                    colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
-                    // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
-                    // is available, so no need to verify.
-                    found = true;
-                    verify = false;
-                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
-                    found = true;
-                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
-                    found = true;
-                } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) {
-                    found = true;
-                } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) {
-                    found = true;
-                } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) {
-                    found = true;
-                } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT &&
-                           dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) {
-                    found = true;
+            // Strip the attribute if the driver doesn't understand it.
+            copyAttribute = false;
+            std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+            for (auto driverColorSpace : driverColorSpaces) {
+                if (attr[1] == driverColorSpace) {
+                    copyAttribute = true;
+                    break;
                 }
-                if (!found) {
-                    return false;
-                }
-                if (verify && window) {
-                    bool wide_color_support = true;
-                    // Ordinarily we'd put a call to native_window_get_wide_color_support
-                    // at the beginning of the function so that we'll have the
-                    // result when needed elsewhere in the function.
-                    // However, because eglCreateWindowSurface is called by SurfaceFlinger and
-                    // SurfaceFlinger is required to answer the call below we would
-                    // end up in a deadlock situation. By moving the call to only happen
-                    // if the application has specifically asked for wide-color we avoid
-                    // the deadlock with SurfaceFlinger since it will not ask for a
-                    // wide-color surface.
-                    int err = native_window_get_wide_color_support(window, &wide_color_support);
-
-                    if (err) {
-                        ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
-                              "failed (%#x) (already connected to another API?)",
-                              window, err);
-                        return false;
-                    }
-                    if (!wide_color_support) {
-                        // Application has asked for a wide-color colorspace but
-                        // wide-color support isn't available on the display the window is on.
-                        return false;
-                    }
-                }
-                // Only change the dataSpace from default if the application
-                // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
-                dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
             }
         }
+        if (copyAttribute) {
+            strippedAttribList->push_back(attr[0]);
+            strippedAttribList->push_back(attr[1]);
+        }
+    }
+    // Terminate the attribute list.
+    strippedAttribList->push_back(EGL_NONE);
+
+    // If the passed color space has wide color gamut, check whether the target native window
+    // supports wide color.
+    const bool colorSpaceIsNarrow =
+        *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+        *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
+        *colorSpace == EGL_UNKNOWN;
+    if (window && !colorSpaceIsNarrow) {
+        bool windowSupportsWideColor = true;
+        // Ordinarily we'd put a call to native_window_get_wide_color_support
+        // at the beginning of the function so that we'll have the
+        // result when needed elsewhere in the function.
+        // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+        // SurfaceFlinger is required to answer the call below we would
+        // end up in a deadlock situation. By moving the call to only happen
+        // if the application has specifically asked for wide-color we avoid
+        // the deadlock with SurfaceFlinger since it will not ask for a
+        // wide-color surface.
+        int err = native_window_get_wide_color_support(window, &windowSupportsWideColor);
+
+        if (err) {
+            ALOGE("processAttributes: invalid window (win=%p) "
+                  "failed (%#x) (already connected to another API?)",
+                  window, err);
+            return false;
+        }
+        if (!windowSupportsWideColor) {
+            // Application has asked for a wide-color colorspace but
+            // wide-color support isn't available on the display the window is on.
+            return false;
+        }
     }
     return true;
 }
 
-static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
-                                         EGLint& colorSpace, android_dataspace& dataSpace) {
-    return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
-}
-
-void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
+// Gets the native pixel format corrsponding to the passed EGLConfig.
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
+                          android_pixel_format* format) {
     // Set the native window's buffers format to match what this config requests.
     // Whether to use sRGB gamma is not part of the EGLconfig, but is part
     // of our native format. So if sRGB gamma is requested, we have to
@@ -639,42 +641,67 @@
     // endif
     if (a == 0) {
         if (colorDepth <= 16) {
-            format = HAL_PIXEL_FORMAT_RGB_565;
+            *format = HAL_PIXEL_FORMAT_RGB_565;
         } else {
             if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
                 if (colorDepth > 24) {
-                    format = HAL_PIXEL_FORMAT_RGBA_1010102;
+                    *format = HAL_PIXEL_FORMAT_RGBA_1010102;
                 } else {
-                    format = HAL_PIXEL_FORMAT_RGBX_8888;
+                    *format = HAL_PIXEL_FORMAT_RGBX_8888;
                 }
             } else {
-                format = HAL_PIXEL_FORMAT_RGBA_FP16;
+                *format = HAL_PIXEL_FORMAT_RGBA_FP16;
             }
         }
     } else {
         if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
             if (colorDepth > 24) {
-                format = HAL_PIXEL_FORMAT_RGBA_1010102;
+                *format = HAL_PIXEL_FORMAT_RGBA_1010102;
             } else {
-                format = HAL_PIXEL_FORMAT_RGBA_8888;
+                *format = HAL_PIXEL_FORMAT_RGBA_8888;
             }
         } else {
-            format = HAL_PIXEL_FORMAT_RGBA_FP16;
+            *format = HAL_PIXEL_FORMAT_RGBA_FP16;
         }
     }
 }
 
+EGLBoolean sendSurfaceMetadata(egl_surface_t* s) {
+    android_smpte2086_metadata smpteMetadata;
+    if (s->getSmpte2086Metadata(smpteMetadata)) {
+        int err =
+                native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
+        s->resetSmpte2086Metadata();
+        if (err != 0) {
+            ALOGE("error setting native window smpte2086 metadata: %s (%d)",
+                  strerror(-err), err);
+            return EGL_FALSE;
+        }
+    }
+    android_cta861_3_metadata cta8613Metadata;
+    if (s->getCta8613Metadata(cta8613Metadata)) {
+        int err =
+                native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
+        s->resetCta8613Metadata();
+        if (err != 0) {
+            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
+                  strerror(-err), err);
+            return EGL_FALSE;
+        }
+    }
+    return EGL_TRUE;
+}
+
 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                     NativeWindowType window,
                                     const EGLint *attrib_list)
 {
+    const EGLint *origAttribList = attrib_list;
     clearError();
 
     egl_connection_t* cnx = NULL;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
-        EGLDisplay iDpy = dp->disp.dpy;
-
         if (!window) {
             return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
@@ -693,39 +720,36 @@
             return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
 
-        EGLint format;
-        getNativePixelFormat(iDpy, cnx, config, format);
+        EGLDisplay iDpy = dp->disp.dpy;
+        android_pixel_format format;
+        getNativePixelFormat(iDpy, cnx, config, &format);
 
         // now select correct colorspace and dataspace based on user's attribute list
-        EGLint colorSpace;
-        android_dataspace dataSpace;
-        if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
+        EGLint colorSpace = EGL_UNKNOWN;
+        std::vector<EGLint> strippedAttribList;
+        if (!processAttributes(dp, window, format, attrib_list, &colorSpace,
+                               &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
             return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
+        attrib_list = strippedAttribList.data();
 
-        std::vector<EGLint> strippedAttribList;
-        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
-            // Had to modify the attribute list due to use of color space.
-            // Use modified list from here on.
-            attrib_list = strippedAttribList.data();
-        }
-
-        if (format != 0) {
+        {
             int err = native_window_set_buffers_format(window, format);
             if (err != 0) {
                 ALOGE("error setting native window pixel format: %s (%d)",
-                        strerror(-err), err);
+                      strerror(-err), err);
                 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
             }
         }
 
-        if (dataSpace != 0) {
+        android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
             int err = native_window_set_buffers_data_space(window, dataSpace);
             if (err != 0) {
                 ALOGE("error setting native window pixel dataSpace: %s (%d)",
-                        strerror(-err), err);
+                      strerror(-err), err);
                 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
             }
@@ -740,7 +764,8 @@
                 iDpy, config, window, attrib_list);
         if (surface != EGL_NO_SURFACE) {
             egl_surface_t* s =
-                    new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx);
+                    new egl_surface_t(dp.get(), config, window, surface,
+                                      getReportedColorSpace(colorSpace), cnx);
             return s;
         }
 
@@ -759,19 +784,27 @@
 
     egl_connection_t* cnx = NULL;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
-    EGLint colorSpace;
-    android_dataspace dataSpace;
     if (dp) {
+        EGLDisplay iDpy = dp->disp.dpy;
+        android_pixel_format format;
+        getNativePixelFormat(iDpy, cnx, config, &format);
+
         // now select a corresponding sRGB format if needed
-        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+        EGLint colorSpace = EGL_UNKNOWN;
+        std::vector<EGLint> strippedAttribList;
+        if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
+                               &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
             return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
+        attrib_list = strippedAttribList.data();
 
         EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
                 dp->disp.dpy, config, pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
+            egl_surface_t* s =
+                    new egl_surface_t(dp.get(), config, NULL, surface,
+                                      getReportedColorSpace(colorSpace), cnx);
             return s;
         }
     }
@@ -787,31 +820,25 @@
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         EGLDisplay iDpy = dp->disp.dpy;
-        EGLint format;
-        getNativePixelFormat(iDpy, cnx, config, format);
+        android_pixel_format format;
+        getNativePixelFormat(iDpy, cnx, config, &format);
 
-        // now select correct colorspace and dataspace based on user's attribute list
-        EGLint colorSpace;
-        android_dataspace dataSpace;
-        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+        // Select correct colorspace based on user's attribute list
+        EGLint colorSpace = EGL_UNKNOWN;
+        std::vector<EGLint> strippedAttribList;
+        if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
+                               &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
             return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
-
-        // Pbuffers are not displayed so we don't need to store the
-        // colorspace. We do need to filter out color spaces the
-        // driver doesn't know how to process.
-        std::vector<EGLint> strippedAttribList;
-        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
-            // Had to modify the attribute list due to use of color space.
-            // Use modified list from here on.
-            attrib_list = strippedAttribList.data();
-        }
+        attrib_list = strippedAttribList.data();
 
         EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
                 dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
+            egl_surface_t* s =
+                    new egl_surface_t(dp.get(), config, NULL, surface,
+                                      getReportedColorSpace(colorSpace), cnx);
             return s;
         }
     }
@@ -850,12 +877,14 @@
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
     egl_surface_t const * const s = get_surface(surface);
-    if (attribute == EGL_GL_COLORSPACE_KHR) {
-        *value = s->getColorSpace();
+    if (s->getColorSpaceAttribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->getSmpte2086Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->getCta8613Attribute(attribute, value)) {
         return EGL_TRUE;
     }
-    return s->cnx->egl.eglQuerySurface(
-            dp->disp.dpy, s->surface, attribute, value);
+    return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value);
 }
 
 void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
@@ -1347,7 +1376,7 @@
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(draw);
+    egl_surface_t* const s = get_surface(draw);
 
     if (CC_UNLIKELY(dp->traceGpuCompletion)) {
         EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
@@ -1366,6 +1395,11 @@
         }
     }
 
+    if (!sendSurfaceMetadata(s)) {
+        native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
+        return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+    }
+
     if (n_rects == 0) {
         return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
     }
@@ -1503,7 +1537,11 @@
         return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
-    if (s->cnx->egl.eglSurfaceAttrib) {
+    if (s->setSmpte2086Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->setCta8613Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
                 dp->disp.dpy, s->surface, attribute, value);
     }
@@ -1707,13 +1745,31 @@
     ContextRef _c(dp.get(), ctx);
     egl_context_t * const c = _c.get();
 
+    // Temporary hack: eglImageCreateKHR should accept EGL_GL_COLORSPACE_LINEAR_KHR,
+    // EGL_GL_COLORSPACE_SRGB_KHR and EGL_GL_COLORSPACE_DEFAULT_EXT if
+    // EGL_EXT_image_gl_colorspace is supported, but some drivers don't like
+    // the DEFAULT value and generate an error.
+    std::vector<EGLint> strippedAttribList;
+    for (const EGLint *attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
+        if (attr[0] == EGL_GL_COLORSPACE_KHR &&
+            dp->haveExtension("EGL_EXT_image_gl_colorspace")) {
+            if (attr[1] != EGL_GL_COLORSPACE_LINEAR_KHR &&
+                attr[1] != EGL_GL_COLORSPACE_SRGB_KHR) {
+                continue;
+            }
+        }
+        strippedAttribList.push_back(attr[0]);
+        strippedAttribList.push_back(attr[1]);
+    }
+    strippedAttribList.push_back(EGL_NONE);
+
     EGLImageKHR result = EGL_NO_IMAGE_KHR;
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->egl.eglCreateImageKHR) {
         result = cnx->egl.eglCreateImageKHR(
                 dp->disp.dpy,
                 c ? c->context : EGL_NO_CONTEXT,
-                target, buffer, attrib_list);
+                target, buffer, strippedAttribList.data());
     }
     return result;
 }
@@ -1925,22 +1981,13 @@
     egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_NO_SURFACE;
 
-    EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
-    android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
-    // TODO: Probably need to update EGL_KHR_stream_producer_eglsurface to
-    // indicate support for EGL_GL_COLORSPACE_KHR.
-    // now select a corresponding sRGB format if needed
-    if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
-        ALOGE("error invalid colorspace: %d", colorSpace);
-        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
-    }
-
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
         EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
                 dp->disp.dpy, config, stream, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface,
+                                                 EGL_GL_COLORSPACE_LINEAR_KHR, cnx);
             return s;
         }
     }
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 579e422..ec548f3 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -20,12 +20,8 @@
 
 #include "egl_display.h"
 
-
 #include <private/EGL/cache.h>
 
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
 #include <thread>
@@ -37,10 +33,6 @@
 static const size_t maxValueSize = 64 * 1024;
 static const size_t maxTotalSize = 2 * 1024 * 1024;
 
-// Cache file header
-static const char* cacheFileMagic = "EGL$";
-static const size_t cacheFileHeaderSize = 8;
-
 // The time in seconds to wait before saving newly inserted cache entries.
 static const unsigned int deferredSaveDelay = 4;
 
@@ -124,7 +116,9 @@
 
 void egl_cache_t::terminate() {
     std::lock_guard<std::mutex> lock(mMutex);
-    saveBlobCacheLocked();
+    if (mBlobCache) {
+        mBlobCache->writeToFile();
+    }
     mBlobCache = NULL;
 }
 
@@ -146,8 +140,8 @@
             std::thread deferredSaveThread([this]() {
                 sleep(deferredSaveDelay);
                 std::lock_guard<std::mutex> lock(mMutex);
-                if (mInitialized) {
-                    saveBlobCacheLocked();
+                if (mInitialized && mBlobCache) {
+                    mBlobCache->writeToFile();
                 }
                 mSavePending = false;
             });
@@ -179,163 +173,11 @@
 
 BlobCache* egl_cache_t::getBlobCacheLocked() {
     if (mBlobCache == nullptr) {
-        mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize));
-        loadBlobCacheLocked();
+        mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
     }
     return mBlobCache.get();
 }
 
-static uint32_t crc32c(const uint8_t* buf, size_t len) {
-    const uint32_t polyBits = 0x82F63B78;
-    uint32_t r = 0;
-    for (size_t i = 0; i < len; i++) {
-        r ^= buf[i];
-        for (int j = 0; j < 8; j++) {
-            if (r & 1) {
-                r = (r >> 1) ^ polyBits;
-            } else {
-                r >>= 1;
-            }
-        }
-    }
-    return r;
-}
-
-void egl_cache_t::saveBlobCacheLocked() {
-    if (mFilename.length() > 0 && mBlobCache != NULL) {
-        size_t cacheSize = mBlobCache->getFlattenedSize();
-        size_t headerSize = cacheFileHeaderSize;
-        const char* fname = mFilename.c_str();
-
-        // Try to create the file with no permissions so we can write it
-        // without anyone trying to read it.
-        int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
-        if (fd == -1) {
-            if (errno == EEXIST) {
-                // The file exists, delete it and try again.
-                if (unlink(fname) == -1) {
-                    // No point in retrying if the unlink failed.
-                    ALOGE("error unlinking cache file %s: %s (%d)", fname,
-                            strerror(errno), errno);
-                    return;
-                }
-                // Retry now that we've unlinked the file.
-                fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
-            }
-            if (fd == -1) {
-                ALOGE("error creating cache file %s: %s (%d)", fname,
-                        strerror(errno), errno);
-                return;
-            }
-        }
-
-        size_t fileSize = headerSize + cacheSize;
-
-        uint8_t* buf = new uint8_t [fileSize];
-        if (!buf) {
-            ALOGE("error allocating buffer for cache contents: %s (%d)",
-                    strerror(errno), errno);
-            close(fd);
-            unlink(fname);
-            return;
-        }
-
-        int err = mBlobCache->flatten(buf + headerSize, cacheSize);
-        if (err < 0) {
-            ALOGE("error writing cache contents: %s (%d)", strerror(-err),
-                    -err);
-            delete [] buf;
-            close(fd);
-            unlink(fname);
-            return;
-        }
-
-        // Write the file magic and CRC
-        memcpy(buf, cacheFileMagic, 4);
-        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
-        *crc = crc32c(buf + headerSize, cacheSize);
-
-        if (write(fd, buf, fileSize) == -1) {
-            ALOGE("error writing cache file: %s (%d)", strerror(errno),
-                    errno);
-            delete [] buf;
-            close(fd);
-            unlink(fname);
-            return;
-        }
-
-        delete [] buf;
-        fchmod(fd, S_IRUSR);
-        close(fd);
-    }
-}
-
-void egl_cache_t::loadBlobCacheLocked() {
-    if (mFilename.length() > 0) {
-        size_t headerSize = cacheFileHeaderSize;
-
-        int fd = open(mFilename.c_str(), O_RDONLY, 0);
-        if (fd == -1) {
-            if (errno != ENOENT) {
-                ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
-                        strerror(errno), errno);
-            }
-            return;
-        }
-
-        struct stat statBuf;
-        if (fstat(fd, &statBuf) == -1) {
-            ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
-            close(fd);
-            return;
-        }
-
-        // Sanity check the size before trying to mmap it.
-        size_t fileSize = statBuf.st_size;
-        if (fileSize > maxTotalSize * 2) {
-            ALOGE("cache file is too large: %#" PRIx64,
-                  static_cast<off64_t>(statBuf.st_size));
-            close(fd);
-            return;
-        }
-
-        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
-                PROT_READ, MAP_PRIVATE, fd, 0));
-        if (buf == MAP_FAILED) {
-            ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
-                    errno);
-            close(fd);
-            return;
-        }
-
-        // Check the file magic and CRC
-        size_t cacheSize = fileSize - headerSize;
-        if (memcmp(buf, cacheFileMagic, 4) != 0) {
-            ALOGE("cache file has bad mojo");
-            close(fd);
-            return;
-        }
-        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
-        if (crc32c(buf + headerSize, cacheSize) != *crc) {
-            ALOGE("cache file failed CRC check");
-            close(fd);
-            return;
-        }
-
-        int err = mBlobCache->unflatten(buf + headerSize, cacheSize);
-        if (err < 0) {
-            ALOGE("error reading cache contents: %s (%d)", strerror(-err),
-                    -err);
-            munmap(buf, fileSize);
-            close(fd);
-            return;
-        }
-
-        munmap(buf, fileSize);
-        close(fd);
-    }
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index 56360f0..7382b91 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -20,7 +20,7 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include "BlobCache.h"
+#include "FileBlobCache.h"
 
 #include <memory>
 #include <mutex>
@@ -82,14 +82,6 @@
     // possible.
     BlobCache* getBlobCacheLocked();
 
-    // saveBlobCache attempts to save the current contents of mBlobCache to
-    // disk.
-    void saveBlobCacheLocked();
-
-    // loadBlobCache attempts to load the saved cache contents from disk into
-    // mBlobCache.
-    void loadBlobCacheLocked();
-
     // mInitialized indicates whether the egl_cache_t is in the initialized
     // state.  It is initialized to false at construction time, and gets set to
     // true when initialize is called.  It is set back to false when terminate
@@ -101,7 +93,7 @@
     // mBlobCache is the cache in which the key/value blob pairs are stored.  It
     // is initially NULL, and will be initialized by getBlobCacheLocked the
     // first time it's needed.
-    std::unique_ptr<BlobCache> mBlobCache;
+    std::unique_ptr<FileBlobCache> mBlobCache;
 
     // mFilename is the name of the file for storing cache contents in between
     // program invocations.  It is initialized to an empty string at
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 4e5833a..2aec249 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -51,8 +51,11 @@
 
 // ----------------------------------------------------------------------------
 
-static bool findExtension(const char* exts, const char* name, size_t nameLen) {
+bool findExtension(const char* exts, const char* name, size_t nameLen) {
     if (exts) {
+        if (!nameLen) {
+            nameLen = strlen(name);
+        }
         for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
             if (match[nameLen] == '\0' || match[nameLen] == ' ') {
                 return true;
@@ -79,6 +82,10 @@
 }
 
 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
+    if (uintptr_t(dpy) == 0) {
+        return nullptr;
+    }
+
     uintptr_t index = uintptr_t(dpy)-1U;
     if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
         return nullptr;
@@ -199,17 +206,33 @@
 
         mExtensionString = gBuiltinExtensionString;
 
+        hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace");
+
+        // Note: CDD requires that devices supporting wide color and/or HDR color also support
+        // the EGL_KHR_gl_colorspace extension.
         bool wideColorBoardConfig =
                 getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
                         false);
 
         // Add wide-color extensions if device can support wide-color
-        if (wideColorBoardConfig) {
+        if (wideColorBoardConfig && hasColorSpaceSupport) {
             mExtensionString.append(
                     "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
                     "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
         }
 
+        bool hasHdrBoardConfig =
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
+        if (hasHdrBoardConfig && hasColorSpaceSupport) {
+            // hasHDRBoardConfig indicates the system is capable of supporting HDR content.
+            // Typically that means there is an HDR capable display attached, but could be
+            // support for attaching an HDR display. In either case, advertise support for
+            // HDR color spaces.
+            mExtensionString.append(
+                    "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
+        }
+
         char const* start = gExtensionString;
         do {
             // length of the extension name
@@ -217,6 +240,12 @@
             if (len) {
                 // NOTE: we could avoid the copy if we had strnstr.
                 const std::string ext(start, len);
+                // Temporary hack: Adreno 530 driver exposes this extension under the draft
+                // KHR name, but during Khronos review it was decided to demote it to EXT.
+                if (ext == "EGL_EXT_image_gl_colorspace" &&
+                    findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
+                    mExtensionString.append("EGL_EXT_image_gl_colorspace ");
+                }
                 if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
                     mExtensionString.append(ext + " ");
                 }
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 661f47e..79a9f08 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -42,6 +42,8 @@
 class egl_context_t;
 struct egl_connection_t;
 
+bool findExtension(const char* exts, const char* name, size_t nameLen = 0);
+
 // ----------------------------------------------------------------------------
 
 class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
@@ -111,6 +113,7 @@
     DisplayImpl     disp;
     bool    finishOnSwap;       // property: debug.egl.finish
     bool    traceGpuCompletion; // property: debug.egl.traceGpuCompletion
+    bool    hasColorSpaceSupport;
 
 private:
     friend class egl_display_ptr;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 837cfa9..f879254 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -63,7 +63,18 @@
         win(win),
         cnx(cnx),
         connected(true),
-        colorSpace(colorSpace) {
+        colorSpace(colorSpace),
+        egl_smpte2086_dirty(false),
+        egl_cta861_3_dirty(false) {
+    egl_smpte2086_metadata.displayPrimaryRed = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.displayPrimaryGreen = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.displayPrimaryBlue = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.whitePoint = { EGL_DONT_CARE, EGL_DONT_CARE };
+    egl_smpte2086_metadata.maxLuminance = EGL_DONT_CARE;
+    egl_smpte2086_metadata.minLuminance = EGL_DONT_CARE;
+    egl_cta861_3_metadata.maxFrameAverageLightLevel = EGL_DONT_CARE;
+    egl_cta861_3_metadata.maxContentLightLevel = EGL_DONT_CARE;
+
     if (win) {
         win->incStrong(this);
     }
@@ -86,6 +97,180 @@
     }
 }
 
+EGLBoolean egl_surface_t::setSmpte2086Attribute(EGLint attribute, EGLint value) {
+    switch (attribute) {
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
+            egl_smpte2086_metadata.displayPrimaryRed.x = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
+            egl_smpte2086_metadata.displayPrimaryRed.y = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
+            egl_smpte2086_metadata.displayPrimaryGreen.x = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
+            egl_smpte2086_metadata.displayPrimaryGreen.y = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
+            egl_smpte2086_metadata.displayPrimaryBlue.x = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
+            egl_smpte2086_metadata.displayPrimaryBlue.y = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_WHITE_POINT_X_EXT:
+            egl_smpte2086_metadata.whitePoint.x = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
+            egl_smpte2086_metadata.whitePoint.y = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
+            egl_smpte2086_metadata.maxLuminance = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
+            egl_smpte2086_metadata.minLuminance = value;
+            egl_smpte2086_dirty = true;
+            return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::setCta8613Attribute(EGLint attribute, EGLint value) {
+    switch (attribute) {
+        case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
+            egl_cta861_3_metadata.maxContentLightLevel = value;
+            egl_cta861_3_dirty = true;
+            return EGL_TRUE;
+        case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
+            egl_cta861_3_metadata.maxFrameAverageLightLevel = value;
+            egl_cta861_3_dirty = true;
+            return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getSmpte2086Metadata(android_smpte2086_metadata& metadata) const {
+    if (!egl_smpte2086_dirty) return EGL_FALSE;
+    if (egl_smpte2086_metadata.displayPrimaryRed.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryRed.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryGreen.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryGreen.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryBlue.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.displayPrimaryBlue.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.whitePoint.x == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.whitePoint.y == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.maxLuminance == EGL_DONT_CARE ||
+        egl_smpte2086_metadata.minLuminance == EGL_DONT_CARE) {
+        ALOGW("egl_surface_t: incomplete SMPTE 2086 metadata!");
+        return EGL_FALSE;
+    }
+
+    metadata.displayPrimaryRed.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryRed.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryRed.y) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryGreen.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryGreen.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryGreen.y) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryBlue.x = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.x) / EGL_METADATA_SCALING_EXT;
+    metadata.displayPrimaryBlue.y = static_cast<float>(egl_smpte2086_metadata.displayPrimaryBlue.y) / EGL_METADATA_SCALING_EXT;
+    metadata.whitePoint.x = static_cast<float>(egl_smpte2086_metadata.whitePoint.x) / EGL_METADATA_SCALING_EXT;
+    metadata.whitePoint.y = static_cast<float>(egl_smpte2086_metadata.whitePoint.y) / EGL_METADATA_SCALING_EXT;
+    metadata.maxLuminance = static_cast<float>(egl_smpte2086_metadata.maxLuminance) / EGL_METADATA_SCALING_EXT;
+    metadata.minLuminance = static_cast<float>(egl_smpte2086_metadata.minLuminance) / EGL_METADATA_SCALING_EXT;
+
+    return EGL_TRUE;
+}
+
+EGLBoolean egl_surface_t::getCta8613Metadata(android_cta861_3_metadata& metadata) const {
+    if (!egl_cta861_3_dirty) return EGL_FALSE;
+
+    if (egl_cta861_3_metadata.maxContentLightLevel == EGL_DONT_CARE ||
+        egl_cta861_3_metadata.maxFrameAverageLightLevel == EGL_DONT_CARE) {
+        ALOGW("egl_surface_t: incomplete CTA861.3 metadata!");
+        return EGL_FALSE;
+    }
+
+    metadata.maxContentLightLevel = static_cast<float>(egl_cta861_3_metadata.maxContentLightLevel) / EGL_METADATA_SCALING_EXT;
+    metadata.maxFrameAverageLightLevel = static_cast<float>(egl_cta861_3_metadata.maxFrameAverageLightLevel) / EGL_METADATA_SCALING_EXT;
+
+    return EGL_TRUE;
+}
+
+
+EGLBoolean egl_surface_t::getColorSpaceAttribute(EGLint attribute, EGLint* value) const {
+    if (attribute == EGL_GL_COLORSPACE_KHR) {
+        *value = colorSpace;
+        return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getSmpte2086Attribute(EGLint attribute, EGLint *value) const {
+    switch (attribute) {
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryRed.x;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryRed.y;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryGreen.x;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryGreen.y;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryBlue.x;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
+            *value = egl_smpte2086_metadata.displayPrimaryBlue.y;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_WHITE_POINT_X_EXT:
+            *value = egl_smpte2086_metadata.whitePoint.x;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
+            *value = egl_smpte2086_metadata.whitePoint.y;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
+            *value = egl_smpte2086_metadata.maxLuminance;
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
+            *value = egl_smpte2086_metadata.minLuminance;
+            return EGL_TRUE;
+            break;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getCta8613Attribute(EGLint attribute, EGLint *value) const {
+    switch (attribute) {
+        case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
+            *value = egl_cta861_3_metadata.maxContentLightLevel;
+            return EGL_TRUE;
+            break;
+        case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
+            *value = egl_cta861_3_metadata.maxFrameAverageLightLevel;
+            return EGL_TRUE;
+            break;
+    }
+    return EGL_FALSE;
+}
+
 void egl_surface_t::terminate() {
     disconnect();
     egl_object_t::terminate();
@@ -116,17 +301,23 @@
     if (gl_extensions.empty()) {
         // call the implementation's glGetString(GL_EXTENSIONS)
         const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
-        gl_extensions = exts;
-        if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
-            gl_extensions.insert(0, "GL_EXT_debug_marker ");
-        }
 
-        // tokenize the supported extensions for the glGetStringi() wrapper
-        std::stringstream ss;
-        std::string str;
-        ss << gl_extensions;
-        while (ss >> str) {
-            tokenized_gl_extensions.push_back(str);
+        // If this context is sharing with another context, and the other context was reset
+        // e.g. due to robustness failure, this context might also be reset and glGetString can
+        // return NULL.
+        if (exts) {
+            gl_extensions = exts;
+            if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
+                gl_extensions.insert(0, "GL_EXT_debug_marker ");
+            }
+
+            // tokenize the supported extensions for the glGetStringi() wrapper
+            std::stringstream ss;
+            std::string str;
+            ss << gl_extensions;
+            while (ss >> str) {
+                tokenized_gl_extensions.push_back(str);
+            }
         }
     }
 }
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 7c3075c..4e1de5c 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -137,6 +137,15 @@
     ANativeWindow* getNativeWindow() { return win; }
     ANativeWindow* getNativeWindow() const { return win; }
     EGLint getColorSpace() const { return colorSpace; }
+    EGLBoolean setSmpte2086Attribute(EGLint attribute, EGLint value);
+    EGLBoolean setCta8613Attribute(EGLint attribute, EGLint value);
+    EGLBoolean getColorSpaceAttribute(EGLint attribute, EGLint* value) const;
+    EGLBoolean getSmpte2086Attribute(EGLint attribute, EGLint* value) const;
+    EGLBoolean getCta8613Attribute(EGLint attribute, EGLint* value) const;
+    EGLBoolean getSmpte2086Metadata(android_smpte2086_metadata& smpte2086) const;
+    EGLBoolean getCta8613Metadata(android_cta861_3_metadata& cta861_3) const;
+    void resetSmpte2086Metadata() { egl_smpte2086_dirty = false; }
+    void resetCta8613Metadata() { egl_cta861_3_dirty = false; }
 
     // Try to keep the order of these fields and size unchanged. It's not public API, but
     // it's not hard to imagine native games accessing them.
@@ -150,6 +159,31 @@
     bool connected;
     void disconnect();
     EGLint colorSpace;
+
+    struct egl_xy_color {
+        EGLint x;
+        EGLint y;
+    };
+
+    struct egl_smpte2086_metadata {
+        struct egl_xy_color displayPrimaryRed;
+        struct egl_xy_color displayPrimaryGreen;
+        struct egl_xy_color displayPrimaryBlue;
+        struct egl_xy_color whitePoint;
+        EGLint maxLuminance;
+        EGLint minLuminance;
+    };
+
+    struct egl_cta861_3_metadata {
+        EGLint maxContentLightLevel;
+        EGLint maxFrameAverageLightLevel;
+    };
+
+    bool egl_smpte2086_dirty;
+    bool egl_cta861_3_dirty;
+
+    egl_smpte2086_metadata egl_smpte2086_metadata;
+    egl_cta861_3_metadata egl_cta861_3_metadata;
 };
 
 class egl_context_t: public egl_object_t {
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index c05e840..fedc789 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -54,7 +54,7 @@
             : [tls] "J"(TLS_SLOT_OPENGL_API*4),                 \
               [ext] "J"(__builtin_offsetof(gl_hooks_t,          \
                                       ext.extensions[0])),      \
-              [api] "J"(_api*sizeof(void*))                     \
+              [api] "I"(_api*sizeof(void*))                     \
             : "r12"                                             \
             );
 
@@ -80,46 +80,44 @@
 
 #elif defined(__i386__)
 
-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+    #define API_ENTRY(_api) __attribute__((naked)) _api
 
     #define CALL_GL_EXTENSION_API(_api)                         \
-         register void** fn;                                    \
          __asm__ volatile(                                      \
-            "mov %%gs:0, %[fn]\n"                               \
-            "mov %P[tls](%[fn]), %[fn]\n"                       \
-            "test %[fn], %[fn]\n"                               \
-            "cmovne %P[api](%[fn]), %[fn]\n"                    \
-            "test %[fn], %[fn]\n"                               \
+            "mov %%gs:0, %%eax\n"                               \
+            "mov %P[tls](%%eax), %%eax\n"                       \
+            "test %%eax, %%eax\n"                               \
+            "cmovne %P[api](%%eax), %%eax\n"                    \
+            "test %%eax, %%eax\n"                               \
             "je 1f\n"                                           \
-            "jmp *%[fn]\n"                                      \
-            "1:\n"                                              \
-            : [fn] "=r" (fn)                                    \
+            "jmp *%%eax\n"                                      \
+            "1: ret\n"                                          \
+            :                                                   \
             : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),    \
               [api] "i" (__builtin_offsetof(gl_hooks_t,         \
                                       ext.extensions[_api]))    \
-            : "cc"                                              \
+            : "eax", "cc"                                       \
             );
 
 #elif defined(__x86_64__)
 
-    #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+    #define API_ENTRY(_api) __attribute__((naked)) _api
 
     #define CALL_GL_EXTENSION_API(_api)                         \
-         register void** fn;                                    \
          __asm__ volatile(                                      \
-            "mov %%fs:0, %[fn]\n"                               \
-            "mov %P[tls](%[fn]), %[fn]\n"                       \
-            "test %[fn], %[fn]\n"                               \
-            "cmovne %P[api](%[fn]), %[fn]\n"                    \
-            "test %[fn], %[fn]\n"                               \
+            "mov %%fs:0, %%rax\n"                               \
+            "mov %P[tls](%%rax), %%rax\n"                       \
+            "test %%rax, %%rax\n"                               \
+            "cmovne %P[api](%%rax), %%rax\n"                    \
+            "test %%rax, %%rax\n"                               \
             "je 1f\n"                                           \
-            "jmp *%[fn]\n"                                      \
-            "1:\n"                                              \
-            : [fn] "=r" (fn)                                    \
+            "jmp *%%rax\n"                                      \
+            "1: ret\n"                                          \
+            :                                                   \
             : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)),    \
               [api] "i" (__builtin_offsetof(gl_hooks_t,         \
                                       ext.extensions[_api]))    \
-            : "cc"                                              \
+            : "rax", "cc"                                       \
             );
 
 #elif defined(__mips64)
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
index fc368f2..4a0d4b9 100644
--- a/opengl/libs/GLES2/gl2ext_api.in
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -34,6 +34,9 @@
 void API_ENTRY(glGetPointervKHR)(GLenum pname, void **params) {
     CALL_GL_API(glGetPointervKHR, pname, params);
 }
+void API_ENTRY(glMaxShaderCompilerThreadsKHR)(GLuint count) {
+    CALL_GL_API(glMaxShaderCompilerThreadsKHR, count);
+}
 GLenum API_ENTRY(glGetGraphicsResetStatusKHR)(void) {
     CALL_GL_API_RETURN(glGetGraphicsResetStatusKHR);
 }
@@ -91,8 +94,8 @@
 void API_ENTRY(glDrawElementsInstancedBaseVertexOES)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) {
     CALL_GL_API(glDrawElementsInstancedBaseVertexOES, mode, count, type, indices, instancecount, basevertex);
 }
-void API_ENTRY(glMultiDrawElementsBaseVertexOES)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) {
-    CALL_GL_API(glMultiDrawElementsBaseVertexOES, mode, count, type, indices, primcount, basevertex);
+void API_ENTRY(glMultiDrawElementsBaseVertexEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) {
+    CALL_GL_API(glMultiDrawElementsBaseVertexEXT, mode, count, type, indices, primcount, basevertex);
 }
 void API_ENTRY(glFramebufferTextureOES)(GLenum target, GLenum attachment, GLuint texture, GLint level) {
     CALL_GL_API(glFramebufferTextureOES, target, attachment, texture, level);
@@ -187,6 +190,33 @@
 GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) {
     CALL_GL_API_RETURN(glIsVertexArrayOES, array);
 }
+void API_ENTRY(glViewportArrayvOES)(GLuint first, GLsizei count, const GLfloat *v) {
+    CALL_GL_API(glViewportArrayvOES, first, count, v);
+}
+void API_ENTRY(glViewportIndexedfOES)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
+    CALL_GL_API(glViewportIndexedfOES, index, x, y, w, h);
+}
+void API_ENTRY(glViewportIndexedfvOES)(GLuint index, const GLfloat *v) {
+    CALL_GL_API(glViewportIndexedfvOES, index, v);
+}
+void API_ENTRY(glScissorArrayvOES)(GLuint first, GLsizei count, const GLint *v) {
+    CALL_GL_API(glScissorArrayvOES, first, count, v);
+}
+void API_ENTRY(glScissorIndexedOES)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) {
+    CALL_GL_API(glScissorIndexedOES, index, left, bottom, width, height);
+}
+void API_ENTRY(glScissorIndexedvOES)(GLuint index, const GLint *v) {
+    CALL_GL_API(glScissorIndexedvOES, index, v);
+}
+void API_ENTRY(glDepthRangeArrayfvOES)(GLuint first, GLsizei count, const GLfloat *v) {
+    CALL_GL_API(glDepthRangeArrayfvOES, first, count, v);
+}
+void API_ENTRY(glDepthRangeIndexedfOES)(GLuint index, GLfloat n, GLfloat f) {
+    CALL_GL_API(glDepthRangeIndexedfOES, index, n, f);
+}
+void API_ENTRY(glGetFloati_vOES)(GLenum target, GLuint index, GLfloat *data) {
+    CALL_GL_API(glGetFloati_vOES, target, index, data);
+}
 void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) {
     CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups);
 }
@@ -268,6 +298,12 @@
 void API_ENTRY(glGetSyncivAPPLE)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) {
     CALL_GL_API(glGetSyncivAPPLE, sync, pname, bufSize, length, values);
 }
+void API_ENTRY(glEGLImageTargetTexStorageEXT)(GLenum target, GLeglImageOES image, const GLint* attrib_list) {
+    CALL_GL_API(glEGLImageTargetTexStorageEXT, target, image, attrib_list);
+}
+void API_ENTRY(glEGLImageTargetTextureStorageEXT)(GLuint texture, GLeglImageOES image, const GLint* attrib_list) {
+    CALL_GL_API(glEGLImageTargetTextureStorageEXT, texture, image, attrib_list);
+}
 void API_ENTRY(glDrawArraysInstancedBaseInstanceEXT)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) {
     CALL_GL_API(glDrawArraysInstancedBaseInstanceEXT, mode, first, count, instancecount, baseinstance);
 }
@@ -292,6 +328,15 @@
 void API_ENTRY(glBufferStorageEXT)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags) {
     CALL_GL_API(glBufferStorageEXT, target, size, data, flags);
 }
+void API_ENTRY(glClearTexImageEXT)(GLuint texture, GLint level, GLenum format, GLenum type, const void *data) {
+    CALL_GL_API(glClearTexImageEXT, texture, level, format, type, data);
+}
+void API_ENTRY(glClearTexSubImageEXT)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data) {
+    CALL_GL_API(glClearTexSubImageEXT, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
+}
+void API_ENTRY(glClipControlEXT)(GLenum origin, GLenum depth) {
+    CALL_GL_API(glClipControlEXT, origin, depth);
+}
 void API_ENTRY(glCopyImageSubDataEXT)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) {
     CALL_GL_API(glCopyImageSubDataEXT, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth);
 }
@@ -382,8 +427,8 @@
 void API_ENTRY(glDrawElementsInstancedBaseVertexEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) {
     CALL_GL_API(glDrawElementsInstancedBaseVertexEXT, mode, count, type, indices, instancecount, basevertex);
 }
-void API_ENTRY(glMultiDrawElementsBaseVertexEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) {
-    CALL_GL_API(glMultiDrawElementsBaseVertexEXT, mode, count, type, indices, primcount, basevertex);
+void API_ENTRY(glMultiDrawElementsBaseVertexOES)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) {
+    CALL_GL_API(glMultiDrawElementsBaseVertexOES, mode, count, type, indices, primcount, basevertex);
 }
 void API_ENTRY(glDrawArraysInstancedEXT)(GLenum mode, GLint start, GLsizei count, GLsizei primcount) {
     CALL_GL_API(glDrawArraysInstancedEXT, mode, start, count, primcount);
@@ -391,6 +436,18 @@
 void API_ENTRY(glDrawElementsInstancedEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) {
     CALL_GL_API(glDrawElementsInstancedEXT, mode, count, type, indices, primcount);
 }
+void API_ENTRY(glDrawTransformFeedbackEXT)(GLenum mode, GLuint id) {
+    CALL_GL_API(glDrawTransformFeedbackEXT, mode, id);
+}
+void API_ENTRY(glDrawTransformFeedbackInstancedEXT)(GLenum mode, GLuint id, GLsizei instancecount) {
+    CALL_GL_API(glDrawTransformFeedbackInstancedEXT, mode, id, instancecount);
+}
+void API_ENTRY(glBufferStorageExternalEXT)(GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags) {
+    CALL_GL_API(glBufferStorageExternalEXT, target, offset, size, clientBuffer, flags);
+}
+void API_ENTRY(glNamedBufferStorageExternalEXT)(GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags) {
+    CALL_GL_API(glNamedBufferStorageExternalEXT, buffer, offset, size, clientBuffer, flags);
+}
 void API_ENTRY(glFramebufferTextureEXT)(GLenum target, GLenum attachment, GLuint texture, GLint level) {
     CALL_GL_API(glFramebufferTextureEXT, target, attachment, texture, level);
 }
@@ -403,6 +460,60 @@
 void API_ENTRY(glFlushMappedBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length) {
     CALL_GL_API(glFlushMappedBufferRangeEXT, target, offset, length);
 }
+void API_ENTRY(glGetUnsignedBytevEXT)(GLenum pname, GLubyte *data) {
+    CALL_GL_API(glGetUnsignedBytevEXT, pname, data);
+}
+void API_ENTRY(glGetUnsignedBytei_vEXT)(GLenum target, GLuint index, GLubyte *data) {
+    CALL_GL_API(glGetUnsignedBytei_vEXT, target, index, data);
+}
+void API_ENTRY(glDeleteMemoryObjectsEXT)(GLsizei n, const GLuint *memoryObjects) {
+    CALL_GL_API(glDeleteMemoryObjectsEXT, n, memoryObjects);
+}
+GLboolean API_ENTRY(glIsMemoryObjectEXT)(GLuint memoryObject) {
+    CALL_GL_API_RETURN(glIsMemoryObjectEXT, memoryObject);
+}
+void API_ENTRY(glCreateMemoryObjectsEXT)(GLsizei n, GLuint *memoryObjects) {
+    CALL_GL_API(glCreateMemoryObjectsEXT, n, memoryObjects);
+}
+void API_ENTRY(glMemoryObjectParameterivEXT)(GLuint memoryObject, GLenum pname, const GLint *params) {
+    CALL_GL_API(glMemoryObjectParameterivEXT, memoryObject, pname, params);
+}
+void API_ENTRY(glGetMemoryObjectParameterivEXT)(GLuint memoryObject, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetMemoryObjectParameterivEXT, memoryObject, pname, params);
+}
+void API_ENTRY(glTexStorageMem2DEXT)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTexStorageMem2DEXT, target, levels, internalFormat, width, height, memory, offset);
+}
+void API_ENTRY(glTexStorageMem2DMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTexStorageMem2DMultisampleEXT, target, samples, internalFormat, width, height, fixedSampleLocations, memory, offset);
+}
+void API_ENTRY(glTexStorageMem3DEXT)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTexStorageMem3DEXT, target, levels, internalFormat, width, height, depth, memory, offset);
+}
+void API_ENTRY(glTexStorageMem3DMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTexStorageMem3DMultisampleEXT, target, samples, internalFormat, width, height, depth, fixedSampleLocations, memory, offset);
+}
+void API_ENTRY(glBufferStorageMemEXT)(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glBufferStorageMemEXT, target, size, memory, offset);
+}
+void API_ENTRY(glTextureStorageMem2DEXT)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTextureStorageMem2DEXT, texture, levels, internalFormat, width, height, memory, offset);
+}
+void API_ENTRY(glTextureStorageMem2DMultisampleEXT)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTextureStorageMem2DMultisampleEXT, texture, samples, internalFormat, width, height, fixedSampleLocations, memory, offset);
+}
+void API_ENTRY(glTextureStorageMem3DEXT)(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTextureStorageMem3DEXT, texture, levels, internalFormat, width, height, depth, memory, offset);
+}
+void API_ENTRY(glTextureStorageMem3DMultisampleEXT)(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glTextureStorageMem3DMultisampleEXT, texture, samples, internalFormat, width, height, depth, fixedSampleLocations, memory, offset);
+}
+void API_ENTRY(glNamedBufferStorageMemEXT)(GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset) {
+    CALL_GL_API(glNamedBufferStorageMemEXT, buffer, size, memory, offset);
+}
+void API_ENTRY(glImportMemoryFdEXT)(GLuint memory, GLuint64 size, GLenum handleType, GLint fd) {
+    CALL_GL_API(glImportMemoryFdEXT, memory, size, handleType, fd);
+}
 void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) {
     CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount);
 }
@@ -430,6 +541,9 @@
 void API_ENTRY(glGetIntegeri_vEXT)(GLenum target, GLuint index, GLint *data) {
     CALL_GL_API(glGetIntegeri_vEXT, target, index, data);
 }
+void API_ENTRY(glPolygonOffsetClampEXT)(GLfloat factor, GLfloat units, GLfloat clamp) {
+    CALL_GL_API(glPolygonOffsetClampEXT, factor, units, clamp);
+}
 void API_ENTRY(glPrimitiveBoundingBoxEXT)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) {
     CALL_GL_API(glPrimitiveBoundingBoxEXT, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW);
 }
@@ -448,6 +562,30 @@
 void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
     CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params);
 }
+void API_ENTRY(glGenSemaphoresEXT)(GLsizei n, GLuint *semaphores) {
+    CALL_GL_API(glGenSemaphoresEXT, n, semaphores);
+}
+void API_ENTRY(glDeleteSemaphoresEXT)(GLsizei n, const GLuint *semaphores) {
+    CALL_GL_API(glDeleteSemaphoresEXT, n, semaphores);
+}
+GLboolean API_ENTRY(glIsSemaphoreEXT)(GLuint semaphore) {
+    CALL_GL_API_RETURN(glIsSemaphoreEXT, semaphore);
+}
+void API_ENTRY(glSemaphoreParameterui64vEXT)(GLuint semaphore, GLenum pname, const GLuint64 *params) {
+    CALL_GL_API(glSemaphoreParameterui64vEXT, semaphore, pname, params);
+}
+void API_ENTRY(glGetSemaphoreParameterui64vEXT)(GLuint semaphore, GLenum pname, GLuint64 *params) {
+    CALL_GL_API(glGetSemaphoreParameterui64vEXT, semaphore, pname, params);
+}
+void API_ENTRY(glWaitSemaphoreEXT)(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts) {
+    CALL_GL_API(glWaitSemaphoreEXT, semaphore, numBufferBarriers, buffers, numTextureBarriers, textures, srcLayouts);
+}
+void API_ENTRY(glSignalSemaphoreEXT)(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts) {
+    CALL_GL_API(glSignalSemaphoreEXT, semaphore, numBufferBarriers, buffers, numTextureBarriers, textures, dstLayouts);
+}
+void API_ENTRY(glImportSemaphoreFdEXT)(GLuint semaphore, GLenum handleType, GLint fd) {
+    CALL_GL_API(glImportSemaphoreFdEXT, semaphore, handleType, fd);
+}
 void API_ENTRY(glActiveShaderProgramEXT)(GLuint pipeline, GLuint program) {
     CALL_GL_API(glActiveShaderProgramEXT, pipeline, program);
 }
@@ -580,6 +718,18 @@
 void API_ENTRY(glProgramUniformMatrix4x3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
     CALL_GL_API(glProgramUniformMatrix4x3fvEXT, program, location, count, transpose, value);
 }
+void API_ENTRY(glFramebufferFetchBarrierEXT)(void) {
+    CALL_GL_API(glFramebufferFetchBarrierEXT);
+}
+void API_ENTRY(glFramebufferPixelLocalStorageSizeEXT)(GLuint target, GLsizei size) {
+    CALL_GL_API(glFramebufferPixelLocalStorageSizeEXT, target, size);
+}
+GLsizei API_ENTRY(glGetFramebufferPixelLocalStorageSizeEXT)(GLuint target) {
+    CALL_GL_API_RETURN(glGetFramebufferPixelLocalStorageSizeEXT, target);
+}
+void API_ENTRY(glClearPixelLocalStorageuiEXT)(GLsizei offset, GLsizei n, const GLuint *values) {
+    CALL_GL_API(glClearPixelLocalStorageuiEXT, offset, n, values);
+}
 void API_ENTRY(glTexPageCommitmentEXT)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit) {
     CALL_GL_API(glTexPageCommitmentEXT, target, level, xoffset, yoffset, zoffset, width, height, depth, commit);
 }
@@ -637,6 +787,33 @@
 void API_ENTRY(glTextureViewEXT)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) {
     CALL_GL_API(glTextureViewEXT, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers);
 }
+void API_ENTRY(glWindowRectanglesEXT)(GLenum mode, GLsizei count, const GLint *box) {
+    CALL_GL_API(glWindowRectanglesEXT, mode, count, box);
+}
+GLuint64 API_ENTRY(glGetTextureHandleIMG)(GLuint texture) {
+    CALL_GL_API_RETURN(glGetTextureHandleIMG, texture);
+}
+GLuint64 API_ENTRY(glGetTextureSamplerHandleIMG)(GLuint texture, GLuint sampler) {
+    CALL_GL_API_RETURN(glGetTextureSamplerHandleIMG, texture, sampler);
+}
+void API_ENTRY(glUniformHandleui64IMG)(GLint location, GLuint64 value) {
+    CALL_GL_API(glUniformHandleui64IMG, location, value);
+}
+void API_ENTRY(glUniformHandleui64vIMG)(GLint location, GLsizei count, const GLuint64 *value) {
+    CALL_GL_API(glUniformHandleui64vIMG, location, count, value);
+}
+void API_ENTRY(glProgramUniformHandleui64IMG)(GLuint program, GLint location, GLuint64 value) {
+    CALL_GL_API(glProgramUniformHandleui64IMG, program, location, value);
+}
+void API_ENTRY(glProgramUniformHandleui64vIMG)(GLuint program, GLint location, GLsizei count, const GLuint64 *values) {
+    CALL_GL_API(glProgramUniformHandleui64vIMG, program, location, count, values);
+}
+void API_ENTRY(glFramebufferTexture2DDownsampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale) {
+    CALL_GL_API(glFramebufferTexture2DDownsampleIMG, target, attachment, textarget, texture, level, xscale, yscale);
+}
+void API_ENTRY(glFramebufferTextureLayerDownsampleIMG)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale) {
+    CALL_GL_API(glFramebufferTextureLayerDownsampleIMG, target, attachment, texture, level, layer, xscale, yscale);
+}
 void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
     CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height);
 }
@@ -667,7 +844,7 @@
 void API_ENTRY(glGetPerfCounterInfoINTEL)(GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue) {
     CALL_GL_API(glGetPerfCounterInfoINTEL, queryId, counterId, counterNameLength, counterName, counterDescLength, counterDesc, counterOffset, counterDataSize, counterTypeEnum, counterDataTypeEnum, rawCounterMaxValue);
 }
-void API_ENTRY(glGetPerfQueryDataINTEL)(GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten) {
+void API_ENTRY(glGetPerfQueryDataINTEL)(GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten) {
     CALL_GL_API(glGetPerfQueryDataINTEL, queryHandle, flags, dataSize, data, bytesWritten);
 }
 void API_ENTRY(glGetPerfQueryIdByNameINTEL)(GLchar *queryName, GLuint *queryId) {
@@ -721,6 +898,9 @@
 void API_ENTRY(glBlendBarrierNV)(void) {
     CALL_GL_API(glBlendBarrierNV);
 }
+void API_ENTRY(glViewportPositionWScaleNV)(GLuint index, GLfloat xcoeff, GLfloat ycoeff) {
+    CALL_GL_API(glViewportPositionWScaleNV, index, xcoeff, ycoeff);
+}
 void API_ENTRY(glBeginConditionalRenderNV)(GLuint id, GLenum mode) {
     CALL_GL_API(glBeginConditionalRenderNV, id, mode);
 }
@@ -730,6 +910,9 @@
 void API_ENTRY(glSubpixelPrecisionBiasNV)(GLuint xbits, GLuint ybits) {
     CALL_GL_API(glSubpixelPrecisionBiasNV, xbits, ybits);
 }
+void API_ENTRY(glConservativeRasterParameteriNV)(GLenum pname, GLint param) {
+    CALL_GL_API(glConservativeRasterParameteriNV, pname, param);
+}
 void API_ENTRY(glCopyBufferSubDataNV)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
     CALL_GL_API(glCopyBufferSubDataNV, readTarget, writeTarget, readOffset, writeOffset, size);
 }
@@ -748,6 +931,21 @@
 void API_ENTRY(glDrawElementsInstancedNV)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) {
     CALL_GL_API(glDrawElementsInstancedNV, mode, count, type, indices, primcount);
 }
+void API_ENTRY(glDrawVkImageNV)(GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1) {
+    CALL_GL_API(glDrawVkImageNV, vkImage, sampler, x0, y0, x1, y1, z, s0, t0, s1, t1);
+}
+GLVULKANPROCNV API_ENTRY(glGetVkProcAddrNV)(const GLchar *name) {
+    CALL_GL_API_RETURN(glGetVkProcAddrNV, name);
+}
+void API_ENTRY(glWaitVkSemaphoreNV)(GLuint64 vkSemaphore) {
+    CALL_GL_API(glWaitVkSemaphoreNV, vkSemaphore);
+}
+void API_ENTRY(glSignalVkSemaphoreNV)(GLuint64 vkSemaphore) {
+    CALL_GL_API(glSignalVkSemaphoreNV, vkSemaphore);
+}
+void API_ENTRY(glSignalVkFenceNV)(GLuint64 vkFence) {
+    CALL_GL_API(glSignalVkFenceNV, vkFence);
+}
 void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
     CALL_GL_API(glDeleteFencesNV, n, fences);
 }
@@ -787,6 +985,105 @@
 void API_ENTRY(glRenderbufferStorageMultisampleNV)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
     CALL_GL_API(glRenderbufferStorageMultisampleNV, target, samples, internalformat, width, height);
 }
+void API_ENTRY(glUniform1i64NV)(GLint location, GLint64EXT x) {
+    CALL_GL_API(glUniform1i64NV, location, x);
+}
+void API_ENTRY(glUniform2i64NV)(GLint location, GLint64EXT x, GLint64EXT y) {
+    CALL_GL_API(glUniform2i64NV, location, x, y);
+}
+void API_ENTRY(glUniform3i64NV)(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z) {
+    CALL_GL_API(glUniform3i64NV, location, x, y, z);
+}
+void API_ENTRY(glUniform4i64NV)(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w) {
+    CALL_GL_API(glUniform4i64NV, location, x, y, z, w);
+}
+void API_ENTRY(glUniform1i64vNV)(GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glUniform1i64vNV, location, count, value);
+}
+void API_ENTRY(glUniform2i64vNV)(GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glUniform2i64vNV, location, count, value);
+}
+void API_ENTRY(glUniform3i64vNV)(GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glUniform3i64vNV, location, count, value);
+}
+void API_ENTRY(glUniform4i64vNV)(GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glUniform4i64vNV, location, count, value);
+}
+void API_ENTRY(glUniform1ui64NV)(GLint location, GLuint64EXT x) {
+    CALL_GL_API(glUniform1ui64NV, location, x);
+}
+void API_ENTRY(glUniform2ui64NV)(GLint location, GLuint64EXT x, GLuint64EXT y) {
+    CALL_GL_API(glUniform2ui64NV, location, x, y);
+}
+void API_ENTRY(glUniform3ui64NV)(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z) {
+    CALL_GL_API(glUniform3ui64NV, location, x, y, z);
+}
+void API_ENTRY(glUniform4ui64NV)(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w) {
+    CALL_GL_API(glUniform4ui64NV, location, x, y, z, w);
+}
+void API_ENTRY(glUniform1ui64vNV)(GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glUniform1ui64vNV, location, count, value);
+}
+void API_ENTRY(glUniform2ui64vNV)(GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glUniform2ui64vNV, location, count, value);
+}
+void API_ENTRY(glUniform3ui64vNV)(GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glUniform3ui64vNV, location, count, value);
+}
+void API_ENTRY(glUniform4ui64vNV)(GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glUniform4ui64vNV, location, count, value);
+}
+void API_ENTRY(glGetUniformi64vNV)(GLuint program, GLint location, GLint64EXT *params) {
+    CALL_GL_API(glGetUniformi64vNV, program, location, params);
+}
+void API_ENTRY(glProgramUniform1i64NV)(GLuint program, GLint location, GLint64EXT x) {
+    CALL_GL_API(glProgramUniform1i64NV, program, location, x);
+}
+void API_ENTRY(glProgramUniform2i64NV)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y) {
+    CALL_GL_API(glProgramUniform2i64NV, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3i64NV)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z) {
+    CALL_GL_API(glProgramUniform3i64NV, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4i64NV)(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w) {
+    CALL_GL_API(glProgramUniform4i64NV, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1i64vNV)(GLuint program, GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glProgramUniform1i64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2i64vNV)(GLuint program, GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glProgramUniform2i64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3i64vNV)(GLuint program, GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glProgramUniform3i64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4i64vNV)(GLuint program, GLint location, GLsizei count, const GLint64EXT *value) {
+    CALL_GL_API(glProgramUniform4i64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform1ui64NV)(GLuint program, GLint location, GLuint64EXT x) {
+    CALL_GL_API(glProgramUniform1ui64NV, program, location, x);
+}
+void API_ENTRY(glProgramUniform2ui64NV)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y) {
+    CALL_GL_API(glProgramUniform2ui64NV, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3ui64NV)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z) {
+    CALL_GL_API(glProgramUniform3ui64NV, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4ui64NV)(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w) {
+    CALL_GL_API(glProgramUniform4ui64NV, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1ui64vNV)(GLuint program, GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glProgramUniform1ui64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2ui64vNV)(GLuint program, GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glProgramUniform2ui64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3ui64vNV)(GLuint program, GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glProgramUniform3ui64vNV, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4ui64vNV)(GLuint program, GLint location, GLsizei count, const GLuint64EXT *value) {
+    CALL_GL_API(glProgramUniform4ui64vNV, program, location, count, value);
+}
 void API_ENTRY(glVertexAttribDivisorNV)(GLuint index, GLuint divisor) {
     CALL_GL_API(glVertexAttribDivisorNV, index, divisor);
 }
@@ -982,6 +1279,63 @@
 void API_ENTRY(glGetProgramResourcefvNV)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params) {
     CALL_GL_API(glGetProgramResourcefvNV, program, programInterface, index, propCount, props, bufSize, length, params);
 }
+void API_ENTRY(glMatrixFrustumEXT)(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
+    CALL_GL_API(glMatrixFrustumEXT, mode, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glMatrixLoadIdentityEXT)(GLenum mode) {
+    CALL_GL_API(glMatrixLoadIdentityEXT, mode);
+}
+void API_ENTRY(glMatrixLoadTransposefEXT)(GLenum mode, const GLfloat *m) {
+    CALL_GL_API(glMatrixLoadTransposefEXT, mode, m);
+}
+void API_ENTRY(glMatrixLoadTransposedEXT)(GLenum mode, const GLdouble *m) {
+    CALL_GL_API(glMatrixLoadTransposedEXT, mode, m);
+}
+void API_ENTRY(glMatrixLoadfEXT)(GLenum mode, const GLfloat *m) {
+    CALL_GL_API(glMatrixLoadfEXT, mode, m);
+}
+void API_ENTRY(glMatrixLoaddEXT)(GLenum mode, const GLdouble *m) {
+    CALL_GL_API(glMatrixLoaddEXT, mode, m);
+}
+void API_ENTRY(glMatrixMultTransposefEXT)(GLenum mode, const GLfloat *m) {
+    CALL_GL_API(glMatrixMultTransposefEXT, mode, m);
+}
+void API_ENTRY(glMatrixMultTransposedEXT)(GLenum mode, const GLdouble *m) {
+    CALL_GL_API(glMatrixMultTransposedEXT, mode, m);
+}
+void API_ENTRY(glMatrixMultfEXT)(GLenum mode, const GLfloat *m) {
+    CALL_GL_API(glMatrixMultfEXT, mode, m);
+}
+void API_ENTRY(glMatrixMultdEXT)(GLenum mode, const GLdouble *m) {
+    CALL_GL_API(glMatrixMultdEXT, mode, m);
+}
+void API_ENTRY(glMatrixOrthoEXT)(GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) {
+    CALL_GL_API(glMatrixOrthoEXT, mode, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glMatrixPopEXT)(GLenum mode) {
+    CALL_GL_API(glMatrixPopEXT, mode);
+}
+void API_ENTRY(glMatrixPushEXT)(GLenum mode) {
+    CALL_GL_API(glMatrixPushEXT, mode);
+}
+void API_ENTRY(glMatrixRotatefEXT)(GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glMatrixRotatefEXT, mode, angle, x, y, z);
+}
+void API_ENTRY(glMatrixRotatedEXT)(GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z) {
+    CALL_GL_API(glMatrixRotatedEXT, mode, angle, x, y, z);
+}
+void API_ENTRY(glMatrixScalefEXT)(GLenum mode, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glMatrixScalefEXT, mode, x, y, z);
+}
+void API_ENTRY(glMatrixScaledEXT)(GLenum mode, GLdouble x, GLdouble y, GLdouble z) {
+    CALL_GL_API(glMatrixScaledEXT, mode, x, y, z);
+}
+void API_ENTRY(glMatrixTranslatefEXT)(GLenum mode, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glMatrixTranslatefEXT, mode, x, y, z);
+}
+void API_ENTRY(glMatrixTranslatedEXT)(GLenum mode, GLdouble x, GLdouble y, GLdouble z) {
+    CALL_GL_API(glMatrixTranslatedEXT, mode, x, y, z);
+}
 void API_ENTRY(glPolygonModeNV)(GLenum face, GLenum mode) {
     CALL_GL_API(glPolygonModeNV, face, mode);
 }
@@ -1033,6 +1387,9 @@
 GLboolean API_ENTRY(glIsEnablediNV)(GLenum target, GLuint index) {
     CALL_GL_API_RETURN(glIsEnablediNV, target, index);
 }
+void API_ENTRY(glViewportSwizzleNV)(GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew) {
+    CALL_GL_API(glViewportSwizzleNV, index, swizzlex, swizzley, swizzlez, swizzlew);
+}
 void API_ENTRY(glFramebufferTextureMultiviewOVR)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews) {
     CALL_GL_API(glFramebufferTextureMultiviewOVR, target, attachment, texture, level, baseViewIndex, numViews);
 }
@@ -1090,6 +1447,18 @@
 void API_ENTRY(glExtGetProgramBinarySourceQCOM)(GLuint program, GLenum shadertype, GLchar *source, GLint *length) {
     CALL_GL_API(glExtGetProgramBinarySourceQCOM, program, shadertype, source, length);
 }
+void API_ENTRY(glFramebufferFoveationConfigQCOM)(GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures) {
+    CALL_GL_API(glFramebufferFoveationConfigQCOM, framebuffer, numLayers, focalPointsPerLayer, requestedFeatures, providedFeatures);
+}
+void API_ENTRY(glFramebufferFoveationParametersQCOM)(GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea) {
+    CALL_GL_API(glFramebufferFoveationParametersQCOM, framebuffer, layer, focalPoint, focalX, focalY, gainX, gainY, foveaArea);
+}
+void API_ENTRY(glFramebufferFetchBarrierQCOM)(void) {
+    CALL_GL_API(glFramebufferFetchBarrierQCOM);
+}
+void API_ENTRY(glTextureFoveationParametersQCOM)(GLuint texture, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea) {
+    CALL_GL_API(glTextureFoveationParametersQCOM, texture, layer, focalPoint, focalX, focalY, gainX, gainY, foveaArea);
+}
 void API_ENTRY(glStartTilingQCOM)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {
     CALL_GL_API(glStartTilingQCOM, x, y, width, height, preserveMask);
 }
diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in
index fbf761a..42ac563 100644
--- a/opengl/libs/GLES_CM/glext_api.in
+++ b/opengl/libs/GLES_CM/glext_api.in
@@ -313,6 +313,15 @@
 void API_ENTRY(glGetSyncivAPPLE)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) {
     CALL_GL_API(glGetSyncivAPPLE, sync, pname, bufSize, length, values);
 }
+void API_ENTRY(glInsertEventMarkerEXT)(GLsizei length, const GLchar *marker) {
+    CALL_GL_API(glInsertEventMarkerEXT, length, marker);
+}
+void API_ENTRY(glPushGroupMarkerEXT)(GLsizei length, const GLchar *marker) {
+    CALL_GL_API(glPushGroupMarkerEXT, length, marker);
+}
+void API_ENTRY(glPopGroupMarkerEXT)(void) {
+    CALL_GL_API(glPopGroupMarkerEXT);
+}
 void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
     CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments);
 }
diff --git a/opengl/libs/entries.in b/opengl/libs/entries.in
index e3b7cf3..a306510 100644
--- a/opengl/libs/entries.in
+++ b/opengl/libs/entries.in
@@ -61,6 +61,8 @@
 GL_ENTRY(void, glBlitFramebufferNV, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
 GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage)
 GL_ENTRY(void, glBufferStorageEXT, GLenum target, GLsizeiptr size, const void *data, GLbitfield flags)
+GL_ENTRY(void, glBufferStorageExternalEXT, GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags)
+GL_ENTRY(void, glBufferStorageMemEXT, GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset)
 GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data)
 GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
 GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
@@ -76,10 +78,14 @@
 GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
 GL_ENTRY(void, glClearDepthx, GLfixed depth)
 GL_ENTRY(void, glClearDepthxOES, GLfixed depth)
+GL_ENTRY(void, glClearPixelLocalStorageuiEXT, GLsizei offset, GLsizei n, const GLuint *values)
 GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClearTexImageEXT, GLuint texture, GLint level, GLenum format, GLenum type, const void *data)
+GL_ENTRY(void, glClearTexSubImageEXT, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data)
 GL_ENTRY(void, glClientActiveTexture, GLenum texture)
 GL_ENTRY(GLenum, glClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout)
 GL_ENTRY(GLenum, glClientWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glClipControlEXT, GLenum origin, GLenum depth)
 GL_ENTRY(void, glClipPlanef, GLenum p, const GLfloat *eqn)
 GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn)
 GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
@@ -102,6 +108,7 @@
 GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data)
 GL_ENTRY(void, glCompressedTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
 GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
+GL_ENTRY(void, glConservativeRasterParameteriNV, GLenum pname, GLint param)
 GL_ENTRY(void, glCopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
 GL_ENTRY(void, glCopyBufferSubDataNV, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
 GL_ENTRY(void, glCopyImageSubData, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
@@ -121,6 +128,7 @@
 GL_ENTRY(void, glCoverageModulationNV, GLenum components)
 GL_ENTRY(void, glCoverageModulationTableNV, GLsizei n, const GLfloat *v)
 GL_ENTRY(void, glCoverageOperationNV, GLenum operation)
+GL_ENTRY(void, glCreateMemoryObjectsEXT, GLsizei n, GLuint *memoryObjects)
 GL_ENTRY(void, glCreatePerfQueryINTEL, GLuint queryId, GLuint *queryHandle)
 GL_ENTRY(GLuint, glCreateProgram, void)
 GL_ENTRY(GLuint, glCreateShader, GLenum type)
@@ -138,6 +146,7 @@
 GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
 GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint *framebuffers)
 GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint *framebuffers)
+GL_ENTRY(void, glDeleteMemoryObjectsEXT, GLsizei n, const GLuint *memoryObjects)
 GL_ENTRY(void, glDeletePathsNV, GLuint path, GLsizei range)
 GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
 GL_ENTRY(void, glDeletePerfQueryINTEL, GLuint queryHandle)
@@ -149,6 +158,7 @@
 GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers)
 GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint *renderbuffers)
 GL_ENTRY(void, glDeleteSamplers, GLsizei count, const GLuint *samplers)
+GL_ENTRY(void, glDeleteSemaphoresEXT, GLsizei n, const GLuint *semaphores)
 GL_ENTRY(void, glDeleteShader, GLuint shader)
 GL_ENTRY(void, glDeleteSync, GLsync sync)
 GL_ENTRY(void, glDeleteSyncAPPLE, GLsync sync)
@@ -159,7 +169,9 @@
 GL_ENTRY(void, glDepthFunc, GLenum func)
 GL_ENTRY(void, glDepthMask, GLboolean flag)
 GL_ENTRY(void, glDepthRangeArrayfvNV, GLuint first, GLsizei count, const GLfloat *v)
+GL_ENTRY(void, glDepthRangeArrayfvOES, GLuint first, GLsizei count, const GLfloat *v)
 GL_ENTRY(void, glDepthRangeIndexedfNV, GLuint index, GLfloat n, GLfloat f)
+GL_ENTRY(void, glDepthRangeIndexedfOES, GLuint index, GLfloat n, GLfloat f)
 GL_ENTRY(void, glDepthRangef, GLfloat n, GLfloat f)
 GL_ENTRY(void, glDepthRangefOES, GLclampf n, GLclampf f)
 GL_ENTRY(void, glDepthRangex, GLfixed n, GLfixed f)
@@ -213,8 +225,13 @@
 GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
 GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
 GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glDrawTransformFeedbackEXT, GLenum mode, GLuint id)
+GL_ENTRY(void, glDrawTransformFeedbackInstancedEXT, GLenum mode, GLuint id, GLsizei instancecount)
+GL_ENTRY(void, glDrawVkImageNV, GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1)
 GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTexStorageEXT, GLenum target, GLeglImageOES image, const GLint* attrib_list)
 GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTextureStorageEXT, GLuint texture, GLeglImageOES image, const GLint* attrib_list)
 GL_ENTRY(void, glEnable, GLenum cap)
 GL_ENTRY(void, glEnableClientState, GLenum array)
 GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
@@ -256,18 +273,25 @@
 GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *param)
 GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *param)
 GL_ENTRY(void, glFragmentCoverageColorNV, GLuint color)
+GL_ENTRY(void, glFramebufferFetchBarrierEXT, void)
+GL_ENTRY(void, glFramebufferFetchBarrierQCOM, void)
+GL_ENTRY(void, glFramebufferFoveationConfigQCOM, GLuint framebuffer, GLuint numLayers, GLuint focalPointsPerLayer, GLuint requestedFeatures, GLuint *providedFeatures)
+GL_ENTRY(void, glFramebufferFoveationParametersQCOM, GLuint framebuffer, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea)
 GL_ENTRY(void, glFramebufferParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glFramebufferPixelLocalStorageSizeEXT, GLuint target, GLsizei size)
 GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
 GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
 GL_ENTRY(void, glFramebufferSampleLocationsfvNV, GLenum target, GLuint start, GLsizei count, const GLfloat *v)
 GL_ENTRY(void, glFramebufferTexture, GLenum target, GLenum attachment, GLuint texture, GLint level)
 GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture2DDownsampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale)
 GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
 GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
 GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
 GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
 GL_ENTRY(void, glFramebufferTextureEXT, GLenum target, GLenum attachment, GLuint texture, GLint level)
 GL_ENTRY(void, glFramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+GL_ENTRY(void, glFramebufferTextureLayerDownsampleIMG, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale)
 GL_ENTRY(void, glFramebufferTextureMultisampleMultiviewOVR, GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews)
 GL_ENTRY(void, glFramebufferTextureMultiviewOVR, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews)
 GL_ENTRY(void, glFramebufferTextureOES, GLenum target, GLenum attachment, GLuint texture, GLint level)
@@ -289,6 +313,7 @@
 GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint *renderbuffers)
 GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint *renderbuffers)
 GL_ENTRY(void, glGenSamplers, GLsizei count, GLuint *samplers)
+GL_ENTRY(void, glGenSemaphoresEXT, GLsizei n, GLuint *semaphores)
 GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
 GL_ENTRY(void, glGenTransformFeedbacks, GLsizei n, GLuint *ids)
 GL_ENTRY(void, glGenVertexArrays, GLsizei n, GLuint *arrays)
@@ -323,12 +348,14 @@
 GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
 GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
 GL_ENTRY(void, glGetFloati_vNV, GLenum target, GLuint index, GLfloat *data)
+GL_ENTRY(void, glGetFloati_vOES, GLenum target, GLuint index, GLfloat *data)
 GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *data)
 GL_ENTRY(GLint, glGetFragDataIndexEXT, GLuint program, const GLchar *name)
 GL_ENTRY(GLint, glGetFragDataLocation, GLuint program, const GLchar *name)
 GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(GLsizei, glGetFramebufferPixelLocalStorageSizeEXT, GLuint target)
 GL_ENTRY(GLenum, glGetGraphicsResetStatus, void)
 GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void)
 GL_ENTRY(GLenum, glGetGraphicsResetStatusKHR, void)
@@ -347,6 +374,7 @@
 GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
 GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMemoryObjectParameterivEXT, GLuint memoryObject, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val)
 GL_ENTRY(void, glGetNextPerfQueryIdINTEL, GLuint queryId, GLuint *nextQueryId)
 GL_ENTRY(void, glGetObjectLabel, GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label)
@@ -370,7 +398,7 @@
 GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
 GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString)
 GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
-GL_ENTRY(void, glGetPerfQueryDataINTEL, GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten)
+GL_ENTRY(void, glGetPerfQueryDataINTEL, GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten)
 GL_ENTRY(void, glGetPerfQueryIdByNameINTEL, GLchar *queryName, GLuint *queryId)
 GL_ENTRY(void, glGetPerfQueryInfoINTEL, GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask)
 GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
@@ -407,6 +435,7 @@
 GL_ENTRY(void, glGetSamplerParameterIuivOES, GLuint sampler, GLenum pname, GLuint *params)
 GL_ENTRY(void, glGetSamplerParameterfv, GLuint sampler, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetSamplerParameteriv, GLuint sampler, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetSemaphoreParameterui64vEXT, GLuint semaphore, GLenum pname, GLuint64 *params)
 GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
 GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision)
 GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source)
@@ -434,7 +463,9 @@
 GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
 GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(GLuint64, glGetTextureHandleIMG, GLuint texture)
 GL_ENTRY(GLuint64, glGetTextureHandleNV, GLuint texture)
+GL_ENTRY(GLuint64, glGetTextureSamplerHandleIMG, GLuint texture, GLuint sampler)
 GL_ENTRY(GLuint64, glGetTextureSamplerHandleNV, GLuint texture, GLuint sampler)
 GL_ENTRY(void, glGetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
 GL_ENTRY(void, glGetTranslatedShaderSourceANGLE, GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source)
@@ -442,13 +473,17 @@
 GL_ENTRY(void, glGetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
 GL_ENTRY(GLint, glGetUniformLocation, GLuint program, const GLchar *name)
 GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat *params)
+GL_ENTRY(void, glGetUniformi64vNV, GLuint program, GLint location, GLint64EXT *params)
 GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint *params)
 GL_ENTRY(void, glGetUniformuiv, GLuint program, GLint location, GLuint *params)
+GL_ENTRY(void, glGetUnsignedBytei_vEXT, GLenum target, GLuint index, GLubyte *data)
+GL_ENTRY(void, glGetUnsignedBytevEXT, GLenum pname, GLubyte *data)
 GL_ENTRY(void, glGetVertexAttribIiv, GLuint index, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetVertexAttribIuiv, GLuint index, GLenum pname, GLuint *params)
 GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void **pointer)
 GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint *params)
+GL_ENTRY(GLVULKANPROCNV, glGetVkProcAddrNV, const GLchar *name)
 GL_ENTRY(void, glGetnUniformfv, GLuint program, GLint location, GLsizei bufSize, GLfloat *params)
 GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, GLfloat *params)
 GL_ENTRY(void, glGetnUniformfvKHR, GLuint program, GLint location, GLsizei bufSize, GLfloat *params)
@@ -458,6 +493,8 @@
 GL_ENTRY(void, glGetnUniformuiv, GLuint program, GLint location, GLsizei bufSize, GLuint *params)
 GL_ENTRY(void, glGetnUniformuivKHR, GLuint program, GLint location, GLsizei bufSize, GLuint *params)
 GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(void, glImportMemoryFdEXT, GLuint memory, GLuint64 size, GLenum handleType, GLint fd)
+GL_ENTRY(void, glImportSemaphoreFdEXT, GLuint semaphore, GLenum handleType, GLint fd)
 GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker)
 GL_ENTRY(void, glInterpolatePathsNV, GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight)
 GL_ENTRY(void, glInvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments)
@@ -472,6 +509,7 @@
 GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
 GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
 GL_ENTRY(GLboolean, glIsImageHandleResidentNV, GLuint64 handle)
+GL_ENTRY(GLboolean, glIsMemoryObjectEXT, GLuint memoryObject)
 GL_ENTRY(GLboolean, glIsPathNV, GLuint path)
 GL_ENTRY(GLboolean, glIsPointInFillPathNV, GLuint path, GLuint mask, GLfloat x, GLfloat y)
 GL_ENTRY(GLboolean, glIsPointInStrokePathNV, GLuint path, GLfloat x, GLfloat y)
@@ -483,6 +521,7 @@
 GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
 GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
 GL_ENTRY(GLboolean, glIsSampler, GLuint sampler)
+GL_ENTRY(GLboolean, glIsSemaphoreEXT, GLuint semaphore)
 GL_ENTRY(GLboolean, glIsShader, GLuint shader)
 GL_ENTRY(GLboolean, glIsSync, GLsync sync)
 GL_ENTRY(GLboolean, glIsSyncAPPLE, GLsync sync)
@@ -527,16 +566,37 @@
 GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
 GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *param)
 GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glMatrixFrustumEXT, GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
 GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
 GL_ENTRY(void, glMatrixLoad3x2fNV, GLenum matrixMode, const GLfloat *m)
 GL_ENTRY(void, glMatrixLoad3x3fNV, GLenum matrixMode, const GLfloat *m)
+GL_ENTRY(void, glMatrixLoadIdentityEXT, GLenum mode)
 GL_ENTRY(void, glMatrixLoadTranspose3x3fNV, GLenum matrixMode, const GLfloat *m)
+GL_ENTRY(void, glMatrixLoadTransposedEXT, GLenum mode, const GLdouble *m)
+GL_ENTRY(void, glMatrixLoadTransposefEXT, GLenum mode, const GLfloat *m)
+GL_ENTRY(void, glMatrixLoaddEXT, GLenum mode, const GLdouble *m)
+GL_ENTRY(void, glMatrixLoadfEXT, GLenum mode, const GLfloat *m)
 GL_ENTRY(void, glMatrixMode, GLenum mode)
 GL_ENTRY(void, glMatrixMult3x2fNV, GLenum matrixMode, const GLfloat *m)
 GL_ENTRY(void, glMatrixMult3x3fNV, GLenum matrixMode, const GLfloat *m)
 GL_ENTRY(void, glMatrixMultTranspose3x3fNV, GLenum matrixMode, const GLfloat *m)
+GL_ENTRY(void, glMatrixMultTransposedEXT, GLenum mode, const GLdouble *m)
+GL_ENTRY(void, glMatrixMultTransposefEXT, GLenum mode, const GLfloat *m)
+GL_ENTRY(void, glMatrixMultdEXT, GLenum mode, const GLdouble *m)
+GL_ENTRY(void, glMatrixMultfEXT, GLenum mode, const GLfloat *m)
+GL_ENTRY(void, glMatrixOrthoEXT, GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)
+GL_ENTRY(void, glMatrixPopEXT, GLenum mode)
+GL_ENTRY(void, glMatrixPushEXT, GLenum mode)
+GL_ENTRY(void, glMatrixRotatedEXT, GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
+GL_ENTRY(void, glMatrixRotatefEXT, GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glMatrixScaledEXT, GLenum mode, GLdouble x, GLdouble y, GLdouble z)
+GL_ENTRY(void, glMatrixScalefEXT, GLenum mode, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glMatrixTranslatedEXT, GLenum mode, GLdouble x, GLdouble y, GLdouble z)
+GL_ENTRY(void, glMatrixTranslatefEXT, GLenum mode, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glMaxShaderCompilerThreadsKHR, GLuint count)
 GL_ENTRY(void, glMemoryBarrier, GLbitfield barriers)
 GL_ENTRY(void, glMemoryBarrierByRegion, GLbitfield barriers)
+GL_ENTRY(void, glMemoryObjectParameterivEXT, GLuint memoryObject, GLenum pname, const GLint *params)
 GL_ENTRY(void, glMinSampleShading, GLfloat value)
 GL_ENTRY(void, glMinSampleShadingOES, GLfloat value)
 GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
@@ -551,6 +611,8 @@
 GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
 GL_ENTRY(void, glMultiTexCoord4x, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
 GL_ENTRY(void, glMultiTexCoord4xOES, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNamedBufferStorageExternalEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags)
+GL_ENTRY(void, glNamedBufferStorageMemEXT, GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset)
 GL_ENTRY(void, glNamedFramebufferSampleLocationsfvNV, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v)
 GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
 GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
@@ -600,6 +662,7 @@
 GL_ENTRY(void, glPointSizexOES, GLfixed size)
 GL_ENTRY(void, glPolygonModeNV, GLenum face, GLenum mode)
 GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp)
 GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
 GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
 GL_ENTRY(void, glPopDebugGroup, void)
@@ -619,10 +682,14 @@
 GL_ENTRY(void, glProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform1i, GLuint program, GLint location, GLint v0)
+GL_ENTRY(void, glProgramUniform1i64NV, GLuint program, GLint location, GLint64EXT x)
+GL_ENTRY(void, glProgramUniform1i64vNV, GLuint program, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glProgramUniform1iEXT, GLuint program, GLint location, GLint v0)
 GL_ENTRY(void, glProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform1ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform1ui, GLuint program, GLint location, GLuint v0)
+GL_ENTRY(void, glProgramUniform1ui64NV, GLuint program, GLint location, GLuint64EXT x)
+GL_ENTRY(void, glProgramUniform1ui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glProgramUniform1uiEXT, GLuint program, GLint location, GLuint v0)
 GL_ENTRY(void, glProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glProgramUniform1uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value)
@@ -631,10 +698,14 @@
 GL_ENTRY(void, glProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform2fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1)
+GL_ENTRY(void, glProgramUniform2i64NV, GLuint program, GLint location, GLint64EXT x, GLint64EXT y)
+GL_ENTRY(void, glProgramUniform2i64vNV, GLuint program, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glProgramUniform2iEXT, GLuint program, GLint location, GLint v0, GLint v1)
 GL_ENTRY(void, glProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform2ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1)
+GL_ENTRY(void, glProgramUniform2ui64NV, GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y)
+GL_ENTRY(void, glProgramUniform2ui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glProgramUniform2uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1)
 GL_ENTRY(void, glProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glProgramUniform2uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value)
@@ -643,10 +714,14 @@
 GL_ENTRY(void, glProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform3fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2)
+GL_ENTRY(void, glProgramUniform3i64NV, GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z)
+GL_ENTRY(void, glProgramUniform3i64vNV, GLuint program, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glProgramUniform3iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2)
 GL_ENTRY(void, glProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform3ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2)
+GL_ENTRY(void, glProgramUniform3ui64NV, GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z)
+GL_ENTRY(void, glProgramUniform3ui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glProgramUniform3uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2)
 GL_ENTRY(void, glProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glProgramUniform3uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value)
@@ -655,14 +730,20 @@
 GL_ENTRY(void, glProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform4fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+GL_ENTRY(void, glProgramUniform4i64NV, GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w)
+GL_ENTRY(void, glProgramUniform4i64vNV, GLuint program, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glProgramUniform4iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
 GL_ENTRY(void, glProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform4ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+GL_ENTRY(void, glProgramUniform4ui64NV, GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w)
+GL_ENTRY(void, glProgramUniform4ui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glProgramUniform4uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
 GL_ENTRY(void, glProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glProgramUniform4uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value)
+GL_ENTRY(void, glProgramUniformHandleui64IMG, GLuint program, GLint location, GLuint64 value)
 GL_ENTRY(void, glProgramUniformHandleui64NV, GLuint program, GLint location, GLuint64 value)
+GL_ENTRY(void, glProgramUniformHandleui64vIMG, GLuint program, GLint location, GLsizei count, const GLuint64 *values)
 GL_ENTRY(void, glProgramUniformHandleui64vNV, GLuint program, GLint location, GLsizei count, const GLuint64 *values)
 GL_ENTRY(void, glProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 GL_ENTRY(void, glProgramUniformMatrix2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
@@ -730,13 +811,20 @@
 GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
 GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
 GL_ENTRY(void, glScissorArrayvNV, GLuint first, GLsizei count, const GLint *v)
+GL_ENTRY(void, glScissorArrayvOES, GLuint first, GLsizei count, const GLint *v)
 GL_ENTRY(void, glScissorIndexedNV, GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height)
+GL_ENTRY(void, glScissorIndexedOES, GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height)
 GL_ENTRY(void, glScissorIndexedvNV, GLuint index, const GLint *v)
+GL_ENTRY(void, glScissorIndexedvOES, GLuint index, const GLint *v)
 GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList)
+GL_ENTRY(void, glSemaphoreParameterui64vEXT, GLuint semaphore, GLenum pname, const GLuint64 *params)
 GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
 GL_ENTRY(void, glShadeModel, GLenum mode)
 GL_ENTRY(void, glShaderBinary, GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length)
 GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length)
+GL_ENTRY(void, glSignalSemaphoreEXT, GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts)
+GL_ENTRY(void, glSignalVkFenceNV, GLuint64 vkFence)
+GL_ENTRY(void, glSignalVkSemaphoreNV, GLuint64 vkSemaphore)
 GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
 GL_ENTRY(void, glStencilFillPathInstancedNV, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues)
 GL_ENTRY(void, glStencilFillPathNV, GLuint path, GLenum fillMode, GLuint mask)
@@ -801,12 +889,21 @@
 GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 GL_ENTRY(void, glTexStorage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)
 GL_ENTRY(void, glTexStorage3DMultisampleOES, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)
+GL_ENTRY(void, glTexStorageMem2DEXT, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTexStorageMem2DMultisampleEXT, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTexStorageMem3DEXT, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTexStorageMem3DMultisampleEXT, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset)
 GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
 GL_ENTRY(void, glTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels)
 GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels)
+GL_ENTRY(void, glTextureFoveationParametersQCOM, GLuint texture, GLuint layer, GLuint focalPoint, GLfloat focalX, GLfloat focalY, GLfloat gainX, GLfloat gainY, GLfloat foveaArea)
 GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
 GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
 GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+GL_ENTRY(void, glTextureStorageMem2DEXT, GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTextureStorageMem2DMultisampleEXT, GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTextureStorageMem3DEXT, GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset)
+GL_ENTRY(void, glTextureStorageMem3DMultisampleEXT, GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset)
 GL_ENTRY(void, glTextureViewEXT, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers)
 GL_ENTRY(void, glTextureViewOES, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers)
 GL_ENTRY(void, glTransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
@@ -817,29 +914,47 @@
 GL_ENTRY(void, glUniform1f, GLint location, GLfloat v0)
 GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glUniform1i, GLint location, GLint v0)
+GL_ENTRY(void, glUniform1i64NV, GLint location, GLint64EXT x)
+GL_ENTRY(void, glUniform1i64vNV, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glUniform1ui, GLint location, GLuint v0)
+GL_ENTRY(void, glUniform1ui64NV, GLint location, GLuint64EXT x)
+GL_ENTRY(void, glUniform1ui64vNV, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glUniform1uiv, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glUniform2f, GLint location, GLfloat v0, GLfloat v1)
 GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glUniform2i, GLint location, GLint v0, GLint v1)
+GL_ENTRY(void, glUniform2i64NV, GLint location, GLint64EXT x, GLint64EXT y)
+GL_ENTRY(void, glUniform2i64vNV, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glUniform2ui, GLint location, GLuint v0, GLuint v1)
+GL_ENTRY(void, glUniform2ui64NV, GLint location, GLuint64EXT x, GLuint64EXT y)
+GL_ENTRY(void, glUniform2ui64vNV, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glUniform2uiv, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glUniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
 GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glUniform3i, GLint location, GLint v0, GLint v1, GLint v2)
+GL_ENTRY(void, glUniform3i64NV, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z)
+GL_ENTRY(void, glUniform3i64vNV, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glUniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2)
+GL_ENTRY(void, glUniform3ui64NV, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z)
+GL_ENTRY(void, glUniform3ui64vNV, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glUniform3uiv, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glUniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
 GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat *value)
 GL_ENTRY(void, glUniform4i, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+GL_ENTRY(void, glUniform4i64NV, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w)
+GL_ENTRY(void, glUniform4i64vNV, GLint location, GLsizei count, const GLint64EXT *value)
 GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint *value)
 GL_ENTRY(void, glUniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+GL_ENTRY(void, glUniform4ui64NV, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w)
+GL_ENTRY(void, glUniform4ui64vNV, GLint location, GLsizei count, const GLuint64EXT *value)
 GL_ENTRY(void, glUniform4uiv, GLint location, GLsizei count, const GLuint *value)
 GL_ENTRY(void, glUniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+GL_ENTRY(void, glUniformHandleui64IMG, GLint location, GLuint64 value)
 GL_ENTRY(void, glUniformHandleui64NV, GLint location, GLuint64 value)
+GL_ENTRY(void, glUniformHandleui64vIMG, GLint location, GLsizei count, const GLuint64 *value)
 GL_ENTRY(void, glUniformHandleui64vNV, GLint location, GLsizei count, const GLuint64 *value)
 GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
 GL_ENTRY(void, glUniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
@@ -889,9 +1004,17 @@
 GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
 GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
 GL_ENTRY(void, glViewportArrayvNV, GLuint first, GLsizei count, const GLfloat *v)
+GL_ENTRY(void, glViewportArrayvOES, GLuint first, GLsizei count, const GLfloat *v)
 GL_ENTRY(void, glViewportIndexedfNV, GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h)
+GL_ENTRY(void, glViewportIndexedfOES, GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h)
 GL_ENTRY(void, glViewportIndexedfvNV, GLuint index, const GLfloat *v)
+GL_ENTRY(void, glViewportIndexedfvOES, GLuint index, const GLfloat *v)
+GL_ENTRY(void, glViewportPositionWScaleNV, GLuint index, GLfloat xcoeff, GLfloat ycoeff)
+GL_ENTRY(void, glViewportSwizzleNV, GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew)
+GL_ENTRY(void, glWaitSemaphoreEXT, GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts)
 GL_ENTRY(void, glWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout)
 GL_ENTRY(void, glWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glWaitVkSemaphoreNV, GLuint64 vkSemaphore)
 GL_ENTRY(void, glWeightPathsNV, GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights)
 GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glWindowRectanglesEXT, GLenum mode, GLsizei count, const GLint *box)
diff --git a/opengl/libs/enums.in b/opengl/libs/enums.in
index e052816..d09004f 100644
--- a/opengl/libs/enums.in
+++ b/opengl/libs/enums.in
@@ -1223,6 +1223,8 @@
 GL_ENUM(0x9285,GL_BLEND_ADVANCED_COHERENT_KHR)
 GL_ENUM(0x82FB,GL_CONTEXT_RELEASE_BEHAVIOR_KHR)
 GL_ENUM(0x82FC,GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR)
+GL_ENUM(0x91B0,GL_MAX_SHADER_COMPILER_THREADS_KHR)
+GL_ENUM(0x91B1,GL_COMPLETION_STATUS_KHR)
 GL_ENUM(0x8D66,GL_SAMPLER_EXTERNAL_OES)
 GL_ENUM(0x93C0,GL_COMPRESSED_RGBA_ASTC_3x3x3_OES)
 GL_ENUM(0x93C1,GL_COMPRESSED_RGBA_ASTC_4x3x3_OES)
@@ -1251,6 +1253,10 @@
 GL_ENUM(0x82DE,GL_TEXTURE_VIEW_NUM_LAYERS_OES)
 GL_ENUM(0x8DF6,GL_UNSIGNED_INT_10_10_10_2_OES)
 GL_ENUM(0x8DF7,GL_INT_10_10_10_2_OES)
+GL_ENUM(0x825B,GL_MAX_VIEWPORTS_OES)
+GL_ENUM(0x825C,GL_VIEWPORT_SUBPIXEL_BITS_OES)
+GL_ENUM(0x825D,GL_VIEWPORT_BOUNDS_RANGE_OES)
+GL_ENUM(0x825F,GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES)
 GL_ENUM(0x8BC0,GL_COUNTER_TYPE_AMD)
 GL_ENUM(0x8BC1,GL_COUNTER_RANGE_AMD)
 GL_ENUM(0x8BC2,GL_UNSIGNED_INT64_AMD)
@@ -1288,6 +1294,14 @@
 GL_ENUM(0x88FC,GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT)
 GL_ENUM(0x821F,GL_BUFFER_IMMUTABLE_STORAGE_EXT)
 GL_ENUM(0x8220,GL_BUFFER_STORAGE_FLAGS_EXT)
+GL_ENUM(0x8CA1,GL_LOWER_LEFT_EXT)
+GL_ENUM(0x8CA2,GL_UPPER_LEFT_EXT)
+GL_ENUM(0x935E,GL_NEGATIVE_ONE_TO_ONE_EXT)
+GL_ENUM(0x935F,GL_ZERO_TO_ONE_EXT)
+GL_ENUM(0x935C,GL_CLIP_ORIGIN_EXT)
+GL_ENUM(0x935D,GL_CLIP_DEPTH_MODE_EXT)
+GL_ENUM(0x82F9,GL_MAX_CULL_DISTANCES_EXT)
+GL_ENUM(0x82FA,GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT)
 GL_ENUM(0x8A4F,GL_PROGRAM_PIPELINE_OBJECT_EXT)
 GL_ENUM(0x8B40,GL_PROGRAM_OBJECT_EXT)
 GL_ENUM(0x8B48,GL_SHADER_OBJECT_EXT)
@@ -1298,10 +1312,25 @@
 GL_ENUM(0x88BF,GL_TIME_ELAPSED_EXT)
 GL_ENUM(0x8E28,GL_TIMESTAMP_EXT)
 GL_ENUM(0x8FBB,GL_GPU_DISJOINT_EXT)
+GL_ENUM(0x9580,GL_TEXTURE_TILING_EXT)
+GL_ENUM(0x9581,GL_DEDICATED_MEMORY_OBJECT_EXT)
+GL_ENUM(0x959B,GL_PROTECTED_MEMORY_OBJECT_EXT)
+GL_ENUM(0x9582,GL_NUM_TILING_TYPES_EXT)
+GL_ENUM(0x9583,GL_TILING_TYPES_EXT)
+GL_ENUM(0x9584,GL_OPTIMAL_TILING_EXT)
+GL_ENUM(0x9585,GL_LINEAR_TILING_EXT)
+GL_ENUM(0x9596,GL_NUM_DEVICE_UUIDS_EXT)
+GL_ENUM(0x9597,GL_DEVICE_UUID_EXT)
+GL_ENUM(0x9598,GL_DRIVER_UUID_EXT)
+GL_ENUM(0x9586,GL_HANDLE_TYPE_OPAQUE_FD_EXT)
+GL_ENUM(0x9599,GL_DEVICE_LUID_EXT)
+GL_ENUM(0x959A,GL_DEVICE_NODE_MASK_EXT)
 GL_ENUM(0x90F0,GL_COLOR_ATTACHMENT_EXT)
 GL_ENUM(0x90F1,GL_MULTIVIEW_EXT)
 GL_ENUM(0x0C01,GL_DRAW_BUFFER_EXT)
 GL_ENUM(0x90F2,GL_MAX_MULTIVIEW_BUFFERS_EXT)
+GL_ENUM(0x8E1B,GL_POLYGON_OFFSET_CLAMP_EXT)
+GL_ENUM(0x8BFA,GL_TEXTURE_PROTECTED_EXT)
 GL_ENUM(0x8A54,GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT)
 GL_ENUM(0x8A55,GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT)
 GL_ENUM(0x8A56,GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT)
@@ -1318,10 +1347,22 @@
 GL_ENUM(0x8F99,GL_RG16_SNORM_EXT)
 GL_ENUM(0x8F9B,GL_RGBA16_SNORM_EXT)
 GL_ENUM(0x8DB9,GL_FRAMEBUFFER_SRGB_EXT)
+GL_ENUM(0x958D,GL_LAYOUT_GENERAL_EXT)
+GL_ENUM(0x958E,GL_LAYOUT_COLOR_ATTACHMENT_EXT)
+GL_ENUM(0x958F,GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT)
+GL_ENUM(0x9590,GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT)
+GL_ENUM(0x9591,GL_LAYOUT_SHADER_READ_ONLY_EXT)
+GL_ENUM(0x9592,GL_LAYOUT_TRANSFER_SRC_EXT)
+GL_ENUM(0x9593,GL_LAYOUT_TRANSFER_DST_EXT)
+GL_ENUM(0x9530,GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT)
+GL_ENUM(0x9531,GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT)
 GL_ENUM(0x8A52,GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT)
 GL_ENUM(0x8F63,GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT)
 GL_ENUM(0x8F67,GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT)
 GL_ENUM(0x8F64,GL_SHADER_PIXEL_LOCAL_STORAGE_EXT)
+GL_ENUM(0x9650,GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT)
+GL_ENUM(0x9651,GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT)
+GL_ENUM(0x9652,GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT)
 GL_ENUM(0x91A6,GL_TEXTURE_SPARSE_EXT)
 GL_ENUM(0x91A7,GL_VIRTUAL_PAGE_SIZE_INDEX_EXT)
 GL_ENUM(0x91AA,GL_NUM_SPARSE_LEVELS_EXT)
@@ -1333,6 +1374,23 @@
 GL_ENUM(0x9199,GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT)
 GL_ENUM(0x919A,GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT)
 GL_ENUM(0x91A9,GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT)
+GL_ENUM(0x8F69,GL_TEXTURE_ASTC_DECODE_PRECISION_EXT)
+GL_ENUM(0x8E8C,GL_COMPRESSED_RGBA_BPTC_UNORM_EXT)
+GL_ENUM(0x8E8D,GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT)
+GL_ENUM(0x8E8E,GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT)
+GL_ENUM(0x8E8F,GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT)
+GL_ENUM(0x8DBB,GL_COMPRESSED_RED_RGTC1_EXT)
+GL_ENUM(0x8DBC,GL_COMPRESSED_SIGNED_RED_RGTC1_EXT)
+GL_ENUM(0x8DBD,GL_COMPRESSED_RED_GREEN_RGTC2_EXT)
+GL_ENUM(0x8DBE,GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT)
+GL_ENUM(0x8C4C,GL_COMPRESSED_SRGB_S3TC_DXT1_EXT)
+GL_ENUM(0x8C4D,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT)
+GL_ENUM(0x8C4E,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT)
+GL_ENUM(0x8C4F,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT)
+GL_ENUM(0x9366,GL_TEXTURE_REDUCTION_MODE_EXT)
+GL_ENUM(0x9367,GL_WEIGHTED_AVERAGE_EXT)
+GL_ENUM(0x8FBF,GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT)
+GL_ENUM(0x8743,GL_MIRROR_CLAMP_TO_EDGE_EXT)
 GL_ENUM(0x822A,GL_R16_EXT)
 GL_ENUM(0x822C,GL_RG16_EXT)
 GL_ENUM(0x805B,GL_RGBA16_EXT)
@@ -1343,7 +1401,17 @@
 GL_ENUM(0x8A48,GL_TEXTURE_SRGB_DECODE_EXT)
 GL_ENUM(0x8A49,GL_DECODE_EXT)
 GL_ENUM(0x8A4A,GL_SKIP_DECODE_EXT)
+GL_ENUM(0x8F10,GL_INCLUSIVE_EXT)
+GL_ENUM(0x8F11,GL_EXCLUSIVE_EXT)
+GL_ENUM(0x8F12,GL_WINDOW_RECTANGLE_EXT)
+GL_ENUM(0x8F13,GL_WINDOW_RECTANGLE_MODE_EXT)
+GL_ENUM(0x8F14,GL_MAX_WINDOW_RECTANGLES_EXT)
+GL_ENUM(0x8F15,GL_NUM_WINDOW_RECTANGLES_EXT)
 GL_ENUM(0x9260,GL_GCCSO_SHADER_BINARY_FJ)
+GL_ENUM(0x913C,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG)
+GL_ENUM(0x913D,GL_NUM_DOWNSAMPLE_SCALES_IMG)
+GL_ENUM(0x913E,GL_DOWNSAMPLE_SCALES_IMG)
+GL_ENUM(0x913F,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG)
 GL_ENUM(0x9130,GL_SGX_PROGRAM_BINARY_IMG)
 GL_ENUM(0x8C0A,GL_SGX_BINARY_IMG)
 GL_ENUM(0x9137,GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG)
@@ -1351,6 +1419,8 @@
 GL_ENUM(0x9139,GL_CUBIC_IMG)
 GL_ENUM(0x913A,GL_CUBIC_MIPMAP_NEAREST_IMG)
 GL_ENUM(0x913B,GL_CUBIC_MIPMAP_LINEAR_IMG)
+GL_ENUM(0x83FC,GL_BLACKHOLE_RENDER_INTEL)
+GL_ENUM(0x83FE,GL_CONSERVATIVE_RASTERIZATION_INTEL)
 GL_ENUM(0x00000000,GL_PERFQUERY_SINGLE_CONTEXT_INTEL)
 GL_ENUM(0x00000001,GL_PERFQUERY_GLOBAL_CONTEXT_INTEL)
 GL_ENUM(0x83FB,GL_PERFQUERY_WAIT_INTEL)
@@ -1371,6 +1441,7 @@
 GL_ENUM(0x94FE,GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL)
 GL_ENUM(0x94FF,GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL)
 GL_ENUM(0x9500,GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL)
+GL_ENUM(0x875F,GL_PROGRAM_BINARY_FORMAT_MESA)
 GL_ENUM(0x9281,GL_BLEND_OVERLAP_NV)
 GL_ENUM(0x9280,GL_BLEND_PREMULTIPLIED_SRC_NV)
 GL_ENUM(0x9284,GL_CONJOINT_NV)
@@ -1401,6 +1472,11 @@
 GL_ENUM(0x9288,GL_SRC_OVER_NV)
 GL_ENUM(0x9282,GL_UNCORRELATED_NV)
 GL_ENUM(0x92A6,GL_VIVIDLIGHT_NV)
+GL_ENUM(0x901C,GL_FACTOR_MIN_AMD)
+GL_ENUM(0x901D,GL_FACTOR_MAX_AMD)
+GL_ENUM(0x937C,GL_VIEWPORT_POSITION_W_SCALE_NV)
+GL_ENUM(0x937D,GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV)
+GL_ENUM(0x937E,GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV)
 GL_ENUM(0x8E13,GL_QUERY_WAIT_NV)
 GL_ENUM(0x8E14,GL_QUERY_NO_WAIT_NV)
 GL_ENUM(0x8E15,GL_QUERY_BY_REGION_WAIT_NV)
@@ -1409,6 +1485,10 @@
 GL_ENUM(0x9347,GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV)
 GL_ENUM(0x9348,GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV)
 GL_ENUM(0x9349,GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV)
+GL_ENUM(0x9550,GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV)
+GL_ENUM(0x954D,GL_CONSERVATIVE_RASTER_MODE_NV)
+GL_ENUM(0x954E,GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV)
+GL_ENUM(0x954F,GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV)
 GL_ENUM(0x8ED0,GL_COVERAGE_COMPONENT_NV)
 GL_ENUM(0x8ED1,GL_COVERAGE_COMPONENT4_NV)
 GL_ENUM(0x8ED2,GL_COVERAGE_ATTACHMENT_NV)
@@ -1429,6 +1509,34 @@
 GL_ENUM(0x9330,GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV)
 GL_ENUM(0x9332,GL_COVERAGE_MODULATION_NV)
 GL_ENUM(0x9333,GL_COVERAGE_MODULATION_TABLE_SIZE_NV)
+GL_ENUM(0x140E,GL_INT64_NV)
+GL_ENUM(0x140F,GL_UNSIGNED_INT64_NV)
+GL_ENUM(0x8FE0,GL_INT8_NV)
+GL_ENUM(0x8FE1,GL_INT8_VEC2_NV)
+GL_ENUM(0x8FE2,GL_INT8_VEC3_NV)
+GL_ENUM(0x8FE3,GL_INT8_VEC4_NV)
+GL_ENUM(0x8FE4,GL_INT16_NV)
+GL_ENUM(0x8FE5,GL_INT16_VEC2_NV)
+GL_ENUM(0x8FE6,GL_INT16_VEC3_NV)
+GL_ENUM(0x8FE7,GL_INT16_VEC4_NV)
+GL_ENUM(0x8FE9,GL_INT64_VEC2_NV)
+GL_ENUM(0x8FEA,GL_INT64_VEC3_NV)
+GL_ENUM(0x8FEB,GL_INT64_VEC4_NV)
+GL_ENUM(0x8FEC,GL_UNSIGNED_INT8_NV)
+GL_ENUM(0x8FED,GL_UNSIGNED_INT8_VEC2_NV)
+GL_ENUM(0x8FEE,GL_UNSIGNED_INT8_VEC3_NV)
+GL_ENUM(0x8FEF,GL_UNSIGNED_INT8_VEC4_NV)
+GL_ENUM(0x8FF0,GL_UNSIGNED_INT16_NV)
+GL_ENUM(0x8FF1,GL_UNSIGNED_INT16_VEC2_NV)
+GL_ENUM(0x8FF2,GL_UNSIGNED_INT16_VEC3_NV)
+GL_ENUM(0x8FF3,GL_UNSIGNED_INT16_VEC4_NV)
+GL_ENUM(0x8FF5,GL_UNSIGNED_INT64_VEC2_NV)
+GL_ENUM(0x8FF6,GL_UNSIGNED_INT64_VEC3_NV)
+GL_ENUM(0x8FF7,GL_UNSIGNED_INT64_VEC4_NV)
+GL_ENUM(0x8FF8,GL_FLOAT16_NV)
+GL_ENUM(0x8FF9,GL_FLOAT16_VEC2_NV)
+GL_ENUM(0x8FFA,GL_FLOAT16_VEC3_NV)
+GL_ENUM(0x8FFB,GL_FLOAT16_VEC4_NV)
 GL_ENUM(0x9371,GL_MULTISAMPLES_NV)
 GL_ENUM(0x9372,GL_SUPERSAMPLE_SCALE_X_NV)
 GL_ENUM(0x9373,GL_SUPERSAMPLE_SCALE_Y_NV)
@@ -1564,10 +1672,6 @@
 GL_ENUM(0x8C44,GL_SLUMINANCE_ALPHA_NV)
 GL_ENUM(0x8C47,GL_SLUMINANCE8_NV)
 GL_ENUM(0x8C45,GL_SLUMINANCE8_ALPHA8_NV)
-GL_ENUM(0x8C4C,GL_COMPRESSED_SRGB_S3TC_DXT1_NV)
-GL_ENUM(0x8C4D,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV)
-GL_ENUM(0x8C4E,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV)
-GL_ENUM(0x8C4F,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV)
 GL_ENUM(0x88EE,GL_ETC1_SRGB8_NV)
 GL_ENUM(0x933D,GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV)
 GL_ENUM(0x933E,GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV)
@@ -1576,15 +1680,30 @@
 GL_ENUM(0x9341,GL_PROGRAMMABLE_SAMPLE_LOCATION_NV)
 GL_ENUM(0x9342,GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV)
 GL_ENUM(0x9343,GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV)
-GL_ENUM(0x825B,GL_MAX_VIEWPORTS_NV)
-GL_ENUM(0x825C,GL_VIEWPORT_SUBPIXEL_BITS_NV)
-GL_ENUM(0x825D,GL_VIEWPORT_BOUNDS_RANGE_NV)
-GL_ENUM(0x825F,GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV)
+GL_ENUM(0x9350,GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV)
+GL_ENUM(0x9351,GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV)
+GL_ENUM(0x9352,GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV)
+GL_ENUM(0x9353,GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV)
+GL_ENUM(0x9354,GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV)
+GL_ENUM(0x9355,GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV)
+GL_ENUM(0x9356,GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV)
+GL_ENUM(0x9357,GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV)
+GL_ENUM(0x9358,GL_VIEWPORT_SWIZZLE_X_NV)
+GL_ENUM(0x9359,GL_VIEWPORT_SWIZZLE_Y_NV)
+GL_ENUM(0x935A,GL_VIEWPORT_SWIZZLE_Z_NV)
+GL_ENUM(0x935B,GL_VIEWPORT_SWIZZLE_W_NV)
 GL_ENUM(0x9630,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR)
 GL_ENUM(0x9632,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR)
 GL_ENUM(0x9631,GL_MAX_VIEWS_OVR)
+GL_ENUM(0x9633,GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR)
 GL_ENUM(0x8FB0,GL_BINNING_CONTROL_HINT_QCOM)
 GL_ENUM(0x8FB1,GL_CPU_OPTIMIZED_QCOM)
 GL_ENUM(0x8FB2,GL_GPU_OPTIMIZED_QCOM)
 GL_ENUM(0x8FB3,GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM)
+GL_ENUM(0x96A2,GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM)
+GL_ENUM(0x8BFB,GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM)
+GL_ENUM(0x8BFC,GL_TEXTURE_FOVEATED_MIN_PIXEL_DENSITY_QCOM)
+GL_ENUM(0x8BFD,GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM)
+GL_ENUM(0x8BFE,GL_TEXTURE_FOVEATED_NUM_FOCAL_POINTS_QUERY_QCOM)
+GL_ENUM(0x8BFF,GL_FRAMEBUFFER_INCOMPLETE_FOVEATION_QCOM)
 GL_ENUM(0x8FC4,GL_SHADER_BINARY_VIV)
diff --git a/opengl/libs/libGLESv2.map.txt b/opengl/libs/libGLESv2.map.txt
index 1b0042a..787c835 100644
--- a/opengl/libs/libGLESv2.map.txt
+++ b/opengl/libs/libGLESv2.map.txt
@@ -79,6 +79,7 @@
     glFramebufferRenderbuffer;
     glFramebufferTexture2D;
     glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9
+    glFramebufferTexture2DMultisampleEXT; # introduced=28
     glFramebufferTexture3DOES;
     glFrontFace;
     glGenBuffers;
@@ -147,6 +148,7 @@
     glReadPixels;
     glReleaseShaderCompiler;
     glRenderbufferStorage;
+    glRenderbufferStorageMultisampleEXT; # introduced=28
     glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9
     glSampleCoverage;
     glScissor;
diff --git a/opengl/libs/libGLESv3.map.txt b/opengl/libs/libGLESv3.map.txt
index 21f6cb6..a7b17f4 100644
--- a/opengl/libs/libGLESv3.map.txt
+++ b/opengl/libs/libGLESv3.map.txt
@@ -36,6 +36,8 @@
     glBlendFunciEXT; # introduced=21
     glBlitFramebuffer;
     glBufferData;
+    glBufferStorageEXT; # introduced=28
+    glBufferStorageExternalEXT; # introduced=28
     glBufferSubData;
     glCheckFramebufferStatus;
     glClear;
@@ -110,6 +112,7 @@
     glDrawRangeElementsBaseVertex; # introduced=24
     glEGLImageTargetRenderbufferStorageOES;
     glEGLImageTargetTexture2DOES;
+    glEGLImageTargetTexStorageEXT; # introduced=28
     glEnable;
     glEnableVertexAttribArray;
     glEnablei; # introduced=24
@@ -124,9 +127,12 @@
     glFramebufferRenderbuffer;
     glFramebufferTexture; # introduced=24
     glFramebufferTexture2D;
+    glFramebufferTexture2DMultisampleEXT; # introduced=28
     glFramebufferTexture3DOES;
     glFramebufferTextureEXT; # introduced=21
     glFramebufferTextureLayer;
+    glFramebufferTextureMultisampleMultiviewOVR; # introduced=28
+    glFramebufferTextureMultiviewOVR; # introduced=28
     glFrontFace;
     glGenBuffers;
     glGenFramebuffers;
@@ -306,6 +312,7 @@
     glReleaseShaderCompiler;
     glRenderbufferStorage;
     glRenderbufferStorageMultisample;
+    glRenderbufferStorageMultisampleEXT; # introduced=28
     glResumeTransformFeedback;
     glSampleCoverage;
     glSampleMaski; # introduced=21
diff --git a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
index 772b21a..285bba4 100644
--- a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
+++ b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt
@@ -16,15 +16,15 @@
 
 Status
 
-    Draft
+    Complete
 
 Version
 
-    Version 1.0, January 27, 2017
+    Version 3, October 11, 2017
 
 Number
 
-    EGL Extension #XXX
+    EGL Extension #123
 
 Dependencies
 
@@ -43,11 +43,11 @@
 
 New Types
 
-struct AHardwareBuffer
+    struct AHardwareBuffer
 
 New Procedures and Functions
 
-EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer)
+    EGLClientBuffer eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer)
 
 New Tokens
 
@@ -62,7 +62,7 @@
    "The command
 
         EGLClientBuffer eglGetNativeClientBufferANDROID(
-                                AHardwareBuffer *buffer)
+                                const struct AHardwareBuffer *buffer)
 
     may be used to create an EGLClientBuffer from an AHardwareBuffer object.
     EGL implementations must guarantee that the lifetime of the returned
@@ -92,6 +92,9 @@
 
 Revision History
 
+#3 (Jesse Hall, October 11, 2017)
+    - Assigned extension number, fixed minor issues for publication
+
 #2 (Craig Donner, February 17, 2017)
     - Fix typographical errors.
 
diff --git a/opengl/specs/README b/opengl/specs/README
index cba4453..fdafb1b 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -24,7 +24,8 @@
 0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
 0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
 0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
-0x314D - 0x314F      (unused)
+0x314D               EGL_GL_COLORSPACE_DEFAULT_EXT (EGL_EXT_image_gl_colorspace)
+0x314E - 0x314F      (unused)
 
      Value                       Extension
 ================     ==================================
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index d85af81..f246077 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -8,6 +8,11 @@
         "EGL_test.cpp",
     ],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index b67a053..5927dc1 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -50,10 +50,20 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 static bool hasWideColorDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
+static bool hasHdrDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
 class EGLTest : public ::testing::Test {
+public:
+    void get8BitConfig(EGLConfig& config);
+    void setSurfaceSmpteMetadata(EGLSurface surface);
+    void checkSurfaceSmpteMetadata(EGLSurface eglSurface);
+
 protected:
     EGLDisplay mEglDisplay;
 
@@ -365,6 +375,233 @@
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
 
+void EGLTest::get8BitConfig(EGLConfig& config) {
+    EGLint numConfigs;
+    EGLBoolean success;
+
+    // Use 8-bit to keep focus on colorspace aspect
+    const EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+            EGL_RED_SIZE,                 8,
+            EGL_GREEN_SIZE,               8,
+            EGL_BLUE_SIZE,                8,
+            EGL_ALPHA_SIZE,               8,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+            EGL_NONE,
+            // clang-format on
+    };
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    EGLint components[4];
+    EGLint value;
+    eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    // Verify component sizes on config match what was asked for.
+    EXPECT_EQ(components[0], 8);
+    EXPECT_EQ(components[1], 8);
+    EXPECT_EQ(components[2], 8);
+    EXPECT_EQ(components[3], 8);
+}
+
+void EGLTest::setSurfaceSmpteMetadata(EGLSurface surface) {
+    if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT,
+                         METADATA_SCALE(0.640));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT,
+                         METADATA_SCALE(0.330));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT,
+                         METADATA_SCALE(0.290));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT,
+                         METADATA_SCALE(0.600));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT,
+                         METADATA_SCALE(0.150));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT,
+                         METADATA_SCALE(0.060));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT,
+                         METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT,
+                         METADATA_SCALE(0.3290));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT,
+                         METADATA_SCALE(300));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT,
+                         METADATA_SCALE(0.7));
+    }
+
+    if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                         METADATA_SCALE(300));
+        eglSurfaceAttrib(mEglDisplay, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
+    }
+}
+
+void EGLTest::checkSurfaceSmpteMetadata(EGLSurface eglSurface) {
+    EGLBoolean success;
+    EGLint value;
+
+    if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.640), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.330), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.290), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.600), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.150), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.060), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_X_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.3127), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.3290), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(300.0), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(0.7), value);
+    }
+
+    if (hasEglExtension(mEglDisplay, "EGL_EXT_surface_CTA861_3_metadata")) {
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(300.0), value);
+        success = eglQuerySurface(mEglDisplay, eglSurface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT, &value);
+        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+        ASSERT_EQ(METADATA_SCALE(75.0), value);
+    }
+}
+
+TEST_F(EGLTest, EGLBT2020Linear) {
+    EGLConfig config;
+    EGLBoolean success;
+
+    if (!hasHdrDisplay) {
+        // skip this test if device does not have HDR display
+        RecordProperty("hasHdrDisplay", false);
+        return;
+    }
+
+    // Test that bt2020 linear extension exists
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_bt2020_linear"))
+            << "EGL_EXT_gl_colorspace_bt2020_linear extension not available";
+
+    ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    std::vector<EGLint> winAttrs;
+    winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
+    winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+
+    winAttrs.push_back(EGL_NONE);
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    EGLint value;
+    success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
+
+    ASSERT_NO_FATAL_FAILURE(setSurfaceSmpteMetadata(eglSurface));
+
+    ASSERT_NO_FATAL_FAILURE(checkSurfaceSmpteMetadata(eglSurface));
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLBT2020PQ) {
+    EGLConfig config;
+    EGLBoolean success;
+
+    if (!hasHdrDisplay) {
+        // skip this test if device does not have HDR display
+        RecordProperty("hasHdrDisplay", false);
+        return;
+    }
+
+    // Test that bt2020-pq extension exists
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_bt2020_pq"))
+            << "EGL_EXT_gl_colorspace_bt2020_pq extension not available";
+
+    ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+    std::vector<EGLint> winAttrs;
+    winAttrs.push_back(EGL_GL_COLORSPACE_KHR);
+    winAttrs.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+    winAttrs.push_back(EGL_NONE);
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs.data());
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    EGLint value;
+    success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_GL_COLORSPACE_BT2020_PQ_EXT, value);
+
+    ASSERT_NO_FATAL_FAILURE(setSurfaceSmpteMetadata(eglSurface));
+
+    ASSERT_NO_FATAL_FAILURE(checkSurfaceSmpteMetadata(eglSurface));
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
 TEST_F(EGLTest, EGLConfigFP16) {
     EGLint numConfigs;
     EGLConfig config;
@@ -372,13 +609,13 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
-        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
+        RecordProperty("hasWideColorDisplay", false);
         return;
     }
 
     ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float"));
 
-    EGLint attrs[] = {
+    const EGLint attrs[] = {
             // clang-format off
             EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
             EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
@@ -387,7 +624,7 @@
             EGL_BLUE_SIZE,                16,
             EGL_ALPHA_SIZE,               16,
             EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
-            EGL_NONE,                     EGL_NONE
+            EGL_NONE,
             // clang-format on
     };
     success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
@@ -437,7 +674,7 @@
 TEST_F(EGLTest, EGLNoConfigContext) {
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
-        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
+        RecordProperty("hasWideColorDisplay", false);
         return;
     }
 
@@ -475,11 +712,11 @@
 
     if (!hasWideColorDisplay) {
         // skip this test if device does not have wide-color display
-        std::cerr << "[          ] Device does not support wide-color, test skipped" << std::endl;
+        RecordProperty("hasWideColorDisplay", false);
         return;
     }
 
-    EGLint attrs[] = {
+    const EGLint attrs[] = {
             // clang-format off
             EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
             EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
index bbbc447..5c398a6 100644
--- a/opengl/tests/angeles/Android.bp
+++ b/opengl/tests/angeles/Android.bp
@@ -8,6 +8,11 @@
         "demo.c",
     ],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index ced8786..9d2c98f 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -62,9 +62,6 @@
 
 int gAppAlive = 1;
 
-static const char sAppName[] =
-        "San Angeles Observation OpenGL ES version example (Linux)";
-
 static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
 static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
 static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
@@ -132,7 +129,6 @@
     EGLContext context;
     EGLConfig config;
     EGLSurface surface;
-    EGLint w, h;
     EGLDisplay dpy;
 
     EGLNativeWindowType window = windowSurface.getSurface();
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
index c46477c..ee967970 100644
--- a/opengl/tests/configdump/Android.bp
+++ b/opengl/tests/configdump/Android.bp
@@ -5,6 +5,11 @@
 
     srcs: ["configdump.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     shared_libs: [
         "libcutils",
         "libEGL",
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
index 543f1e3..689cee4 100644
--- a/opengl/tests/fillrate/Android.bp
+++ b/opengl/tests/fillrate/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["fillrate.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index a42f3f2..f022069 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -153,7 +153,7 @@
 
      for (int c=1, j=0 ; c<32 ; c++, j++) {
          nsecs_t t = times[j];
-         printf("%ld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+         printf("%lld\t%d\t%f\n", (long long)t, c, (double(t)/c)/1000000.0);
      }
 
 
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
index 5f925c8..23241e1 100644
--- a/opengl/tests/filter/Android.bp
+++ b/opengl/tests/filter/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
index 287ee93..49778a0 100644
--- a/opengl/tests/filter/filter.cpp
+++ b/opengl/tests/filter/filter.cpp
@@ -140,6 +140,7 @@
 
      //glDrawTexiOES(0, 0, 0, dim, dim);
      
+#if !USE_DRAW_TEXTURE || !GL_OES_draw_texture
      const GLfloat fdim = dim;
      const GLfloat vertices[4][2] = {
              { 0,     0    },
@@ -154,6 +155,7 @@
              { 1,  1 },
              { 1,  0 }
      };
+#endif
      
      if (!usePbuffer) {
          eglSwapBuffers(dpy, surface);
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
index fb5671d..be20851 100644
--- a/opengl/tests/finish/Android.bp
+++ b/opengl/tests/finish/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index ab955fe..63ea822 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -64,7 +64,6 @@
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
      eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
-     GLint dim = w<h ? w : h;
 
      glBindTexture(GL_TEXTURE_2D, 0);
      glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
index 7403271..f4538ad 100644
--- a/opengl/tests/gl2_basic/Android.bp
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -16,5 +16,10 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+
 }
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 67c0969..0bb77f3 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -32,6 +32,8 @@
 using namespace android;
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 static void printGLString(const char *name, GLenum s) {
     // fprintf(stderr, "printGLString %s, %d\n", name, s);
     const char *v = (const char *) glGetString(s);
@@ -265,6 +267,39 @@
     return true;
 }
 
+void setSurfaceMetadata(EGLDisplay dpy, EGLSurface surface) {
+    static EGLBoolean toggle = GL_FALSE;
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, METADATA_SCALE(0.640));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, METADATA_SCALE(0.330));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, METADATA_SCALE(0.290));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, METADATA_SCALE(0.600));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, METADATA_SCALE(0.150));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, METADATA_SCALE(0.060));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT, METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, METADATA_SCALE(0.3290));
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(350));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(300));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, METADATA_SCALE(0.7));
+    }
+
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_CTA861_3_metadata")) {
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(300));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(325));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
+    }
+    toggle = !toggle;
+}
+
 int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
@@ -318,10 +353,11 @@
     printf("Chose this configuration:\n");
     printEGLConfiguration(dpy, myConfig);
 
-    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+    EGLint winAttribs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
+    surface = eglCreateWindowSurface(dpy, myConfig, window, winAttribs);
     checkEglError("eglCreateWindowSurface");
     if (surface == EGL_NO_SURFACE) {
-        printf("gelCreateWindowSurface failed.\n");
+        printf("eglCreateWindowSurface failed.\n");
         return 0;
     }
 
@@ -340,7 +376,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
@@ -357,6 +392,7 @@
 
     for (;;) {
         renderFrame();
+        setSurfaceMetadata(dpy, surface);
         eglSwapBuffers(dpy, surface);
         checkEglError("eglSwapBuffers");
     }
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
index 51e269c..87fa7ea 100644
--- a/opengl/tests/gl2_copyTexImage/Android.bp
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -16,5 +16,9 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
index e0aafa2..ada98aa 100644
--- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -444,7 +444,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gl2_java/Android.mk b/opengl/tests/gl2_java/Android.mk
index 34f4aee..71aa5a0 100644
--- a/opengl/tests/gl2_java/Android.mk
+++ b/opengl/tests/gl2_java/Android.mk
@@ -14,5 +14,6 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := GL2Java
+LOCAL_SDK_VERSION := current
 
 include $(BUILD_PACKAGE)
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index 409bd73..b0081c2 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -14,6 +14,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := GL2JNI
+LOCAL_SDK_VERSION := current
 
 LOCAL_JNI_SHARED_LIBRARIES := libgl2jni
 
@@ -36,13 +37,13 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
 LOCAL_MODULE := libgl2jni
 
+LOCAL_SDK_VERSION := current
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp
index 5af4f6b..9b22c6c 100644
--- a/opengl/tests/gl2_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl2_jni/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GL2JNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
index 613d678..b64d94d 100644
--- a/opengl/tests/gl2_yuvtex/Android.bp
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -20,5 +20,7 @@
     cflags: [
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 22128ab..850a615 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -190,7 +190,7 @@
 static sp<GraphicBuffer> yuvTexBuffer;
 static GLuint yuvTex;
 
-bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) {
+bool setupYuvTexSurface(EGLDisplay dpy, EGLContext /*context*/) {
     int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1;
     int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
     yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
@@ -399,7 +399,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
index 881d8ce..5eed17e 100644
--- a/opengl/tests/gl_basic/Android.bp
+++ b/opengl/tests/gl_basic/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["gl_basic.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index 0b663f7..63d94be 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -15,6 +15,8 @@
 
 using namespace android;
 
+#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
+
 EGLDisplay eglDisplay;
 EGLSurface eglSurface;
 EGLContext eglContext;
@@ -191,8 +193,6 @@
 
 int main(int /*argc*/, char **/*argv*/)
 {
-    int q;
-    int start, end;
     printf("Initializing EGL...\n");
     WindowSurface windowSurface;
     if(!init_gl_surface(windowSurface))
@@ -212,7 +212,6 @@
 
 int init_gl_surface(const WindowSurface& windowSurface)
 {
-    EGLint numConfigs = 1;
     EGLConfig myConfig = {0};
     EGLint attrib[] =
     {
@@ -265,7 +264,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(eglDisplay, eglSurface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
     
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
@@ -334,11 +332,41 @@
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 }
 
+void setSurfaceMetadata(EGLDisplay dpy, EGLSurface surface) {
+    static EGLBoolean toggle = GL_FALSE;
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_SMPTE2086_metadata")) {
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, METADATA_SCALE(0.640));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, METADATA_SCALE(0.330));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, METADATA_SCALE(0.290));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, METADATA_SCALE(0.600));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, METADATA_SCALE(0.150));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, METADATA_SCALE(0.060));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT, METADATA_SCALE(0.3127));
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, METADATA_SCALE(0.3290));
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(350));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(300));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, METADATA_SCALE(0.7));
+    }
+
+    if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_CTA861_3_metadata")) {
+        if (toggle) {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(300));
+        } else {
+            eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
+                             METADATA_SCALE(325));
+        }
+        eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
+                         METADATA_SCALE(75));
+    }
+    toggle = !toggle;
+}
+
 void render()
 {
-    int i, j;
-    int quads = 1;
-
     const GLfloat vertices[] = {
             -1,  -1,  0,
              1,  -1,  0,
@@ -361,5 +389,6 @@
     int nelem = sizeof(indices)/sizeof(indices[0]);
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, indices);
+    setSurfaceMetadata(eglDisplay, eglSurface);
     eglSwapBuffers(eglDisplay, eglSurface);
 }
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index 11b4c8b..d64dfcf 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -14,6 +14,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := GLJNI
+LOCAL_SDK_VERSION := current
 
 LOCAL_JNI_SHARED_LIBRARIES := libgljni
 
@@ -36,13 +37,14 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv1_CM
 
 LOCAL_MODULE := libgljni
 
+LOCAL_SDK_VERSION := current
+
 LOCAL_ARM_MODE := arm
 
 
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index 3aa8adb..88f3228 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GLJNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <GLES/gl.h>
 
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
index 0ffb121..25a317c 100644
--- a/opengl/tests/gl_perf/Android.bp
+++ b/opengl/tests/gl_perf/Android.bp
@@ -20,5 +20,9 @@
 
     static_libs: ["libglTest"],
 
-    cflags: ["-DGL_GLEXT_PROTOTYPES"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
 }
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
index 2998864..047db20 100644
--- a/opengl/tests/gl_perf/gl2_perf.cpp
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -44,13 +44,6 @@
     }
 }
 
-static void checkGlError(const char* op) {
-    for (GLint error = glGetError(); error; error
-            = glGetError()) {
-        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
-    }
-}
-
 bool doTest(uint32_t w, uint32_t h);
 
 static EGLDisplay dpy;
@@ -118,7 +111,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     glViewport(0, 0, w, h);
 
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
index 854b54f..3f411ea 100644
--- a/opengl/tests/gl_perfapp/Android.mk
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -39,11 +39,12 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
+LOCAL_SDK_VERSION := current
+
 LOCAL_MODULE := libglperf
 
 
diff --git a/opengl/tests/gl_perfapp/jni/gl_code.cpp b/opengl/tests/gl_perfapp/jni/gl_code.cpp
index 0cb594a..bd1fd83 100644
--- a/opengl/tests/gl_perfapp/jni/gl_code.cpp
+++ b/opengl/tests/gl_perfapp/jni/gl_code.cpp
@@ -2,16 +2,21 @@
 
 #include <jni.h>
 #define LOG_TAG "GLPerf gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
-#include <utils/Timers.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <time.h>
 
 #include "../../gl_perf/fill_common.cpp"
 
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
index b6be327..9b4924a 100644
--- a/opengl/tests/gl_yuvtex/Android.bp
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -19,5 +19,7 @@
     cflags: [
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
     ],
 }
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index 7ef3f4e..2c9640b 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -289,7 +289,6 @@
     checkEglError("eglQuerySurface");
     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
     checkEglError("eglQuerySurface");
-    GLint dim = w < h ? w : h;
 
     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
index 1991ed9..5bdc0a8 100644
--- a/opengl/tests/gldual/Android.mk
+++ b/opengl/tests/gldual/Android.mk
@@ -14,6 +14,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := GLDual
+LOCAL_SDK_VERSION := current
 
 LOCAL_JNI_SHARED_LIBRARIES := libgldualjni
 
@@ -36,13 +37,13 @@
   gl_code.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libutils \
 	liblog \
 	libEGL \
 	libGLESv2
 
 LOCAL_MODULE := libgldualjni
 
+LOCAL_SDK_VERSION := current
 
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gldual/jni/gl_code.cpp b/opengl/tests/gldual/jni/gl_code.cpp
index 90d150b..4e44976 100644
--- a/opengl/tests/gldual/jni/gl_code.cpp
+++ b/opengl/tests/gldual/jni/gl_code.cpp
@@ -2,7 +2,12 @@
 
 #include <jni.h>
 #define LOG_TAG "GL2JNI gl_code.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
+
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
index 414c804..33c3dba 100644
--- a/opengl/tests/gralloc/Android.bp
+++ b/opengl/tests/gralloc/Android.bp
@@ -3,6 +3,11 @@
 
     srcs: ["gralloc.cpp"],
 
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
     gtest: false,
 
     shared_libs: [
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 69e56ff..5956366 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -170,7 +170,7 @@
 static EGLint width, height;
 
 // Function prototypes
-static Rectangle parseRect(string rectStr);
+static Rectangle parseRect(const string& rectStr);
 void init(void);
 void printSyntax(const char *cmd);
 
@@ -358,7 +358,7 @@
 
 // Parse string description of rectangle and add it to list of rectangles
 // to be rendered.
-static Rectangle parseRect(string rectStr)
+static Rectangle parseRect(const string& rectStr)
 {
     int rv;
     string str;
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 1428945..2b76279 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -62,19 +62,10 @@
         return;
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    err = sc->setLayer(0x7FFFFFFF);     // always on top
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
-        return;
-    }
-
-    err = sc->show();
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
-        return;
-    }
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction{}
+            .setLayer(sc, 0x7FFFFFFF)
+            .show(sc)
+            .apply();
 
     mSurfaceControl = sc;
 }
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
index 9563e61..0047231 100644
--- a/opengl/tests/lighting1709/Android.mk
+++ b/opengl/tests/lighting1709/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := LightingTest
+LOCAL_SDK_VERSION := current
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
index 968756a..3df0a0f 100644
--- a/opengl/tests/linetex/Android.mk
+++ b/opengl/tests/linetex/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	linetex.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
     libEGL \
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
index b0b15eb..2a2c12f 100644
--- a/opengl/tests/swapinterval/Android.mk
+++ b/opengl/tests/swapinterval/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	swapinterval.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
index 500abf3..ca6654a 100644
--- a/opengl/tests/testFramerate/Android.mk
+++ b/opengl/tests/testFramerate/Android.mk
@@ -15,5 +15,6 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := TestFramerate
+LOCAL_SDK_VERSION := system_current
 
 include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testPauseResume/Android.mk b/opengl/tests/testPauseResume/Android.mk
index cf8bdc3..dda5424 100644
--- a/opengl/tests/testPauseResume/Android.mk
+++ b/opengl/tests/testPauseResume/Android.mk
@@ -14,5 +14,6 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := TestEGL
+LOCAL_SDK_VERSION := current
 
 include $(BUILD_PACKAGE)
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index bee61f9..629a2d2 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -21,5 +21,6 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+LOCAL_CFLAGS += -Wall -Werror
 
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index 7be942a..bdb5c82 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -87,12 +87,6 @@
              0x0000, 0x5555, 0x0000, 0x5555, 
              0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF  };
 
-     uint16_t t5551[]  = { 
-             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
-             0xFFFF, 0x0000, 0xFFFF, 0x0000,
-             0x0000, 0xFFFF, 0x0000, 0xFFFF, 
-             0xFFFF, 0x0000, 0xFFFF, 0x0000  };
-
      uint32_t t32[]  = { 
              0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 
              0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF, 
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 64382ed..7055afa 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	tritex.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
     libEGL \
diff --git a/opengl/tests/tritex/tritex.cpp b/opengl/tests/tritex/tritex.cpp
index 2db73ef..c008003 100644
--- a/opengl/tests/tritex/tritex.cpp
+++ b/opengl/tests/tritex/tritex.cpp
@@ -93,9 +93,6 @@
 

 int main(int argc, char **argv)

 {

-    int q;
-    int start, end;

-
     printf("Initializing EGL...\n");
 

     WindowSurface windowSurface;
@@ -120,7 +117,6 @@
 

 int init_gl_surface(const WindowSurface& windowSurface)

 {

-    EGLint numConfigs = 1;

     EGLConfig myConfig = {0};

     EGLint attrib[] =

     {

diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f6813fd..f90e3ec 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -17,11 +17,10 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 4df61d3..12b96f4 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -17,11 +17,10 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 1fa9275..dd17ca4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index 4004a7d..b2bbdf6 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES2/gl2.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
index c5bdf32..b039bc9 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl3.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
index 2260a80..dd00e92 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl31.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
index 130612d..88e00be 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
index e9c5fc7..3e7ec8b 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
@@ -17,8 +17,7 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
-#include <GLES3/gl32.h>
\ No newline at end of file
+#include <GLES3/gl32.h>
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 7062c57..2163d76 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -1,5 +1,5 @@
 #include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 #include <assert.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 026cb37..29296ff 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -17,11 +17,10 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index a140091..fa981a8 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -117,6 +117,8 @@
         reg.OutputGenerator.__init__(self, sys.stderr, sys.stderr, None)
 
     def genCmd(self, cmd, name):
+        if re.search('Win32', name):
+            return
         reg.OutputGenerator.genCmd(self, cmd, name)
 
         rtype, fname = parseProto(cmd.elem.find('proto'))
@@ -142,6 +144,8 @@
         self.enums = collections.OrderedDict()
 
     def genCmd(self, cmd, name):
+        if re.search('Win32', name):
+            return
         reg.OutputGenerator.genCmd(self, cmd, name)
         rtype, fname = parseProto(cmd.elem.find('proto'))
         params = [parseParam(p) for p in cmd.elem.findall('param')]
@@ -166,6 +170,8 @@
         # so leaving for later.
         if re.search('_BIT($|\d*_)', name):
             return
+        if re.search('D3D|WIN32', name):
+            return
 
         # Skip non-hex values (GL_TRUE, GL_FALSE, header guard junk)
         if not re.search('0x[0-9A-Fa-f]+', value):
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
old mode 100755
new mode 100644
index c2d3494..e422e96
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <registry>
     <!--
-    Copyright (c) 2013-2014 The Khronos Group Inc.
+    Copyright (c) 2013-2017 The Khronos Group Inc.
 
     Permission is hereby granted, free of charge, to any person obtaining a
     copy of this software and/or associated documentation files (the
@@ -29,7 +29,7 @@
     together with documentation, schema, and Python generator scripts used
     to generate C header files for EGL, can be found in the Khronos Registry
     at
-        http://www.opengl.org/registry/
+        https://www.github.com/KhronosGroup/EGL-Registry
     -->
 
     <!-- SECTION: EGL type definitions. Does not include GL types. -->
@@ -38,6 +38,7 @@
         <type name="khrplatform">#include &lt;KHR/khrplatform.h&gt;</type>
         <type name="eglplatform" requires="khrplatform">#include &lt;EGL/eglplatform.h&gt;</type>
         <type name="khronos_utime_nanoseconds_t" requires="khrplatform"/>
+        <type name="khronos_stime_nanoseconds_t" requires="khrplatform"/>
         <type name="khronos_uint64_t" requires="khrplatform"/>
         <type name="khronos_ssize_t" requires="khrplatform"/>
         <type name="EGLNativeDisplayType" requires="eglplatform"/>
@@ -47,6 +48,7 @@
         <type name="NativeDisplayType" requires="eglplatform"/>
         <type name="NativePixmapType" requires="eglplatform"/>
         <type name="NativeWindowType" requires="eglplatform"/>
+        <type>struct <name>AHardwareBuffer</name>;</type>
         <!-- Dummy placeholders for non-EGL types -->
         <type name="Bool"/>
             <!-- These are actual EGL types.  -->
@@ -76,6 +78,7 @@
         <type requires="khrplatform">typedef khronos_utime_nanoseconds_t <name>EGLTimeNV</name>;</type>
         <type requires="khrplatform">typedef khronos_utime_nanoseconds_t <name>EGLuint64NV</name>;</type>
         <type requires="khrplatform">typedef khronos_uint64_t <name>EGLuint64KHR</name>;</type>
+        <type requires="khrplatform">typedef khronos_stime_nanoseconds_t <name>EGLnsecsANDROID</name>;</type>
         <type>typedef int <name>EGLNativeFileDescriptorKHR</name>;</type>
         <type requires="khrplatform">typedef khronos_ssize_t <name>EGLsizeiANDROID</name>;</type>
         <type requires="EGLsizeiANDROID">typedef void (*<name>EGLSetBlobFuncANDROID</name>) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);</type>
@@ -112,6 +115,7 @@
             <!--
         <enum value="0x0800"      name="EGL_STREAM_BIT_NV" comment="Draft EGL_NV_stream_producer_eglsurface extension (bug 8064)"/>
             -->
+        <enum value="0x1000" name="EGL_MUTABLE_RENDER_BUFFER_BIT_KHR"/>
     </enums>
 
     <enums namespace="EGLRenderableTypeMask" type="bitmask" comment="EGL_RENDERABLE_TYPE bits">
@@ -130,6 +134,12 @@
         <enum value="0x0002" name="EGL_WRITE_SURFACE_BIT_KHR"/>
     </enums>
 
+    <enums namespace="EGLNativeBufferUsageFlags" type="bitmask" comment="EGL_NATIVE_BUFFER_USAGE_ANDROID bits">
+        <enum value="0x00000001" name="EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID"/>
+        <enum value="0x00000002" name="EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID"/>
+        <enum value="0x00000004" name="EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID"/>
+    </enums>
+
     <enums namespace="EGLSyncFlagsKHR" type="bitmask" comment="Fence/reusable sync wait bits">
         <enum value="0x0001" name="EGL_SYNC_FLUSH_COMMANDS_BIT"/>
         <enum value="0x0001" name="EGL_SYNC_FLUSH_COMMANDS_BIT_KHR" alias="EGL_SYNC_FLUSH_COMMANDS_BIT"/>
@@ -139,6 +149,7 @@
     <enums namespace="EGLDRMBufferUseMESAMask" type="bitmask" comment="EGL_DRM_BUFFER_USE_MESA bits">
         <enum value="0x00000001" name="EGL_DRM_BUFFER_USE_SCANOUT_MESA"/>
         <enum value="0x00000002" name="EGL_DRM_BUFFER_USE_SHARE_MESA"/>
+        <enum value="0x00000004" name="EGL_DRM_BUFFER_USE_CURSOR_MESA"/>
     </enums>
 
     <!-- Should be shared with GL, but aren't aren't since the
@@ -165,7 +176,11 @@
          tokens are reused for different purposes in different
          extensions and API versions). -->
 
-    <enums namespace="EGL" start="0x0000" end="0x2FFF" vendor="ARB"/>
+    <enums namespace="EGL" start="0x0000" end="0x2FFF" vendor="KHR" comment="Reserved for enumerants shared with WGL, GLX, and GL">
+        <enum value="0" name="EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR"/>
+        <enum value="0x2097" name="EGL_CONTEXT_RELEASE_BEHAVIOR_KHR"/>
+        <enum value="0x2098" name="EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR"/>
+    </enums>
 
     <enums namespace="EGL" group="Boolean" vendor="ARB">
         <enum value="0" name="EGL_FALSE"/>
@@ -173,24 +188,24 @@
     </enums>
 
     <enums namespace="EGL" group="SpecialNumbers" vendor="ARB" comment="Tokens whose numeric value is intrinsically meaningful">
-        <enum value="((EGLint)-1)" name="EGL_DONT_CARE"/>
-        <enum value="((EGLint)-1)" name="EGL_UNKNOWN"/>
+        <enum value="EGL_CAST(EGLint,-1)" name="EGL_DONT_CARE"/>
+        <enum value="EGL_CAST(EGLint,-1)" name="EGL_UNKNOWN"/>
         <enum value="-1" name="EGL_NO_NATIVE_FENCE_FD_ANDROID"/>
         <enum value="0" name="EGL_DEPTH_ENCODING_NONE_NV"/>
-        <enum value="((EGLContext)0)" name="EGL_NO_CONTEXT"/>
-        <enum value="((EGLDeviceEXT)(0))" name="EGL_NO_DEVICE_EXT"/>
-        <enum value="((EGLDisplay)0)" name="EGL_NO_DISPLAY"/>
-        <enum value="((EGLImage)0)" name="EGL_NO_IMAGE"/>
-        <enum value="((EGLImageKHR)0)" name="EGL_NO_IMAGE_KHR"/>
-        <enum value="((EGLNativeDisplayType)0)" name="EGL_DEFAULT_DISPLAY"/>
-        <enum value="((EGLNativeFileDescriptorKHR)(-1))" name="EGL_NO_FILE_DESCRIPTOR_KHR"/>
-        <enum value="((EGLOutputLayerEXT)0)" name="EGL_NO_OUTPUT_LAYER_EXT"/>
-        <enum value="((EGLOutputPortEXT)0)" name="EGL_NO_OUTPUT_PORT_EXT"/>
-        <enum value="((EGLStreamKHR)0)" name="EGL_NO_STREAM_KHR"/>
-        <enum value="((EGLSurface)0)" name="EGL_NO_SURFACE"/>
-        <enum value="((EGLSync)0)" name="EGL_NO_SYNC"/>
-        <enum value="((EGLSyncKHR)0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/>
-        <enum value="((EGLSyncNV)0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/>
+        <enum value="EGL_CAST(EGLContext,0)" name="EGL_NO_CONTEXT"/>
+        <enum value="EGL_CAST(EGLDeviceEXT,0)" name="EGL_NO_DEVICE_EXT"/>
+        <enum value="EGL_CAST(EGLDisplay,0)" name="EGL_NO_DISPLAY"/>
+        <enum value="EGL_CAST(EGLImage,0)" name="EGL_NO_IMAGE"/>
+        <enum value="EGL_CAST(EGLImageKHR,0)" name="EGL_NO_IMAGE_KHR"/>
+        <enum value="EGL_CAST(EGLNativeDisplayType,0)" name="EGL_DEFAULT_DISPLAY"/>
+        <enum value="EGL_CAST(EGLNativeFileDescriptorKHR,-1)" name="EGL_NO_FILE_DESCRIPTOR_KHR"/>
+        <enum value="EGL_CAST(EGLOutputLayerEXT,0)" name="EGL_NO_OUTPUT_LAYER_EXT"/>
+        <enum value="EGL_CAST(EGLOutputPortEXT,0)" name="EGL_NO_OUTPUT_PORT_EXT"/>
+        <enum value="EGL_CAST(EGLStreamKHR,0)" name="EGL_NO_STREAM_KHR"/>
+        <enum value="EGL_CAST(EGLSurface,0)" name="EGL_NO_SURFACE"/>
+        <enum value="EGL_CAST(EGLSync,0)" name="EGL_NO_SYNC"/>
+        <enum value="EGL_CAST(EGLSyncKHR,0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/>
+        <enum value="EGL_CAST(EGLSyncNV,0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/>
         <enum value="EGL_CAST(EGLConfig,0)" name="EGL_NO_CONFIG_KHR"/>
         <enum value="10000" name="EGL_DISPLAY_SCALING"/>
         <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER" type="ull"/>
@@ -357,7 +372,7 @@
         <enum value="0x30BD" name="EGL_GL_TEXTURE_ZOFFSET"/>
         <enum value="0x30BD" name="EGL_GL_TEXTURE_ZOFFSET_KHR" alias="EGL_GL_TEXTURE_ZOFFSET"/>
         <enum value="0x30BE" name="EGL_POST_SUB_BUFFER_SUPPORTED_NV"/>
-        <enum value="0x30BF" name="EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT" alias="EGL_CONTEXT_OPENGL_ROBUST_ACCESS"/>
+        <enum value="0x30BF" name="EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT"/>
     </enums>
 
     <enums namespace="EGL" start="0x30C0-0x30CF" vendor="KHR">
@@ -442,7 +457,10 @@
         <enum value="0x3101" name="EGL_CONTEXT_PRIORITY_HIGH_IMG"/>
         <enum value="0x3102" name="EGL_CONTEXT_PRIORITY_MEDIUM_IMG"/>
         <enum value="0x3103" name="EGL_CONTEXT_PRIORITY_LOW_IMG"/>
-            <unused start="0x3104" end="0x310F"/>
+            <unused start="0x3104"/>
+        <enum value="0x3105" name="EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG"/>
+        <enum value="0x3106" name="EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG"/>
+            <unused start="0x3107" end="0x310F"/>
     </enums>
 
     <enums namespace="EGL" start="0x3110" end="0x311F" vendor="ATX" comment="Reserved for Tim Renouf, Antix (Khronos bug 4949)">
@@ -475,12 +493,15 @@
         <enum value="0x3140" name="EGL_NATIVE_BUFFER_ANDROID"/>
         <enum value="0x3141" name="EGL_PLATFORM_ANDROID_KHR"/>
         <enum value="0x3142" name="EGL_RECORDABLE_ANDROID"/>
-            <unused start="0x3143"/>
+        <enum value="0x3143" name="EGL_NATIVE_BUFFER_USAGE_ANDROID"/>
         <enum value="0x3144" name="EGL_SYNC_NATIVE_FENCE_ANDROID"/>
         <enum value="0x3145" name="EGL_SYNC_NATIVE_FENCE_FD_ANDROID"/>
         <enum value="0x3146" name="EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID"/>
         <enum value="0x3147" name="EGL_FRAMEBUFFER_TARGET_ANDROID"/>
-            <unused start="0x3148" end="0x314F"/>
+            <unused start="0x3148" end="0x314B"/>
+        <enum value="0x314C" name="EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID"/>
+        <enum value="0x314D" name="EGL_GL_COLORSPACE_DEFAULT_EXT"/>
+            <unused start="0x314E" end="0x314F"/>
     </enums>
 
     <enums namespace="EGL" start="0x3150" end="0x315F" vendor="NOK" comment="Reserved for Robert Palmer (Khronos bug 5368)">
@@ -533,7 +554,9 @@
         <enum value="0x31D7" name="EGL_PLATFORM_GBM_MESA" alias="EGL_PLATFORM_GBM_KHR"/>
         <enum value="0x31D8" name="EGL_PLATFORM_WAYLAND_KHR"/>
         <enum value="0x31D8" name="EGL_PLATFORM_WAYLAND_EXT" alias="EGL_PLATFORM_WAYLAND_KHR"/>
-            <unused start="0x31D9" end="0x31DF"/>
+            <unused start="0x31D9" end="0x31DC"/>
+        <enum value="0x31DD" name="EGL_PLATFORM_SURFACELESS_MESA"/>
+            <unused start="0x31DE" end="0x31DF"/>
     </enums>
 
     <enums namespace="EGL" start="0x31E0" end="0x31EF" vendor="HI" comment="Reserved for Mark Callow (Khronos bug 6799)">
@@ -606,7 +629,23 @@
         <enum value="0x323B" name="EGL_CUDA_EVENT_HANDLE_NV"/>
         <enum value="0x323C" name="EGL_SYNC_CUDA_EVENT_NV"/>
         <enum value="0x323D" name="EGL_SYNC_CUDA_EVENT_COMPLETE_NV"/>
-            <unused start="0x323E" end="0x324F"/>
+            <unused start="0x323E"/>
+        <enum value="0x323F" name="EGL_STREAM_CROSS_PARTITION_NV"/>
+        <enum value="0x3240" name="EGL_STREAM_STATE_INITIALIZING_NV"/>
+        <enum value="0x3241" name="EGL_STREAM_TYPE_NV"/>
+        <enum value="0x3242" name="EGL_STREAM_PROTOCOL_NV"/>
+        <enum value="0x3243" name="EGL_STREAM_ENDPOINT_NV"/>
+        <enum value="0x3244" name="EGL_STREAM_LOCAL_NV"/>
+        <enum value="0x3245" name="EGL_STREAM_CROSS_PROCESS_NV"/>
+        <enum value="0x3246" name="EGL_STREAM_PROTOCOL_FD_NV"/>
+        <enum value="0x3247" name="EGL_STREAM_PRODUCER_NV"/>
+        <enum value="0x3248" name="EGL_STREAM_CONSUMER_NV"/>
+            <unused start="0x3239" end="0x324A"/>
+        <enum value="0x324B" name="EGL_STREAM_PROTOCOL_SOCKET_NV"/>
+        <enum value="0x324C" name="EGL_SOCKET_HANDLE_NV"/>
+        <enum value="0x324D" name="EGL_SOCKET_TYPE_NV"/>
+        <enum value="0x324E" name="EGL_SOCKET_TYPE_UNIX_NV"/>
+        <enum value="0x324F" name="EGL_SOCKET_TYPE_INET_NV"/>
         <enum value="0x3250" name="EGL_MAX_STREAM_METADATA_BLOCKS_NV"/>
         <enum value="0x3251" name="EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV"/>
         <enum value="0x3252" name="EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV"/>
@@ -651,7 +690,9 @@
         <enum value="0x3284" name="EGL_YUV_CHROMA_SITING_0_EXT"/>
         <enum value="0x3285" name="EGL_YUV_CHROMA_SITING_0_5_EXT"/>
         <enum value="0x3286" name="EGL_DISCARD_SAMPLES_ARM"/>
-            <unused start="0x3287" end="0x328F"/>
+            <unused start="0x3287" end="0x3289"/>
+        <enum value="0x328A" name="EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM"/>
+            <unused start="0x328B" end="0x328F"/>
     </enums>
 
     <enums namespace="EGL" start="0x3290" end="0x329F" vendor="MESA" comment="Reserved for John K&#229;re Alsaker (Public bug 757)">
@@ -716,11 +757,18 @@
     <enums namespace="EGL" start="0x3320" end="0x339F" vendor="NV" comment="Reserved for James Jones (Bug 13209)">
             <unused start="0x3320" end="0x3327"/>
         <enum value="0x3328" name="EGL_PENDING_METADATA_NV"/>
-            <unused start="0x3329" end="0x332B"/>
+        <enum value="0x3329" name="EGL_PENDING_FRAME_NV"/>
+        <enum value="0x332A" name="EGL_STREAM_TIME_PENDING_NV"/>
+            <unused start="0x332B"/>
         <enum value="0x332C" name="EGL_YUV_PLANE0_TEXTURE_UNIT_NV"/>
         <enum value="0x332D" name="EGL_YUV_PLANE1_TEXTURE_UNIT_NV"/>
         <enum value="0x332E" name="EGL_YUV_PLANE2_TEXTURE_UNIT_NV"/>
-            <unused start="0x332F" end="0x339F"/>
+            <unused start="0x332F" end="0x3333"/>
+        <enum value="0x3334" name="EGL_SUPPORT_RESET_NV"/>
+        <enum value="0x3335" name="EGL_SUPPORT_REUSE_NV"/>
+        <enum value="0x3336" name="EGL_STREAM_FIFO_SYNCHRONOUS_NV"/>
+        <enum value="0x3337" name="EGL_PRODUCER_MAX_FRAME_HINT_NV"/>
+        <enum value="0x3338" name="EGL_CONSUMER_MAX_FRAME_HINT_NV"/>
         <enum value="0x3339" name="EGL_COLOR_COMPONENT_TYPE_EXT"/>
         <enum value="0x333A" name="EGL_COLOR_COMPONENT_TYPE_FIXED_EXT"/>
         <enum value="0x333B" name="EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT"/>
@@ -738,9 +786,19 @@
         <enum value="0x3349" name="EGL_SMPTE2086_MAX_LUMINANCE_EXT"/>
         <enum value="0x334A" name="EGL_SMPTE2086_MIN_LUMINANCE_EXT"/>
         <enum value="50000"  name="EGL_METADATA_SCALING_EXT"/>
-            <unused start="0x334B" end="0x334F"/>
+            <unused start="0x334B"/>
+        <enum value="0x334C" name="EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV"/>
+        <enum value="0x334D" name="EGL_STREAM_CROSS_OBJECT_NV"/>
+        <enum value="0x334E" name="EGL_STREAM_CROSS_DISPLAY_NV"/>
+        <enum value="0x334F" name="EGL_STREAM_CROSS_SYSTEM_NV"/>
         <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
-            <unused start="0x3351" end="0x3361"/>
+        <enum value="0x3351" name="EGL_GL_COLORSPACE_SCRGB_EXT"/>
+        <enum value="0x3352" name="EGL_TRACK_REFERENCES_KHR"/>
+            <unused start="0x3353" end="0x3356"/>
+        <enum value="0x3357" name="EGL_CONTEXT_PRIORITY_REALTIME_NV"/>
+            <unused start="0x3358" end="0x335F"/>
+        <enum value="0x3360" name="EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT"/>
+        <enum value="0x3361" name="EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT"/>
         <enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
         <enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
             <unused start="0x3364" end="0x339F"/>
@@ -777,6 +835,59 @@
             <unused start="0x33E0" end="0x342F"/>
     </enums>
 
+    <enums namespace="EGL" start="0x3430" end="0x343F" vendor="ANDROID" comment="Reserved for Pablo Ceballos (Bug 15874)">
+        <enum value="EGL_CAST(EGLnsecsANDROID,-2)" name="EGL_TIMESTAMP_PENDING_ANDROID"/>
+        <enum value="EGL_CAST(EGLnsecsANDROID,-1)" name="EGL_TIMESTAMP_INVALID_ANDROID"/>
+        <enum value="0x3430" name="EGL_TIMESTAMPS_ANDROID"/>
+        <enum value="0x3431" name="EGL_COMPOSITE_DEADLINE_ANDROID"/>
+        <enum value="0x3432" name="EGL_COMPOSITE_INTERVAL_ANDROID"/>
+        <enum value="0x3433" name="EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID"/>
+        <enum value="0x3434" name="EGL_REQUESTED_PRESENT_TIME_ANDROID"/>
+        <enum value="0x3435" name="EGL_RENDERING_COMPLETE_TIME_ANDROID"/>
+        <enum value="0x3436" name="EGL_COMPOSITION_LATCH_TIME_ANDROID"/>
+        <enum value="0x3437" name="EGL_FIRST_COMPOSITION_START_TIME_ANDROID"/>
+        <enum value="0x3438" name="EGL_LAST_COMPOSITION_START_TIME_ANDROID"/>
+        <enum value="0x3439" name="EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID"/>
+        <enum value="0x343A" name="EGL_DISPLAY_PRESENT_TIME_ANDROID"/>
+        <enum value="0x343B" name="EGL_DEQUEUE_READY_TIME_ANDROID"/>
+        <enum value="0x343C" name="EGL_READS_DONE_TIME_ANDROID"/>
+            <unused start="0x343D" end="0x343F"/>
+    </enums>
+
+    <enums namespace="EGL" start="0x3440" end="0x344F" vendor="ANDROID" comment="Reserved for Kristian Kristensen (Bug 16033)">
+        <enum value="0x3440" name="EGL_DMA_BUF_PLANE3_FD_EXT"/>
+        <enum value="0x3441" name="EGL_DMA_BUF_PLANE3_OFFSET_EXT"/>
+        <enum value="0x3442" name="EGL_DMA_BUF_PLANE3_PITCH_EXT"/>
+        <enum value="0x3443" name="EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT"/>
+        <enum value="0x3444" name="EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT"/>
+        <enum value="0x3445" name="EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT"/>
+        <enum value="0x3446" name="EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT"/>
+        <enum value="0x3447" name="EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT"/>
+        <enum value="0x3448" name="EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT"/>
+        <enum value="0x3449" name="EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT"/>
+        <enum value="0x344A" name="EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT"/>
+            <unused start="0x344B" end="0x344F"/>
+    </enums>
+
+    <enums namespace="EGL" start="0x3450" end="0x345F" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 16106)">
+            <unused start="0x3450" end="0x345F"/>
+    </enums>
+
+    <enums namespace="EGL" start="0x3460" end="0x346F" vendor="COREAVI" comment="Reserved for Daniel Herring (Bug 16162)">
+        <enum value="0x3460" name="EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT"/>
+        <enum value="0x3461" name="EGL_EXTERNAL_REF_ID_EXT"/>
+        <enum value="0x3462" name="EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT"/>
+        <enum value="0x3463" name="EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT"/>
+        <enum value="0x3464" name="EGL_FRONT_BUFFER_EXT"/>
+        <unused start="0x3465" end="0x346F"/>
+    </enums>
+
+    <enums namespace="EGL" start="0x3470" end="0x347F" vendor="EXT" comment="Reserved for Daniel Stone (PR 14)">
+        <enum value="0x3470" name="EGL_IMPORT_SYNC_TYPE_EXT"/>
+        <enum value="0x3471" name="EGL_IMPORT_IMPLICIT_SYNC_EXT"/>
+        <enum value="0x3472" name="EGL_IMPORT_EXPLICIT_SYNC_EXT"/>
+    </enums>
+
 <!-- Please remember that new enumerant allocations must be obtained by
      request to the Khronos API registrar (see comments at the top of this
      file) File requests in the Khronos Bugzilla, EGL project, Registry
@@ -786,8 +897,8 @@
 
 <!-- Reservable for future use. To generate a new range, allocate multiples
      of 16 starting at the lowest available point in this block. -->
-    <enums namespace="EGL" start="0x3470" end="0x3FFF" vendor="KHR">
-            <unused start="0x3470" end="0x3FFF" comment="Reserved for future use"/>
+    <enums namespace="EGL" start="0x3480" end="0x3FFF" vendor="KHR" comment="Reserved for future use">
+            <unused start="0x3480" end="0x3FFF"/>
     </enums>
 
     <enums namespace="EGL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with GL.">
@@ -880,6 +991,10 @@
             <param>const <ptype>EGLint</ptype> *<name>attrib_list</name></param>
         </command>
         <command>
+            <proto><ptype>EGLClientBuffer</ptype> <name>eglCreateNativeClientBufferANDROID</name></proto>
+            <param>const <ptype>EGLint</ptype> *<name>attrib_list</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLSurface</ptype> <name>eglCreatePbufferFromClientBuffer</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLenum</ptype> <name>buftype</name></param>
@@ -945,6 +1060,11 @@
             <param>const <ptype>EGLint</ptype> *<name>attrib_list</name></param>
         </command>
         <command>
+            <proto><ptype>EGLStreamKHR</ptype> <name>eglCreateStreamAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLSurface</ptype> <name>eglCreateStreamProducerSurfaceKHR</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLConfig</ptype> <name>config</name></param>
@@ -1095,6 +1215,10 @@
             <proto><ptype>EGLint</ptype> <name>eglGetError</name></proto>
         </command>
         <command>
+            <proto><ptype>EGLClientBuffer</ptype> <name>eglGetNativeClientBufferANDROID</name></proto>
+            <param>const struct <ptype>AHardwareBuffer</ptype> *<name>buffer</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglGetOutputLayersEXT</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
@@ -1207,6 +1331,47 @@
             <param><ptype>EGLint</ptype> <name>height</name></param>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglPresentationTimeANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLnsecsANDROID</ptype> <name>time</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglGetCompositorTimingSupportedANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLint</ptype> <name>name</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglGetCompositorTimingANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLint</ptype> <name>numTimestamps</name></param>
+            <param> const <ptype>EGLint</ptype> *<name>names</name></param>
+            <param><ptype>EGLnsecsANDROID</ptype> *<name>values</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglGetNextFrameIdANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLuint64KHR</ptype> *<name>frameId</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglGetFrameTimestampSupportedANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLint</ptype> <name>timestamp</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglGetFrameTimestampsANDROID</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLuint64KHR</ptype> <name>frameId</name></param>
+            <param><ptype>EGLint</ptype> <name>numTimestamps</name></param>
+            <param> const <ptype>EGLint</ptype> *<name>timestamps</name></param>
+            <param><ptype>EGLnsecsANDROID</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLenum</ptype> <name>eglQueryAPI</name></proto>
         </command>
         <command>
@@ -1243,13 +1408,36 @@
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLint</ptype> <name>attribute</name></param>
             <param><ptype>EGLAttrib</ptype> *<name>value</name></param>
+            <alias name="eglQueryDisplayAttribKHR"/>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglQueryDisplayAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLint</ptype> <name>name</name></param>
+            <param><ptype>EGLAttrib</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglQueryDisplayAttribNV</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLint</ptype> <name>attribute</name></param>
             <param><ptype>EGLAttrib</ptype> *<name>value</name></param>
-            <alias name="eglQueryDisplayAttribEXT"/>
+            <alias name="eglQueryDisplayAttribKHR"/>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglQueryDmaBufFormatsEXT</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLint</ptype> <name>max_formats</name></param>
+            <param><ptype>EGLint</ptype> *<name>formats</name></param>
+            <param><ptype>EGLint</ptype> *<name>num_formats</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglQueryDmaBufModifiersEXT</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLint</ptype> <name>format</name></param>
+            <param><ptype>EGLint</ptype> <name>max_modifiers</name></param>
+            <param><ptype>EGLuint64KHR</ptype> *<name>modifiers</name></param>
+            <param><ptype>EGLBoolean</ptype> *<name>external_only</name></param>
+            <param><ptype>EGLint</ptype> *<name>num_modifiers</name></param>
         </command>
         <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglQueryNativeDisplayNV</name></proto>
@@ -1302,6 +1490,13 @@
             <param><ptype>EGLint</ptype> *<name>value</name></param>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglQueryStreamAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+            <param><ptype>EGLenum</ptype> <name>attribute</name></param>
+            <param><ptype>EGLAttrib</ptype> *<name>value</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglQueryStreamMetadataNV</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
@@ -1361,6 +1556,11 @@
             <proto><ptype>EGLBoolean</ptype> <name>eglReleaseThread</name></proto>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglResetStreamNV</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+        </command>
+        <command>
             <proto>void <name>eglSetBlobCacheFuncsANDROID</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLSetBlobFuncANDROID</ptype> <name>set</name></param>
@@ -1374,6 +1574,13 @@
             <param><ptype>EGLint</ptype> <name>n_rects</name></param>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglSetStreamAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+            <param><ptype>EGLenum</ptype> <name>attribute</name></param>
+            <param><ptype>EGLAttrib</ptype> <name>value</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglSetStreamMetadataNV</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
@@ -1406,6 +1613,12 @@
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglStreamConsumerAcquireAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+            <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglStreamConsumerGLTextureExternalKHR</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
@@ -1414,7 +1627,7 @@
             <proto><ptype>EGLBoolean</ptype> <name>eglStreamConsumerGLTextureExternalAttribsNV</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
-            <param><ptype>EGLAttrib</ptype> <name>*attrib_list</name></param>
+            <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
         </command>
         <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglStreamConsumerOutputEXT</name></proto>
@@ -1428,6 +1641,12 @@
             <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
         </command>
         <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglStreamConsumerReleaseAttribKHR</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLStreamKHR</ptype> <name>stream</name></param>
+            <param>const <ptype>EGLAttrib</ptype> *<name>attrib_list</name></param>
+        </command>
+        <command>
             <proto><ptype>EGLBoolean</ptype> <name>eglSurfaceAttrib</name></proto>
             <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
             <param><ptype>EGLSurface</ptype> <name>surface</name></param>
@@ -1503,6 +1722,44 @@
             <param><ptype>EGLSyncKHR</ptype> <name>sync</name></param>
             <param><ptype>EGLint</ptype> <name>flags</name></param>
         </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSetContextListEXT</name></proto>
+            <param>const <ptype>EGLint</ptype> *<name>external_ref_ids</name></param>
+            <param><ptype>EGLint</ptype> <name>num_entries</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSetContextAttributesEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_ref_id</name></param>
+            <param>const <ptype>EGLint</ptype> *<name>context_attributes</name></param>
+            <param><ptype>EGLint</ptype> <name>num_entries</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSetWindowListEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_ref_id</name></param>
+            <param>const <ptype>EGLint</ptype> *<name>external_win_ids</name></param>
+            <param><ptype>EGLint</ptype> <name>num_entries</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSetWindowAttributesEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_win_id</name></param>
+            <param>const <ptype>EGLint</ptype> *<name>window_attributes</name></param>
+            <param><ptype>EGLint</ptype> <name>num_entries</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorBindTexWindowEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_win_id</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSetSizeEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_win_id</name></param>
+            <param><ptype>EGLint</ptype> <name>width</name></param>
+            <param><ptype>EGLint</ptype> <name>height</name></param>
+        </command>
+        <command>
+            <proto><ptype>EGLBoolean</ptype> <name>eglCompositorSwapPolicyEXT</name></proto>
+            <param><ptype>EGLint</ptype> <name>external_win_id</name></param>
+            <param><ptype>EGLint</ptype> <name>policy</name></param>
+        </command>
     </commands>
 
     <!-- SECTION: EGL API interface definitions. -->
@@ -1775,11 +2032,30 @@
                 <command name="eglSetBlobCacheFuncsANDROID"/>
             </require>
         </extension>
+        <extension name="EGL_ANDROID_create_native_client_buffer" supported="egl">
+            <require>
+                <enum name="EGL_NATIVE_BUFFER_USAGE_ANDROID"/>
+                <enum name="EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID"/>
+                <enum name="EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID"/>
+                <enum name="EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID"/>
+                <command name="eglCreateNativeClientBufferANDROID"/>
+            </require>
+        </extension>
         <extension name="EGL_ANDROID_framebuffer_target" supported="egl">
             <require>
                 <enum name="EGL_FRAMEBUFFER_TARGET_ANDROID"/>
             </require>
         </extension>
+        <extension name="EGL_ANDROID_get_native_client_buffer" supported="egl">
+            <require>
+                <command name="eglGetNativeClientBufferANDROID"/>
+            </require>
+        </extension>
+        <extension name="EGL_ANDROID_front_buffer_auto_refresh" supported="egl">
+            <require>
+                <enum name="EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID"/>
+            </require>
+        </extension>
         <extension name="EGL_ANDROID_image_native_buffer" supported="egl">
             <require>
                 <enum name="EGL_NATIVE_BUFFER_ANDROID"/>
@@ -1794,6 +2070,35 @@
                 <command name="eglDupNativeFenceFDANDROID"/>
             </require>
         </extension>
+        <extension name="EGL_ANDROID_presentation_time" supported="egl">
+            <require>
+                <command name="eglPresentationTimeANDROID"/>
+            </require>
+        </extension>
+        <extension name="EGL_ANDROID_get_frame_timestamps" supported="egl">
+            <require>
+                <enum name="EGL_TIMESTAMP_PENDING_ANDROID"/>
+                <enum name="EGL_TIMESTAMP_INVALID_ANDROID"/>
+                <enum name="EGL_TIMESTAMPS_ANDROID"/>
+                <enum name="EGL_COMPOSITE_DEADLINE_ANDROID"/>
+                <enum name="EGL_COMPOSITE_INTERVAL_ANDROID"/>
+                <enum name="EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID"/>
+                <enum name="EGL_REQUESTED_PRESENT_TIME_ANDROID"/>
+                <enum name="EGL_RENDERING_COMPLETE_TIME_ANDROID"/>
+                <enum name="EGL_COMPOSITION_LATCH_TIME_ANDROID"/>
+                <enum name="EGL_FIRST_COMPOSITION_START_TIME_ANDROID"/>
+                <enum name="EGL_LAST_COMPOSITION_START_TIME_ANDROID"/>
+                <enum name="EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID"/>
+                <enum name="EGL_DISPLAY_PRESENT_TIME_ANDROID"/>
+                <enum name="EGL_DEQUEUE_READY_TIME_ANDROID"/>
+                <enum name="EGL_READS_DONE_TIME_ANDROID"/>
+                <command name="eglGetCompositorTimingSupportedANDROID"/>
+                <command name="eglGetCompositorTimingANDROID"/>
+                <command name="eglGetNextFrameIdANDROID"/>
+                <command name="eglGetFrameTimestampSupportedANDROID"/>
+                <command name="eglGetFrameTimestampsANDROID"/>
+            </require>
+        </extension>
         <extension name="EGL_ANDROID_recordable" supported="egl">
             <require>
                 <enum name="EGL_RECORDABLE_ANDROID"/>
@@ -1825,6 +2130,11 @@
                 <enum name="EGL_FIXED_SIZE_ANGLE"/>
             </require>
         </extension>
+        <extension name="EGL_ARM_implicit_external_sync" supported="egl">
+            <require>
+                <enum name="EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM"/>
+            </require>
+        </extension>
         <extension name="EGL_ARM_pixmap_multisample_discard" supported="egl">
             <require>
                 <enum name="EGL_DISCARD_SAMPLES_ARM"/>
@@ -1890,6 +2200,11 @@
                 <enum name="EGL_GL_COLORSPACE_BT2020_PQ_EXT"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_gl_colorspace_scrgb" supported="egl">
+            <require>
+                <enum name="EGL_GL_COLORSPACE_SCRGB_EXT"/>
+            </require>
+        </extension>
         <extension name="EGL_EXT_gl_colorspace_scrgb_linear" supported="egl">
             <require>
                 <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
@@ -1931,6 +2246,29 @@
                 <enum name="EGL_YUV_CHROMA_SITING_0_5_EXT"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_image_dma_buf_import_modifiers" supported="egl">
+            <require>
+                <enum name="EGL_DMA_BUF_PLANE3_FD_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE3_OFFSET_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE3_PITCH_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT"/>
+                <enum name="EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT"/>
+                <command name="eglQueryDmaBufFormatsEXT"/>
+                <command name="eglQueryDmaBufModifiersEXT"/>
+            </require>
+        </extension>
+        <extension name="EGL_EXT_image_gl_colorspace" supported="egl">
+            <require>
+                <enum name="EGL_GL_COLORSPACE"/>
+                <enum name="EGL_GL_COLORSPACE_DEFAULT_EXT"/>
+            </require>
+        </extension>
         <extension name="EGL_EXT_multiview_window" supported="egl">
             <require>
                 <enum name="EGL_MULTIVIEW_VIEW_COUNT_EXT"/>
@@ -1968,6 +2306,13 @@
                 <enum name="EGL_OPENWF_PORT_ID_EXT"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_pixel_format_float" supported="egl">
+            <require>
+                <enum name="EGL_COLOR_COMPONENT_TYPE_EXT"/>
+                <enum name="EGL_COLOR_COMPONENT_TYPE_FIXED_EXT"/>
+                <enum name="EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT"/>
+            </require>
+        </extension>
         <extension name="EGL_EXT_platform_base" supported="egl">
             <require>
                 <command name="eglGetPlatformDisplayEXT"/>
@@ -1991,6 +2336,11 @@
                 <enum name="EGL_PLATFORM_X11_SCREEN_EXT"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_protected_content" supported="egl">
+            <require>
+                <enum name="EGL_PROTECTED_CONTENT_EXT"/>
+            </require>
+        </extension>
         <extension name="EGL_EXT_protected_surface" supported="egl">
             <require>
                 <enum name="EGL_PROTECTED_CONTENT_EXT"/>
@@ -2016,7 +2366,6 @@
                 <enum name="EGL_METADATA_SCALING_EXT"/>
             </require>
         </extension>
-
         <extension name="EGL_EXT_swap_buffers_with_damage" supported="egl">
             <require>
                 <command name="eglSwapBuffersWithDamageEXT"/>
@@ -2073,6 +2422,12 @@
                 <enum name="EGL_CONTEXT_PRIORITY_LOW_IMG"/>
             </require>
         </extension>
+        <extension name="EGL_IMG_image_plane_attribs" supported="egl">
+            <require>
+                <enum name="EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG"/>
+                <enum name="EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG"/>
+            </require>
+        </extension>
         <extension name="EGL_KHR_cl_event" supported="egl">
             <require>
                 <enum name="EGL_CL_EVENT_HANDLE_KHR"/>
@@ -2096,6 +2451,13 @@
             </require>
         </extension>
         <extension name="EGL_KHR_client_get_all_proc_addresses" supported="egl" comment="Alias of EGL_KHR_get_all_proc_addresses"/>
+        <extension name="EGL_KHR_context_flush_control" supported="egl">
+            <require>
+                <enum name="EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR"/>
+                <enum name="EGL_CONTEXT_RELEASE_BEHAVIOR_KHR"/>
+                <enum name="EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR"/>
+            </require>
+        </extension>
         <extension name="EGL_KHR_create_context" supported="egl">
             <require>
                 <enum name="EGL_CONTEXT_MAJOR_VERSION_KHR"/>
@@ -2141,6 +2503,12 @@
                 <command name="eglLabelObjectKHR"/>
             </require>
         </extension>
+        <extension name="EGL_KHR_display_reference" supported="egl">
+            <require>
+                <enum name="EGL_TRACK_REFERENCES_KHR"/>
+                <command name="eglQueryDisplayAttribKHR"/>
+            </require>
+        </extension>
         <extension name="EGL_KHR_fence_sync" protect="KHRONOS_SUPPORT_INT64" supported="egl">
             <require>
                 <!-- Most interfaces also defined by EGL_KHR_reusable sync -->
@@ -2270,6 +2638,16 @@
                 <command name="eglQuerySurface64KHR"/>
             </require>
         </extension>
+        <extension name="EGL_KHR_mutable_render_buffer" supported="egl">
+            <require>
+                <enum name="EGL_MUTABLE_RENDER_BUFFER_BIT_KHR"/>
+            </require>
+        </extension>
+        <extension name="EGL_KHR_no_config_context" supported="egl">
+            <require>
+                <enum name="EGL_NO_CONFIG_KHR"/>
+            </require>
+        </extension>
         <extension name="EGL_KHR_partial_update" supported="egl">
             <require>
                 <enum name="EGL_BUFFER_AGE_KHR"/>
@@ -2338,6 +2716,19 @@
                 <command name="eglQueryStreamu64KHR"/>
             </require>
         </extension>
+        <extension name="EGL_KHR_stream_attrib" protect="KHRONOS_SUPPORT_INT64" supported="egl">
+            <require>
+                <enum name="EGL_CONSUMER_LATENCY_USEC_KHR"/>
+                <enum name="EGL_STREAM_STATE_KHR"/>
+                <enum name="EGL_STREAM_STATE_CREATED_KHR"/>
+                <enum name="EGL_STREAM_STATE_CONNECTING_KHR"/>
+                <command name="eglCreateStreamAttribKHR"/>
+                <command name="eglSetStreamAttribKHR"/>
+                <command name="eglQueryStreamAttribKHR"/>
+                <command name="eglStreamConsumerAcquireAttribKHR"/>
+                <command name="eglStreamConsumerReleaseAttribKHR"/>
+            </require>
+        </extension>
         <extension name="EGL_KHR_stream_consumer_gltexture" protect="EGL_KHR_stream" supported="egl">
             <require>
                 <enum name="EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR"/>
@@ -2394,6 +2785,7 @@
                 <enum name="EGL_DRM_BUFFER_STRIDE_MESA"/>
                 <enum name="EGL_DRM_BUFFER_USE_SCANOUT_MESA"/>
                 <enum name="EGL_DRM_BUFFER_USE_SHARE_MESA"/>
+                <enum name="EGL_DRM_BUFFER_USE_CURSOR_MESA"/>
                 <command name="eglCreateDRMImageMESA"/>
                 <command name="eglExportDRMImageMESA"/>
             </require>
@@ -2410,6 +2802,11 @@
                 <enum name="EGL_PLATFORM_GBM_MESA"/>
             </require>
         </extension>
+        <extension name="EGL_MESA_platform_surfaceless" supported="egl">
+            <require>
+                <enum name="EGL_PLATFORM_SURFACELESS_MESA"/>
+            </require>
+        </extension>
         <extension name="EGL_NOK_swap_region" supported="egl">
             <require>
                 <command name="eglSwapBuffersRegionNOK"/>
@@ -2436,6 +2833,11 @@
                 <enum name="EGL_COVERAGE_SAMPLES_NV"/>
             </require>
         </extension>
+        <extension name="EGL_NV_context_priority_realtime" supported="egl">
+            <require>
+                <enum name="EGL_CONTEXT_PRIORITY_REALTIME_NV"/>
+            </require>
+        </extension>
         <extension name="EGL_NV_coverage_sample_resolve" supported="egl">
             <require>
                 <enum name="EGL_COVERAGE_SAMPLE_RESOLVE_NV"/>
@@ -2479,6 +2881,11 @@
                 <command name="eglPostSubBufferNV"/>
             </require>
         </extension>
+        <extension name="EGL_NV_robustness_video_memory_purge" supported="egl">
+            <require>
+                <enum name="EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV"/>
+            </require>
+        </extension>
         <extension name="EGL_NV_stream_consumer_gltexture_yuv" supported="egl">
             <require>
                 <enum name="EGL_YUV_PLANE0_TEXTURE_UNIT_NV"/>
@@ -2489,6 +2896,48 @@
                 <command name="eglStreamConsumerGLTextureExternalAttribsNV"/>
             </require>
         </extension>
+        <extension name="EGL_NV_stream_cross_object" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_CROSS_OBJECT_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_cross_display" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_CROSS_DISPLAY_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_cross_partition" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_CROSS_PARTITION_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_cross_process" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_CROSS_PROCESS_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_cross_system" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_CROSS_SYSTEM_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_fifo_next" supported="egl">
+            <require>
+                <enum name="EGL_PENDING_FRAME_NV"/>
+                <enum name="EGL_STREAM_TIME_PENDING_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_fifo_synchronous" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_FIFO_SYNCHRONOUS_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_frame_limits" supported="egl">
+            <require>
+                <enum name="EGL_PRODUCER_MAX_FRAME_HINT_NV"/>
+                <enum name="EGL_CONSUMER_MAX_FRAME_HINT_NV"/>
+            </require>
+        </extension>
         <extension name="EGL_NV_stream_metadata" supported="egl">
             <require>
                 <enum name="EGL_MAX_STREAM_METADATA_BLOCKS_NV"/>
@@ -2510,6 +2959,44 @@
                 <command name="eglQueryStreamMetadataNV"/>
             </require>
         </extension>
+        <extension name="EGL_NV_stream_reset" supported="egl">
+            <require>
+                <enum name="EGL_SUPPORT_RESET_NV"/>
+                <enum name="EGL_SUPPORT_REUSE_NV"/>
+                <command name="eglResetStreamNV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_remote" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_STATE_INITIALIZING_NV"/>
+                <enum name="EGL_STREAM_TYPE_NV"/>
+                <enum name="EGL_STREAM_PROTOCOL_NV"/>
+                <enum name="EGL_STREAM_ENDPOINT_NV"/>
+                <enum name="EGL_STREAM_LOCAL_NV"/>
+                <enum name="EGL_STREAM_PRODUCER_NV"/>
+                <enum name="EGL_STREAM_CONSUMER_NV"/>
+            </require>
+            <require comment="Supported only if EGL_KHR_stream_cross_process_fd is supported">
+                <enum name="EGL_STREAM_PROTOCOL_FD_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_socket" supported="egl">
+            <require>
+                <enum name="EGL_STREAM_PROTOCOL_SOCKET_NV"/>
+                <enum name="EGL_SOCKET_HANDLE_NV"/>
+                <enum name="EGL_SOCKET_TYPE_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_socket_inet" supported="egl">
+            <require>
+                <enum name="EGL_SOCKET_TYPE_INET_NV"/>
+            </require>
+        </extension>
+        <extension name="EGL_NV_stream_socket_unix" supported="egl">
+            <require>
+                <enum name="EGL_SOCKET_TYPE_UNIX_NV"/>
+            </require>
+        </extension>
         <extension name="EGL_NV_stream_sync" supported="egl">
             <require>
                 <enum name="EGL_SYNC_TYPE_KHR"/>
@@ -2556,5 +3043,39 @@
                 <enum name="EGL_NATIVE_SURFACE_TIZEN"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_compositor" supported="egl">
+            <require>
+                <enum name="EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT"/>
+                <enum name="EGL_EXTERNAL_REF_ID_EXT"/>
+                <enum name="EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT"/>
+                <enum name="EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT"/>
+
+                <command name="eglCompositorSetContextListEXT"/>
+                <command name="eglCompositorSetContextAttributesEXT"/>
+                <command name="eglCompositorSetWindowListEXT"/>
+                <command name="eglCompositorSetWindowAttributesEXT"/>
+                <command name="eglCompositorBindTexWindowEXT"/>
+                <command name="eglCompositorSetSizeEXT"/>
+                <command name="eglCompositorSwapPolicyEXT"/>
+            </require>
+        </extension>
+        <extension name="EGL_EXT_surface_CTA861_3_metadata" supported="egl">
+            <require>
+                <enum name="EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT"/>
+                <enum name="EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT"/>
+            </require>
+        </extension>
+        <extension name="EGL_EXT_image_implicit_sync_control" supported="egl">
+            <require>
+                <enum name="EGL_IMPORT_SYNC_TYPE_EXT"/>
+                <enum name="EGL_IMPORT_IMPLICIT_SYNC_EXT"/>
+                <enum name="EGL_IMPORT_EXPLICIT_SYNC_EXT"/>
+            </require>
+        </extension>
+        <extension name="EGL_EXT_bind_to_front" supported="egl">
+            <require>
+                <enum name="EGL_FRONT_BUFFER_EXT"/>
+            </require>
+        </extension>
     </extensions>
 </registry>
diff --git a/opengl/tools/glgen2/registry/gl.xml b/opengl/tools/glgen2/registry/gl.xml
old mode 100755
new mode 100644
index be231c7..9b27342
--- a/opengl/tools/glgen2/registry/gl.xml
+++ b/opengl/tools/glgen2/registry/gl.xml
@@ -1,36 +1,27 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <registry>
     <comment>
-Copyright (c) 2013-2015 The Khronos Group Inc.
+Copyright (c) 2013-2017 The Khronos Group Inc.
 
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and/or associated documentation files (the
-"Materials"), to deal in the Materials without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Materials, and to
-permit persons to whom the Materials are furnished to do so, subject to
-the following conditions:
+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
 
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Materials.
+    http://www.apache.org/licenses/LICENSE-2.0
 
-THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+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.
 
 ------------------------------------------------------------------------
 
-This file, gl.xml, is the OpenGL and OpenGL API Registry. The older
-".spec" file format has been retired and will no longer be updated with
-new extensions and API versions. The canonical version of the registry,
-together with documentation, schema, and Python generator scripts used
-to generate C header files for OpenGL and OpenGL ES, can always be found
-in the Khronos Registry at
-        http://www.opengl.org/registry/
+This file, gl.xml, is the OpenGL and OpenGL API Registry. The canonical
+version of the registry, together with documentation, schema, and Python
+generator scripts used to generate C header files for OpenGL and OpenGL ES,
+can always be found in the Khronos Registry at
+        https://github.com/KhronosGroup/OpenGL-Registry
     </comment>
 
     <!-- SECTION: GL type definitions. -->
@@ -92,6 +83,7 @@
         <type>typedef float <name>GLclampf</name>;</type>
         <type>typedef double <name>GLdouble</name>;</type>
         <type>typedef double <name>GLclampd</name>;</type>
+        <type>typedef void *<name>GLeglClientBufferEXT</name>;</type>
         <type>typedef void *<name>GLeglImageOES</name>;</type>
         <type>typedef char <name>GLchar</name>;</type>
         <type>typedef char <name>GLcharARB</name>;</type>
@@ -142,10 +134,16 @@
         <type api="gles2" requires="khrplatform">typedef khronos_intptr_t <name>GLintptr</name>;</type>
         <type api="gles2" requires="khrplatform">typedef khronos_ssize_t <name>GLsizeiptr</name>;</type>
             <!-- GLES 2 types (none currently) -->
+            <!-- GLSC 2 types -->
+        <type api="glsc2" requires="khrplatform">typedef khronos_uint8_t <name>GLubyte</name>;</type>
+        <type api="glsc2" requires="khrplatform">typedef khronos_float_t <name>GLfloat</name>;</type>
+        <type api="glsc2" requires="khrplatform">typedef khronos_intptr_t <name>GLintptr</name>;</type>
+        <type api="glsc2" requires="khrplatform">typedef khronos_ssize_t <name>GLsizeiptr</name>;</type>
             <!-- Vendor extension types -->
         <type>typedef void (<apientry/> *<name>GLDEBUGPROCAMD</name>)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);</type>
         <type>typedef unsigned short <name>GLhalfNV</name>;</type>
         <type requires="GLintptr">typedef GLintptr <name>GLvdpauSurfaceNV</name>;</type>
+        <type>typedef void (<apientry/> *<name>GLVULKANPROCNV</name>)(void);</type>
     </types>
 
     <!-- SECTION: GL parameter class type definitions. -->
@@ -207,37 +205,9 @@
             <enum name="GL_LOGIC_OP"/>
             <enum name="GL_MAX_EXT"/>
             <enum name="GL_MIN_EXT"/>
-        </group>
-
-        <group name="BlendingFactorDest">
-            <enum name="GL_CONSTANT_ALPHA_EXT"/>
-            <enum name="GL_CONSTANT_COLOR_EXT"/>
-            <enum name="GL_DST_ALPHA"/>
-            <enum name="GL_ONE"/>
-            <enum name="GL_ONE_MINUS_CONSTANT_ALPHA_EXT"/>
-            <enum name="GL_ONE_MINUS_CONSTANT_COLOR_EXT"/>
-            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
-            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
-            <enum name="GL_ONE_MINUS_SRC_COLOR"/>
-            <enum name="GL_SRC_ALPHA"/>
-            <enum name="GL_SRC_COLOR"/>
-            <enum name="GL_ZERO"/>
-        </group>
-
-        <group name="BlendingFactorSrc">
-            <enum name="GL_CONSTANT_ALPHA_EXT"/>
-            <enum name="GL_CONSTANT_COLOR_EXT"/>
-            <enum name="GL_DST_ALPHA"/>
-            <enum name="GL_DST_COLOR"/>
-            <enum name="GL_ONE"/>
-            <enum name="GL_ONE_MINUS_CONSTANT_ALPHA_EXT"/>
-            <enum name="GL_ONE_MINUS_CONSTANT_COLOR_EXT"/>
-            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
-            <enum name="GL_ONE_MINUS_DST_COLOR"/>
-            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
-            <enum name="GL_SRC_ALPHA"/>
-            <enum name="GL_SRC_ALPHA_SATURATE"/>
-            <enum name="GL_ZERO"/>
+            <enum name="GL_FUNC_ADD"/>
+            <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
+            <enum name="GL_FUNC_SUBTRACT"/>
         </group>
 
         <group name="Boolean">
@@ -245,6 +215,95 @@
             <enum name="GL_TRUE"/>
         </group>
 
+        <group name="BufferBitQCOM">
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT7_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT6_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT5_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT4_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT3_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT2_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT1_QCOM"/>
+            <enum name="GL_MULTISAMPLE_BUFFER_BIT0_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT7_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT6_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT5_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT4_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT3_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT2_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT1_QCOM"/>
+            <enum name="GL_STENCIL_BUFFER_BIT0_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT7_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT6_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT5_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT4_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT3_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT2_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT1_QCOM"/>
+            <enum name="GL_DEPTH_BUFFER_BIT0_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT7_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT6_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT5_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT4_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT3_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT2_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT1_QCOM"/>
+            <enum name="GL_COLOR_BUFFER_BIT0_QCOM"/>
+        </group>
+
+        <group name="BufferTargetARB">
+          <enum name="GL_ARRAY_BUFFER"/>
+          <enum name="GL_ATOMIC_COUNTER_BUFFER" />
+          <enum name="GL_COPY_READ_BUFFER" />
+          <enum name="GL_COPY_WRITE_BUFFER" />
+          <enum name="GL_DISPATCH_INDIRECT_BUFFER" />
+          <enum name="GL_DRAW_INDIRECT_BUFFER" />
+          <enum name="GL_ELEMENT_ARRAY_BUFFER" />
+          <enum name="GL_PIXEL_PACK_BUFFER" />
+          <enum name="GL_PIXEL_UNPACK_BUFFER" />
+          <enum name="GL_QUERY_BUFFER" />
+          <enum name="GL_SHADER_STORAGE_BUFFER" />
+          <enum name="GL_TEXTURE_BUFFER" />
+          <enum name="GL_TRANSFORM_FEEDBACK_BUFFER" />
+          <enum name="GL_UNIFORM_BUFFER" />
+        </group>
+
+        <group name="BufferUsageARB">
+          <enum name="GL_STREAM_DRAW"/>
+          <enum name="GL_STREAM_READ"/>
+          <enum name="GL_STREAM_COPY"/>
+          <enum name="GL_STATIC_DRAW"/>
+          <enum name="GL_STATIC_READ"/>
+          <enum name="GL_STATIC_COPY"/>
+          <enum name="GL_DYNAMIC_DRAW"/>
+          <enum name="GL_DYNAMIC_READ"/>
+          <enum name="GL_DYNAMIC_COPY"/>
+        </group>
+
+        <group name="BufferAccessARB">
+          <enum name="GL_READ_ONLY"/>
+          <enum name="GL_WRITE_ONLY"/>
+          <enum name="GL_READ_WRITE"/>
+        </group>
+
+        <group name="BufferAccessMask">
+            <enum name="GL_MAP_COHERENT_BIT"/>
+            <enum name="GL_MAP_COHERENT_BIT_EXT"/>
+            <enum name="GL_MAP_FLUSH_EXPLICIT_BIT"/>
+            <enum name="GL_MAP_FLUSH_EXPLICIT_BIT_EXT"/>
+            <enum name="GL_MAP_INVALIDATE_BUFFER_BIT"/>
+            <enum name="GL_MAP_INVALIDATE_BUFFER_BIT_EXT"/>
+            <enum name="GL_MAP_INVALIDATE_RANGE_BIT"/>
+            <enum name="GL_MAP_INVALIDATE_RANGE_BIT_EXT"/>
+            <enum name="GL_MAP_PERSISTENT_BIT"/>
+            <enum name="GL_MAP_PERSISTENT_BIT_EXT"/>
+            <enum name="GL_MAP_READ_BIT"/>
+            <enum name="GL_MAP_READ_BIT_EXT"/>
+            <enum name="GL_MAP_UNSYNCHRONIZED_BIT"/>
+            <enum name="GL_MAP_UNSYNCHRONIZED_BIT_EXT"/>
+            <enum name="GL_MAP_WRITE_BIT"/>
+            <enum name="GL_MAP_WRITE_BIT_EXT"/>
+        </group>
+
         <group name="ClearBufferMask">
             <enum name="GL_ACCUM_BUFFER_BIT"/>
             <enum name="GL_COLOR_BUFFER_BIT"/>
@@ -329,7 +388,11 @@
             <enum name="GL_CONTEXT_FLAG_DEBUG_BIT"/>
             <enum name="GL_CONTEXT_FLAG_DEBUG_BIT_KHR"/>
             <enum name="GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT"/>
+            <enum name="GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT"/>
             <enum name="GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB"/>
+            <enum name="GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT"/>
+            <enum name="GL_CONTEXT_FLAG_NO_ERROR_BIT"/>
+            <enum name="GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR"/>
         </group>
 
         <group name="ContextProfileMask">
@@ -395,6 +458,12 @@
             <enum name="GL_RIGHT"/>
         </group>
 
+        <group name="DrawElementsType">
+            <enum name="GL_UNSIGNED_BYTE"/>
+            <enum name="GL_UNSIGNED_SHORT"/>
+            <enum name="GL_UNSIGNED_INT"/>
+        </group>
+
         <group name="EnableCap">
             <enum name="GL_ALPHA_TEST"/>
             <enum name="GL_ASYNC_DRAW_PIXELS_SGIX"/>
@@ -520,6 +589,17 @@
             <enum name="GL_TEXTURE_TOO_LARGE_EXT"/>
         </group>
 
+        <group name="ExternalHandleType">
+            <enum name="GL_HANDLE_TYPE_OPAQUE_FD_EXT"/>
+            <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_EXT"/>
+            <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT"/>
+            <enum name="GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT"/>
+            <enum name="GL_HANDLE_TYPE_D3D12_RESOURCE_EXT"/>
+            <enum name="GL_HANDLE_TYPE_D3D11_IMAGE_EXT"/>
+            <enum name="GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT"/>
+            <enum name="GL_HANDLE_TYPE_D3D12_FENCE_EXT"/>
+        </group>
+
         <group name="FeedbackType">
             <enum name="GL_2D"/>
             <enum name="GL_3D"/>
@@ -585,6 +665,10 @@
             <enum name="GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX"/>
         </group>
 
+        <group name="FramebufferFetchNoncoherent">
+            <enum name="GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM"/>
+        </group>
+
         <group name="FrontFaceDirection">
             <enum name="GL_CCW"/>
             <enum name="GL_CW"/>
@@ -601,6 +685,16 @@
             <enum name="GL_COLOR_TABLE_RED_SIZE_SGI"/>
             <enum name="GL_COLOR_TABLE_SCALE_SGI"/>
             <enum name="GL_COLOR_TABLE_WIDTH_SGI"/>
+            <enum name="GL_COLOR_TABLE_BIAS"/>
+            <enum name="GL_COLOR_TABLE_SCALE"/>
+            <enum name="GL_COLOR_TABLE_FORMAT"/>
+            <enum name="GL_COLOR_TABLE_WIDTH"/>
+            <enum name="GL_COLOR_TABLE_RED_SIZE"/>
+            <enum name="GL_COLOR_TABLE_GREEN_SIZE"/>
+            <enum name="GL_COLOR_TABLE_BLUE_SIZE"/>
+            <enum name="GL_COLOR_TABLE_ALPHA_SIZE"/>
+            <enum name="GL_COLOR_TABLE_LUMINANCE_SIZE"/>
+            <enum name="GL_COLOR_TABLE_INTENSITY_SIZE"/>
         </group>
 
         <group name="GetConvolutionParameter">
@@ -612,6 +706,15 @@
             <enum name="GL_CONVOLUTION_WIDTH_EXT"/>
             <enum name="GL_MAX_CONVOLUTION_HEIGHT_EXT"/>
             <enum name="GL_MAX_CONVOLUTION_WIDTH_EXT"/>
+            <enum name="GL_CONVOLUTION_BORDER_MODE"/>
+            <enum name="GL_CONVOLUTION_BORDER_COLOR"/>
+            <enum name="GL_CONVOLUTION_FILTER_SCALE"/>
+            <enum name="GL_CONVOLUTION_FILTER_BIAS"/>
+            <enum name="GL_CONVOLUTION_FORMAT"/>
+            <enum name="GL_CONVOLUTION_WIDTH"/>
+            <enum name="GL_CONVOLUTION_HEIGHT"/>
+            <enum name="GL_MAX_CONVOLUTION_WIDTH"/>
+            <enum name="GL_MAX_CONVOLUTION_HEIGHT"/>
         </group>
 
         <group name="GetHistogramParameterPNameEXT">
@@ -623,6 +726,22 @@
             <enum name="GL_HISTOGRAM_RED_SIZE_EXT"/>
             <enum name="GL_HISTOGRAM_SINK_EXT"/>
             <enum name="GL_HISTOGRAM_WIDTH_EXT"/>
+            <enum name="GL_HISTOGRAM_WIDTH"/>
+            <enum name="GL_HISTOGRAM_FORMAT"/>
+            <enum name="GL_HISTOGRAM_RED_SIZE"/>
+            <enum name="GL_HISTOGRAM_GREEN_SIZE"/>
+            <enum name="GL_HISTOGRAM_BLUE_SIZE"/>
+            <enum name="GL_HISTOGRAM_ALPHA_SIZE"/>
+            <enum name="GL_HISTOGRAM_LUMINANCE_SIZE"/>
+            <enum name="GL_HISTOGRAM_SINK"/>
+            <enum name="GL_HISTOGRAM_ALPHA_SIZE_EXT"/>
+            <enum name="GL_HISTOGRAM_BLUE_SIZE_EXT"/>
+            <enum name="GL_HISTOGRAM_FORMAT_EXT"/>
+            <enum name="GL_HISTOGRAM_GREEN_SIZE_EXT"/>
+            <enum name="GL_HISTOGRAM_LUMINANCE_SIZE_EXT"/>
+            <enum name="GL_HISTOGRAM_RED_SIZE_EXT"/>
+            <enum name="GL_HISTOGRAM_SINK_EXT"/>
+            <enum name="GL_HISTOGRAM_WIDTH_EXT"/>
         </group>
 
         <group name="GetMapQuery">
@@ -636,6 +755,8 @@
             <enum name="GL_MINMAX_FORMAT_EXT"/>
             <enum name="GL_MINMAX_SINK"/>
             <enum name="GL_MINMAX_SINK_EXT"/>
+            <enum name="GL_MINMAX_FORMAT"/>
+            <enum name="GL_MINMAX_SINK"/>
         </group>
 
         <group name="GetPixelMap">
@@ -731,11 +852,15 @@
             <enum name="GL_DEPTH_TEST"/>
             <enum name="GL_DEPTH_WRITEMASK"/>
             <enum name="GL_DETAIL_TEXTURE_2D_BINDING_SGIS"/>
+            <enum name="GL_DEVICE_LUID_EXT"/>
+            <enum name="GL_DEVICE_NODE_MASK_EXT"/>
+            <enum name="GL_DEVICE_UUID_EXT"/>
             <enum name="GL_DISTANCE_ATTENUATION_SGIS"/>
             <enum name="GL_DITHER"/>
             <enum name="GL_DOUBLEBUFFER"/>
             <enum name="GL_DRAW_BUFFER"/>
             <enum name="GL_DRAW_BUFFER_EXT"/>
+            <enum name="GL_DRIVER_UUID_EXT"/>
             <enum name="GL_EDGE_FLAG"/>
             <enum name="GL_EDGE_FLAG_ARRAY"/>
             <enum name="GL_EDGE_FLAG_ARRAY_COUNT_EXT"/>
@@ -875,6 +1000,7 @@
             <enum name="GL_NORMAL_ARRAY_COUNT_EXT"/>
             <enum name="GL_NORMAL_ARRAY_STRIDE"/>
             <enum name="GL_NORMAL_ARRAY_TYPE"/>
+            <enum name="GL_NUM_DEVICE_UUIDS_EXT"/>
             <enum name="GL_PACK_ALIGNMENT"/>
             <enum name="GL_PACK_CMYK_HINT_EXT"/>
             <enum name="GL_PACK_IMAGE_DEPTH_SGIS"/>
@@ -1057,6 +1183,8 @@
             <enum name="GL_TEXTURE_COORD_ARRAY_POINTER_EXT"/>
             <enum name="GL_VERTEX_ARRAY_POINTER"/>
             <enum name="GL_VERTEX_ARRAY_POINTER_EXT"/>
+            <enum name="GL_DEBUG_CALLBACK_FUNCTION"/>
+            <enum name="GL_DEBUG_CALLBACK_USER_PARAM"/>
         </group>
 
         <group name="GetTextureParameter">
@@ -1181,6 +1309,8 @@
             <enum name="GL_HISTOGRAM_EXT"/>
             <enum name="GL_PROXY_HISTOGRAM"/>
             <enum name="GL_PROXY_HISTOGRAM_EXT"/>
+            <enum name="GL_HISTOGRAM"/>
+            <enum name="GL_PROXY_HISTOGRAM"/>
         </group>
 
         <group name="IndexPointerType">
@@ -1307,8 +1437,11 @@
 
         <group name="MapBufferUsageMask">
             <enum name="GL_CLIENT_STORAGE_BIT"/>
+            <enum name="GL_CLIENT_STORAGE_BIT_EXT"/>
             <enum name="GL_DYNAMIC_STORAGE_BIT"/>
+            <enum name="GL_DYNAMIC_STORAGE_BIT_EXT"/>
             <enum name="GL_MAP_COHERENT_BIT"/>
+            <enum name="GL_MAP_COHERENT_BIT_EXT"/>
             <enum name="GL_MAP_FLUSH_EXPLICIT_BIT"/>
             <enum name="GL_MAP_FLUSH_EXPLICIT_BIT_EXT"/>
             <enum name="GL_MAP_INVALIDATE_BUFFER_BIT"/>
@@ -1316,12 +1449,16 @@
             <enum name="GL_MAP_INVALIDATE_RANGE_BIT"/>
             <enum name="GL_MAP_INVALIDATE_RANGE_BIT_EXT"/>
             <enum name="GL_MAP_PERSISTENT_BIT"/>
+            <enum name="GL_MAP_PERSISTENT_BIT_EXT"/>
             <enum name="GL_MAP_READ_BIT"/>
             <enum name="GL_MAP_READ_BIT_EXT"/>
             <enum name="GL_MAP_UNSYNCHRONIZED_BIT"/>
             <enum name="GL_MAP_UNSYNCHRONIZED_BIT_EXT"/>
             <enum name="GL_MAP_WRITE_BIT"/>
             <enum name="GL_MAP_WRITE_BIT_EXT"/>
+            <enum name="GL_SPARSE_STORAGE_BIT_ARB"/>
+            <enum name="GL_LGPU_SEPARATE_STORAGE_BIT_NVX"/>
+            <enum name="GL_PER_GPU_STORAGE_BIT_NV"/>
         </group>
 
         <group name="MapTarget">
@@ -1384,6 +1521,7 @@
             <enum name="GL_BUFFER_UPDATE_BARRIER_BIT"/>
             <enum name="GL_BUFFER_UPDATE_BARRIER_BIT_EXT"/>
             <enum name="GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT"/>
+            <enum name="GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT"/>
             <enum name="GL_COMMAND_BARRIER_BIT"/>
             <enum name="GL_COMMAND_BARRIER_BIT_EXT"/>
             <enum name="GL_ELEMENT_ARRAY_BARRIER_BIT"/>
@@ -1409,6 +1547,11 @@
             <enum name="GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT"/>
         </group>
 
+        <group name="MemoryObjectParameterName">
+            <enum name="GL_DEDICATED_MEMORY_OBJECT_EXT"/>
+            <enum name="GL_PROTECTED_MEMORY_OBJECT_EXT"/>
+        </group>
+
         <group name="MeshMode1">
             <enum name="GL_LINE"/>
             <enum name="GL_POINT"/>
@@ -1465,15 +1608,13 @@
         </group>
 
         <group name="InternalFormat" comment="Was PixelInternalFormat">
+            <!-- Compatibility -->
             <enum name="GL_ALPHA12"/>
             <enum name="GL_ALPHA16"/>
-            <enum name="GL_ALPHA16_ICC_SGIX"/>
+            <!-- <enum name="GL_ALPHA16_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_ALPHA4"/>
             <enum name="GL_ALPHA8"/>
-            <enum name="GL_ALPHA_ICC_SGIX"/>
-            <enum name="GL_DEPTH_COMPONENT16_SGIX"/>
-            <enum name="GL_DEPTH_COMPONENT24_SGIX"/>
-            <enum name="GL_DEPTH_COMPONENT32_SGIX"/>
+            <!-- <enum name="GL_ALPHA_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_DUAL_ALPHA12_SGIS"/>
             <enum name="GL_DUAL_ALPHA16_SGIS"/>
             <enum name="GL_DUAL_ALPHA4_SGIS"/>
@@ -1491,49 +1632,212 @@
             <enum name="GL_INTENSITY"/>
             <enum name="GL_INTENSITY12"/>
             <enum name="GL_INTENSITY16"/>
-            <enum name="GL_INTENSITY16_ICC_SGIX"/>
+            <!-- <enum name="GL_INTENSITY16_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_INTENSITY4"/>
             <enum name="GL_INTENSITY8"/>
-            <enum name="GL_INTENSITY_ICC_SGIX"/>
+            <!-- <enum name="GL_INTENSITY_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_LUMINANCE12"/>
             <enum name="GL_LUMINANCE12_ALPHA12"/>
             <enum name="GL_LUMINANCE12_ALPHA4"/>
             <enum name="GL_LUMINANCE16"/>
             <enum name="GL_LUMINANCE16_ALPHA16"/>
-            <enum name="GL_LUMINANCE16_ALPHA8_ICC_SGIX"/>
-            <enum name="GL_LUMINANCE16_ICC_SGIX"/>
+            <!-- <enum name="GL_LUMINANCE16_ALPHA8_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- <enum name="GL_LUMINANCE16_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_LUMINANCE4"/>
             <enum name="GL_LUMINANCE4_ALPHA4"/>
             <enum name="GL_LUMINANCE6_ALPHA2"/>
             <enum name="GL_LUMINANCE8"/>
             <enum name="GL_LUMINANCE8_ALPHA8"/>
-            <enum name="GL_LUMINANCE_ALPHA_ICC_SGIX"/>
-            <enum name="GL_LUMINANCE_ICC_SGIX"/>
+            <!-- <enum name="GL_LUMINANCE_ALPHA_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- <enum name="GL_LUMINANCE_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
             <enum name="GL_QUAD_ALPHA4_SGIS"/>
             <enum name="GL_QUAD_ALPHA8_SGIS"/>
             <enum name="GL_QUAD_INTENSITY4_SGIS"/>
             <enum name="GL_QUAD_INTENSITY8_SGIS"/>
             <enum name="GL_QUAD_LUMINANCE4_SGIS"/>
             <enum name="GL_QUAD_LUMINANCE8_SGIS"/>
-            <enum name="GL_R3_G3_B2"/>
-            <enum name="GL_R5_G6_B5_A8_ICC_SGIX"/>
-            <enum name="GL_R5_G6_B5_ICC_SGIX"/>
-            <enum name="GL_RGB10"/>
-            <enum name="GL_RGB10_A2"/>
-            <enum name="GL_RGB12"/>
-            <enum name="GL_RGB16"/>
+            <!-- <enum name="GL_R5_G6_B5_A8_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- <enum name="GL_R5_G6_B5_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- <enum name="GL_RGBA_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- <enum name="GL_RGB_ICC_SGIX" comment="Incomplete extension SGIX_icc_texture"/> -->
+            <!-- Base internal format: GL_RED -->
+            <enum name="GL_RED"/>
+            <enum name="GL_RED_EXT"/>
+            <enum name="GL_R8"/>
+            <enum name="GL_R8_EXT"/>
+            <enum name="GL_R8_SNORM"/>
+            <enum name="GL_R16"/>
+            <enum name="GL_R16_EXT"/>
+            <enum name="GL_R16_SNORM"/>
+            <enum name="GL_R16_SNORM_EXT"/>
+            <!-- <enum name="GL_R32" comment="cut & paste error?"/> -->
+            <!-- <enum name="GL_R32_EXT" comment="cut & paste error?"/> -->
+            <enum name="GL_R16F"/>
+            <enum name="GL_R16F_EXT"/>
+            <enum name="GL_R32F"/>
+            <enum name="GL_R32F_EXT"/>
+            <enum name="GL_R8I"/>
+            <enum name="GL_R16I"/>
+            <enum name="GL_R32I"/>
+            <enum name="GL_R8UI"/>
+            <enum name="GL_R16UI"/>
+            <enum name="GL_R32UI"/>
+            <!-- Base internal format: GL_RG -->
+            <enum name="GL_RG"/>
+            <enum name="GL_RG8"/>
+            <enum name="GL_RG8_EXT"/>
+            <enum name="GL_RG8_SNORM"/>
+            <enum name="GL_RG16"/>
+            <enum name="GL_RG16_EXT"/>
+            <enum name="GL_RG16_SNORM"/>
+            <enum name="GL_RG16_SNORM_EXT"/>
+            <enum name="GL_RG16F"/>
+            <enum name="GL_RG16F_EXT"/>
+            <enum name="GL_RG32F"/>
+            <enum name="GL_RG32F_EXT"/>
+            <enum name="GL_RG8I"/>
+            <enum name="GL_RG16I"/>
+            <enum name="GL_RG32I"/>
+            <enum name="GL_RG8UI"/>
+            <enum name="GL_RG16UI"/>
+            <enum name="GL_RG32UI"/>
+            <!-- Base internal format: GL_RGB -->
+            <enum name="GL_RGB"/>
+            <!-- <enum name="GL_RGB2" comment="Never actually added to core"/> -->
             <enum name="GL_RGB2_EXT"/>
             <enum name="GL_RGB4"/>
+            <enum name="GL_RGB4_EXT"/>
             <enum name="GL_RGB5"/>
-            <enum name="GL_RGB5_A1"/>
+            <enum name="GL_RGB5_EXT"/>
             <enum name="GL_RGB8"/>
-            <enum name="GL_RGBA12"/>
-            <enum name="GL_RGBA16"/>
-            <enum name="GL_RGBA2"/>
+            <enum name="GL_RGB8_EXT"/>
+            <enum name="GL_RGB8_OES"/>
+            <enum name="GL_RGB8_SNORM"/>
+            <enum name="GL_RGB10"/>
+            <enum name="GL_RGB10_EXT"/>
+            <enum name="GL_RGB12"/>
+            <enum name="GL_RGB12_EXT"/>
+            <enum name="GL_RGB16"/>
+            <enum name="GL_RGB16_EXT"/>
+            <enum name="GL_RGB16F"/>
+            <enum name="GL_RGB16F_ARB"/>
+            <enum name="GL_RGB16F_EXT"/>
+            <enum name="GL_RGB16_SNORM"/>
+            <enum name="GL_RGB16_SNORM_EXT"/>
+            <enum name="GL_RGB8I"/>
+            <enum name="GL_RGB16I"/>
+            <enum name="GL_RGB32I"/>
+            <enum name="GL_RGB8UI"/>
+            <enum name="GL_RGB16UI"/>
+            <enum name="GL_RGB32UI"/>
+            <enum name="GL_SRGB"/>
+            <enum name="GL_SRGB_EXT"/>
+            <enum name="GL_SRGB_ALPHA"/>
+            <enum name="GL_SRGB_ALPHA_EXT"/>
+            <enum name="GL_SRGB8"/>
+            <enum name="GL_SRGB8_EXT"/>
+            <enum name="GL_SRGB8_NV"/>
+            <enum name="GL_SRGB8_ALPHA8"/>
+            <enum name="GL_SRGB8_ALPHA8_EXT"/>
+            <enum name="GL_R3_G3_B2"/>
+            <enum name="GL_R11F_G11F_B10F"/>
+            <enum name="GL_R11F_G11F_B10F_APPLE"/>
+            <enum name="GL_R11F_G11F_B10F_EXT"/>
+            <enum name="GL_RGB9_E5"/>
+            <enum name="GL_RGB9_E5_APPLE"/>
+            <enum name="GL_RGB9_E5_EXT"/>
+            <!-- Base internal format: GL_RGBA -->
+            <enum name="GL_RGBA"/>
             <enum name="GL_RGBA4"/>
+            <enum name="GL_RGBA4_EXT"/>
+            <enum name="GL_RGBA4_OES"/>
+            <enum name="GL_RGB5_A1"/>
+            <enum name="GL_RGB5_A1_EXT"/>
+            <enum name="GL_RGB5_A1_OES"/>
             <enum name="GL_RGBA8"/>
-            <enum name="GL_RGBA_ICC_SGIX"/>
-            <enum name="GL_RGB_ICC_SGIX"/>
+            <enum name="GL_RGBA8_EXT"/>
+            <enum name="GL_RGBA8_OES"/>
+            <enum name="GL_RGBA8_SNORM"/>
+            <enum name="GL_RGB10_A2"/>
+            <enum name="GL_RGB10_A2_EXT"/>
+            <enum name="GL_RGBA12"/>
+            <enum name="GL_RGBA12_EXT"/>
+            <enum name="GL_RGBA16"/>
+            <enum name="GL_RGBA16_EXT"/>
+            <enum name="GL_RGBA16F"/>
+            <enum name="GL_RGBA16F_ARB"/>
+            <enum name="GL_RGBA16F_EXT"/>
+            <enum name="GL_RGBA32F"/>
+            <enum name="GL_RGBA32F_ARB"/>
+            <enum name="GL_RGBA32F_EXT"/>
+            <enum name="GL_RGBA8I"/>
+            <enum name="GL_RGBA16I"/>
+            <enum name="GL_RGBA32I"/>
+            <enum name="GL_RGBA8UI"/>
+            <enum name="GL_RGBA16UI"/>
+            <enum name="GL_RGBA32UI"/>
+            <enum name="GL_RGB10_A2UI"/>
+            <!-- Base internal format: GL_DEPTH_COMPONENT -->
+            <enum name="GL_DEPTH_COMPONENT"/>
+            <enum name="GL_DEPTH_COMPONENT16"/>
+            <enum name="GL_DEPTH_COMPONENT16_ARB"/>
+            <enum name="GL_DEPTH_COMPONENT16_OES"/>
+            <enum name="GL_DEPTH_COMPONENT16_SGIX"/>
+            <enum name="GL_DEPTH_COMPONENT24_ARB"/>
+            <enum name="GL_DEPTH_COMPONENT24_OES"/>
+            <enum name="GL_DEPTH_COMPONENT24_SGIX"/>
+            <enum name="GL_DEPTH_COMPONENT32_ARB"/>
+            <enum name="GL_DEPTH_COMPONENT32_OES"/>
+            <enum name="GL_DEPTH_COMPONENT32_SGIX"/>
+            <enum name="GL_DEPTH_COMPONENT32F"/>
+            <enum name="GL_DEPTH_COMPONENT32F_NV"/>
+            <enum name="GL_DEPTH_COMPONENT32F_NV"/>
+            <!-- Base internal format: GL_DEPTH_STENCIL -->
+            <enum name="GL_DEPTH_STENCIL"/>
+            <enum name="GL_DEPTH_STENCIL_EXT"/>
+            <enum name="GL_DEPTH_STENCIL_MESA"/>
+            <enum name="GL_DEPTH_STENCIL_NV"/>
+            <enum name="GL_DEPTH_STENCIL_OES"/>
+            <enum name="GL_DEPTH24_STENCIL8"/>
+            <enum name="GL_DEPTH24_STENCIL8_EXT"/>
+            <enum name="GL_DEPTH24_STENCIL8_OES"/>
+            <enum name="GL_DEPTH32F_STENCIL8"/>
+            <enum name="GL_DEPTH32F_STENCIL8_NV"/>
+            <!-- Compressed base internal formats -->
+            <enum name="GL_COMPRESSED_RED"/>
+            <enum name="GL_COMPRESSED_RG"/>
+            <enum name="GL_COMPRESSED_RGB"/>
+            <enum name="GL_COMPRESSED_RGBA"/>
+            <enum name="GL_COMPRESSED_SRGB"/>
+            <enum name="GL_COMPRESSED_SRGB_ALPHA"/>
+            <enum name="GL_COMPRESSED_RED_RGTC1"/>
+            <enum name="GL_COMPRESSED_RED_RGTC1_EXT"/>
+            <enum name="GL_COMPRESSED_SIGNED_RED_RGTC1"/>
+            <enum name="GL_COMPRESSED_SIGNED_RED_RGTC1_EXT"/>
+            <enum name="GL_COMPRESSED_R11_EAC"/>
+            <enum name="GL_COMPRESSED_SIGNED_R11_EAC"/>
+            <enum name="GL_COMPRESSED_RG_RGTC2"/>
+            <enum name="GL_COMPRESSED_SIGNED_RG_RGTC2"/>
+            <enum name="GL_COMPRESSED_RGBA_BPTC_UNORM"/>
+            <enum name="GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM"/>
+            <enum name="GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT"/>
+            <enum name="GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT"/>
+            <enum name="GL_COMPRESSED_RGB8_ETC2"/>
+            <enum name="GL_COMPRESSED_SRGB8_ETC2"/>
+            <enum name="GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"/>
+            <enum name="GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"/>
+            <enum name="GL_COMPRESSED_RGBA8_ETC2_EAC"/>
+            <enum name="GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"/>
+            <enum name="GL_COMPRESSED_RG11_EAC"/>
+            <enum name="GL_COMPRESSED_SIGNED_RG11_EAC"/>
+            <enum name="GL_COMPRESSED_RGB_S3TC_DXT1_EXT"/>
+            <enum name="GL_COMPRESSED_SRGB_S3TC_DXT1_EXT"/>
+            <enum name="GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"/>
+            <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT"/>
+            <enum name="GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"/>
+            <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT"/>
+            <enum name="GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"/>
+            <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT"/>
         </group>
 
         <group name="PixelMap">
@@ -1789,6 +2093,10 @@
             <enum name="GL_4PASS_3_SGIS"/>
         </group>
 
+        <group name="SemaphoreParameterName">
+            <enum name="GL_D3D12_FENCE_VALUE_EXT"/>
+        </group>
+
         <group name="SeparableTargetEXT">
             <enum name="GL_SEPARABLE_2D"/>
             <enum name="GL_SEPARABLE_2D_EXT"/>
@@ -1799,6 +2107,12 @@
             <enum name="GL_SMOOTH"/>
         </group>
 
+        <group name="StencilFaceDirection">
+             <enum name="GL_FRONT"/>
+             <enum name="GL_BACK"/>
+             <enum name="GL_FRONT_AND_BACK"/>
+        </group>
+
         <group name="StencilFunction">
             <enum name="GL_ALWAYS"/>
             <enum name="GL_EQUAL"/>
@@ -1824,6 +2138,12 @@
             <enum name="GL_RENDERER"/>
             <enum name="GL_VENDOR"/>
             <enum name="GL_VERSION"/>
+            <enum name="GL_SHADING_LANGUAGE_VERSION"/>
+        </group>
+
+        <group name="SyncObjectMask">
+            <enum name="GL_SYNC_FLUSH_COMMANDS_BIT"/>
+            <enum name="GL_SYNC_FLUSH_COMMANDS_BIT_APPLE"/>
         </group>
 
         <group name="TexCoordPointerType">
@@ -1948,31 +2268,96 @@
             <enum name="GL_TEXTURE_WRAP_R_OES"/>
             <enum name="GL_TEXTURE_WRAP_S"/>
             <enum name="GL_TEXTURE_WRAP_T"/>
+            <enum name="GL_TEXTURE_BASE_LEVEL"/>
+            <enum name="GL_TEXTURE_COMPARE_MODE"/>
+            <enum name="GL_TEXTURE_COMPARE_FUNC"/>
+            <enum name="GL_TEXTURE_LOD_BIAS"/>
+            <enum name="GL_TEXTURE_MIN_LOD"/>
+            <enum name="GL_TEXTURE_MAX_LOD"/>
+            <enum name="GL_TEXTURE_MAX_LEVEL"/>
+            <enum name="GL_TEXTURE_SWIZZLE_R"/>
+            <enum name="GL_TEXTURE_SWIZZLE_G"/>
+            <enum name="GL_TEXTURE_SWIZZLE_B"/>
+            <enum name="GL_TEXTURE_SWIZZLE_A"/>
+            <enum name="GL_TEXTURE_SWIZZLE_RGBA"/>
+            <enum name="GL_TEXTURE_TILING_EXT"/>
+            <enum name="GL_DEPTH_STENCIL_TEXTURE_MODE"/>
+            <enum name="GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS"/>
+            <enum name="GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS"/>
+            <enum name="GL_TEXTURE_4DSIZE_SGIS"/>
+            <enum name="GL_TEXTURE_ALPHA_SIZE"/>
+            <enum name="GL_TEXTURE_BASE_LEVEL_SGIS"/>
+            <enum name="GL_TEXTURE_BLUE_SIZE"/>
+            <enum name="GL_TEXTURE_BORDER"/>
+            <enum name="GL_TEXTURE_BORDER_COLOR_NV"/>
+            <enum name="GL_TEXTURE_COMPARE_OPERATOR_SGIX"/>
+            <enum name="GL_TEXTURE_COMPONENTS"/>
+            <enum name="GL_TEXTURE_DEPTH_EXT"/>
+            <enum name="GL_TEXTURE_FILTER4_SIZE_SGIS"/>
+            <enum name="GL_TEXTURE_GEQUAL_R_SGIX"/>
+            <enum name="GL_TEXTURE_GREEN_SIZE"/>
+            <enum name="GL_TEXTURE_HEIGHT"/>
+            <enum name="GL_TEXTURE_INTENSITY_SIZE"/>
+            <enum name="GL_TEXTURE_INTERNAL_FORMAT"/>
+            <enum name="GL_TEXTURE_LEQUAL_R_SGIX"/>
+            <enum name="GL_TEXTURE_LUMINANCE_SIZE"/>
+            <enum name="GL_TEXTURE_MAX_LEVEL_SGIS"/>
+            <enum name="GL_TEXTURE_MAX_LOD_SGIS"/>
+            <enum name="GL_TEXTURE_MIN_LOD_SGIS"/>
+            <enum name="GL_TEXTURE_RED_SIZE"/>
+            <enum name="GL_TEXTURE_RESIDENT"/>
+            <enum name="GL_TEXTURE_WIDTH"/>
+        </group>
+
+        <group name="TextureStorageMaskAMD">
+            <enum name="GL_TEXTURE_STORAGE_SPARSE_BIT_AMD"/>
         </group>
 
         <group name="TextureTarget">
             <enum name="GL_DETAIL_TEXTURE_2D_SGIS"/>
             <enum name="GL_PROXY_TEXTURE_1D"/>
+            <enum name="GL_PROXY_TEXTURE_1D_ARRAY"/>
+            <enum name="GL_PROXY_TEXTURE_1D_ARRAY_EXT"/>
             <enum name="GL_PROXY_TEXTURE_1D_EXT"/>
             <enum name="GL_PROXY_TEXTURE_2D"/>
+            <enum name="GL_PROXY_TEXTURE_2D_ARRAY"/>
+            <enum name="GL_PROXY_TEXTURE_2D_ARRAY_EXT"/>
             <enum name="GL_PROXY_TEXTURE_2D_EXT"/>
+            <enum name="GL_PROXY_TEXTURE_2D_MULTISAMPLE"/>
+            <enum name="GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY"/>
             <enum name="GL_PROXY_TEXTURE_3D"/>
             <enum name="GL_PROXY_TEXTURE_3D_EXT"/>
             <enum name="GL_PROXY_TEXTURE_4D_SGIS"/>
+            <enum name="GL_PROXY_TEXTURE_CUBE_MAP"/>
+            <enum name="GL_PROXY_TEXTURE_CUBE_MAP_ARB"/>
+            <enum name="GL_PROXY_TEXTURE_CUBE_MAP_EXT"/>
+            <enum name="GL_PROXY_TEXTURE_CUBE_MAP_ARRAY"/>
+            <enum name="GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB"/>
+            <enum name="GL_PROXY_TEXTURE_RECTANGLE"/>
+            <enum name="GL_PROXY_TEXTURE_RECTANGLE_ARB"/>
+            <enum name="GL_PROXY_TEXTURE_RECTANGLE_NV"/>
             <enum name="GL_TEXTURE_1D"/>
             <enum name="GL_TEXTURE_2D"/>
             <enum name="GL_TEXTURE_3D"/>
             <enum name="GL_TEXTURE_3D_EXT"/>
             <enum name="GL_TEXTURE_3D_OES"/>
             <enum name="GL_TEXTURE_4D_SGIS"/>
-            <enum name="GL_TEXTURE_BASE_LEVEL"/>
-            <enum name="GL_TEXTURE_BASE_LEVEL_SGIS"/>
-            <enum name="GL_TEXTURE_MAX_LEVEL"/>
-            <enum name="GL_TEXTURE_MAX_LEVEL_SGIS"/>
-            <enum name="GL_TEXTURE_MAX_LOD"/>
-            <enum name="GL_TEXTURE_MAX_LOD_SGIS"/>
-            <enum name="GL_TEXTURE_MIN_LOD"/>
-            <enum name="GL_TEXTURE_MIN_LOD_SGIS"/>
+            <enum name="GL_TEXTURE_RECTANGLE"/>
+            <enum name="GL_TEXTURE_CUBE_MAP"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_POSITIVE_X"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_NEGATIVE_X"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_POSITIVE_Y"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_NEGATIVE_Y"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_POSITIVE_Z"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_NEGATIVE_Z"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_ARRAY"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_ARRAY_ARB"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_ARRAY_EXT"/>
+            <enum name="GL_TEXTURE_CUBE_MAP_ARRAY_OES"/>
+            <enum name="GL_TEXTURE_1D_ARRAY"/>
+            <enum name="GL_TEXTURE_2D_ARRAY"/>
+            <enum name="GL_TEXTURE_2D_MULTISAMPLE"/>
+            <enum name="GL_TEXTURE_2D_MULTISAMPLE_ARRAY"/>
         </group>
 
         <group name="TextureWrapMode">
@@ -1993,10 +2378,13 @@
             <enum name="GL_FRAGMENT_SHADER_BIT_EXT"/>
             <enum name="GL_GEOMETRY_SHADER_BIT"/>
             <enum name="GL_GEOMETRY_SHADER_BIT_EXT"/>
+            <enum name="GL_GEOMETRY_SHADER_BIT_OES"/>
             <enum name="GL_TESS_CONTROL_SHADER_BIT"/>
             <enum name="GL_TESS_CONTROL_SHADER_BIT_EXT"/>
+            <enum name="GL_TESS_CONTROL_SHADER_BIT_OES"/>
             <enum name="GL_TESS_EVALUATION_SHADER_BIT"/>
             <enum name="GL_TESS_EVALUATION_SHADER_BIT_EXT"/>
+            <enum name="GL_TESS_EVALUATION_SHADER_BIT_OES"/>
             <enum name="GL_COMPUTE_SHADER_BIT"/>
             <enum name="GL_ALL_SHADER_BITS"/>
             <enum name="GL_ALL_SHADER_BITS_EXT"/>
@@ -2008,6 +2396,994 @@
             <enum name="GL_INT"/>
             <enum name="GL_SHORT"/>
         </group>
+
+        <group name="FramebufferAttachment">
+            <enum name="GL_MAX_COLOR_ATTACHMENTS"/>
+            <enum name="GL_MAX_COLOR_ATTACHMENTS_EXT"/>
+            <enum name="GL_MAX_COLOR_ATTACHMENTS_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT0"/>
+            <enum name="GL_COLOR_ATTACHMENT0_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT0_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT0_OES"/>
+            <enum name="GL_COLOR_ATTACHMENT1"/>
+            <enum name="GL_COLOR_ATTACHMENT1_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT1_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT2"/>
+            <enum name="GL_COLOR_ATTACHMENT2_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT2_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT3"/>
+            <enum name="GL_COLOR_ATTACHMENT3_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT3_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT4"/>
+            <enum name="GL_COLOR_ATTACHMENT4_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT4_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT5"/>
+            <enum name="GL_COLOR_ATTACHMENT5_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT5_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT6"/>
+            <enum name="GL_COLOR_ATTACHMENT6_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT6_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT7"/>
+            <enum name="GL_COLOR_ATTACHMENT7_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT7_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT8"/>
+            <enum name="GL_COLOR_ATTACHMENT8_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT8_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT9"/>
+            <enum name="GL_COLOR_ATTACHMENT9_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT9_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT10"/>
+            <enum name="GL_COLOR_ATTACHMENT10_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT10_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT11"/>
+            <enum name="GL_COLOR_ATTACHMENT11_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT11_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT12"/>
+            <enum name="GL_COLOR_ATTACHMENT12_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT12_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT13"/>
+            <enum name="GL_COLOR_ATTACHMENT13_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT13_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT14"/>
+            <enum name="GL_COLOR_ATTACHMENT14_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT14_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT15"/>
+            <enum name="GL_COLOR_ATTACHMENT15_EXT"/>
+            <enum name="GL_COLOR_ATTACHMENT15_NV"/>
+            <enum name="GL_COLOR_ATTACHMENT16"/>
+            <enum name="GL_COLOR_ATTACHMENT17"/>
+            <enum name="GL_COLOR_ATTACHMENT18"/>
+            <enum name="GL_COLOR_ATTACHMENT19"/>
+            <enum name="GL_COLOR_ATTACHMENT20"/>
+            <enum name="GL_COLOR_ATTACHMENT21"/>
+            <enum name="GL_COLOR_ATTACHMENT22"/>
+            <enum name="GL_COLOR_ATTACHMENT23"/>
+            <enum name="GL_COLOR_ATTACHMENT24"/>
+            <enum name="GL_COLOR_ATTACHMENT25"/>
+            <enum name="GL_COLOR_ATTACHMENT26"/>
+            <enum name="GL_COLOR_ATTACHMENT27"/>
+            <enum name="GL_COLOR_ATTACHMENT28"/>
+            <enum name="GL_COLOR_ATTACHMENT29"/>
+            <enum name="GL_COLOR_ATTACHMENT30"/>
+            <enum name="GL_COLOR_ATTACHMENT31"/>
+            <enum name="GL_DEPTH_ATTACHMENT"/>
+            <enum name="GL_DEPTH_ATTACHMENT_EXT"/>
+            <enum name="GL_DEPTH_ATTACHMENT_OES"/>
+        </group>
+
+        <group name="RenderbufferTarget">
+            <enum name="GL_RENDERBUFFER" />
+        </group>
+
+        <group name="FramebufferTarget">
+            <enum name="GL_FRAMEBUFFER" />
+            <enum name="GL_DRAW_FRAMEBUFFER" />
+            <enum name="GL_READ_FRAMEBUFFER" />
+        </group>
+
+        <group name="TextureUnit">
+            <enum name="GL_TEXTURE0"/>
+            <enum name="GL_TEXTURE1"/>
+            <enum name="GL_TEXTURE2"/>
+            <enum name="GL_TEXTURE3"/>
+            <enum name="GL_TEXTURE4"/>
+            <enum name="GL_TEXTURE5"/>
+            <enum name="GL_TEXTURE6"/>
+            <enum name="GL_TEXTURE7"/>
+            <enum name="GL_TEXTURE8"/>
+            <enum name="GL_TEXTURE9"/>
+            <enum name="GL_TEXTURE10"/>
+            <enum name="GL_TEXTURE11"/>
+            <enum name="GL_TEXTURE12"/>
+            <enum name="GL_TEXTURE13"/>
+            <enum name="GL_TEXTURE14"/>
+            <enum name="GL_TEXTURE15"/>
+            <enum name="GL_TEXTURE16"/>
+            <enum name="GL_TEXTURE17"/>
+            <enum name="GL_TEXTURE18"/>
+            <enum name="GL_TEXTURE19"/>
+            <enum name="GL_TEXTURE20"/>
+            <enum name="GL_TEXTURE21"/>
+            <enum name="GL_TEXTURE22"/>
+            <enum name="GL_TEXTURE23"/>
+            <enum name="GL_TEXTURE24"/>
+            <enum name="GL_TEXTURE25"/>
+            <enum name="GL_TEXTURE26"/>
+            <enum name="GL_TEXTURE27"/>
+            <enum name="GL_TEXTURE28"/>
+            <enum name="GL_TEXTURE29"/>
+            <enum name="GL_TEXTURE30"/>
+            <enum name="GL_TEXTURE31"/>
+        </group>
+
+        <group name="TypeEnum">
+            <enum name="GL_QUERY_WAIT"/>
+            <enum name="GL_QUERY_NO_WAIT"/>
+            <enum name="GL_QUERY_BY_REGION_WAIT"/>
+            <enum name="GL_QUERY_BY_REGION_NO_WAIT"/>
+        </group>
+
+        <group name="FragmentOpATI">
+            <enum name="GL_MOV_ATI"/>
+            <enum name="GL_ADD_ATI"/>
+            <enum name="GL_MUL_ATI"/>
+            <enum name="GL_SUB_ATI"/>
+            <enum name="GL_DOT3_ATI"/>
+            <enum name="GL_DOT4_ATI"/>
+            <enum name="GL_MAD_ATI"/>
+            <enum name="GL_LERP_ATI"/>
+            <enum name="GL_CND_ATI"/>
+            <enum name="GL_CND0_ATI"/>
+            <enum name="GL_DOT2_ADD_ATI"/>
+        </group>
+
+        <group name="FramebufferStatus">
+            <enum name="GL_FRAMEBUFFER_COMPLETE"/>
+            <enum name="GL_FRAMEBUFFER_UNDEFINED"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"/>
+            <enum name="GL_FRAMEBUFFER_UNSUPPORTED"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"/>
+        </group>
+
+        <group name="GraphicsResetStatus">
+            <enum name="GL_NO_ERROR"/>
+            <enum name="GL_GUILTY_CONTEXT_RESET"/>
+            <enum name="GL_INNOCENT_CONTEXT_RESET"/>
+            <enum name="GL_UNKNOWN_CONTEXT_RESET"/>
+        </group>
+
+        <group name="SyncStatus">
+            <enum name="GL_ALREADY_SIGNALED"/>
+            <enum name="GL_TIMEOUT_EXPIRED"/>
+            <enum name="GL_CONDITION_SATISFIED"/>
+            <enum name="GL_WAIT_FAILED"/>
+        </group>
+
+        <group name="QueryTarget">
+            <enum name="GL_SAMPLES_PASSED"/>
+            <enum name="GL_ANY_SAMPLES_PASSED"/>
+            <enum name="GL_ANY_SAMPLES_PASSED_CONSERVATIVE"/>
+            <enum name="GL_PRIMITIVES_GENERATED"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN"/>
+            <enum name="GL_TIME_ELAPSED"/>
+        </group>
+
+        <group name="ConvolutionTarget">
+            <enum name="GL_CONVOLUTION_1D"/>
+            <enum name="GL_CONVOLUTION_2D"/>
+        </group>
+
+        <group name="PathFillMode">
+            <enum name="GL_INVERT"/>
+            <enum name="GL_COUNT_UP_NV"/>
+            <enum name="GL_COUNT_DOWN_NV"/>
+            <enum name="GL_PATH_FILL_MODE_NV"/>
+        </group>
+
+        <group name="ColorTableTarget">
+            <enum name="GL_COLOR_TABLE"/>
+            <enum name="GL_POST_CONVOLUTION_COLOR_TABLE"/>
+            <enum name="GL_POST_COLOR_MATRIX_COLOR_TABLE"/>
+        </group>
+
+        <group name="VertexBufferObjectParameter">
+            <enum name="GL_BUFFER_ACCESS"/>
+            <enum name="GL_BUFFER_ACCESS_FLAGS"/>
+            <enum name="GL_BUFFER_IMMUTABLE_STORAGE"/>
+            <enum name="GL_BUFFER_MAPPED"/>
+            <enum name="GL_BUFFER_MAP_LENGTH"/>
+            <enum name="GL_BUFFER_MAP_OFFSET"/>
+            <enum name="GL_BUFFER_SIZE"/>
+            <enum name="GL_BUFFER_STORAGE_FLAGS"/>
+            <enum name="GL_BUFFER_USAGE"/>
+        </group>
+
+        <group name="RenderbufferParameterName">
+            <enum name="GL_RENDERBUFFER_WIDTH"/>
+            <enum name="GL_RENDERBUFFER_HEIGHT"/>
+            <enum name="GL_RENDERBUFFER_INTERNAL_FORMAT"/>
+            <enum name="GL_RENDERBUFFER_SAMPLES"/>
+            <enum name="GL_RENDERBUFFER_RED_SIZE"/>
+            <enum name="GL_RENDERBUFFER_GREEN_SIZE"/>
+            <enum name="GL_RENDERBUFFER_BLUE_SIZE"/>
+            <enum name="GL_RENDERBUFFER_ALPHA_SIZE"/>
+            <enum name="GL_RENDERBUFFER_DEPTH_SIZE"/>
+            <enum name="GL_RENDERBUFFER_STENCIL_SIZE"/>
+        </group>
+
+        <group name="VertexBufferObjectUsage">
+            <enum name="GL_STREAM_DRAW"/>
+            <enum name="GL_STREAM_READ"/>
+            <enum name="GL_STREAM_COPY"/>
+            <enum name="GL_STATIC_DRAW"/>
+            <enum name="GL_STATIC_READ"/>
+            <enum name="GL_STATIC_COPY"/>
+            <enum name="GL_DYNAMIC_DRAW"/>
+            <enum name="GL_DYNAMIC_READ"/>
+            <enum name="GL_DYNAMIC_COPY"/>
+        </group>
+
+        <group name="FramebufferParameterName">
+            <enum name="GL_FRAMEBUFFER_DEFAULT_WIDTH"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_HEIGHT"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_LAYERS"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_SAMPLES"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS"/>
+        </group>
+
+        <group name="ProgramParameterPName">
+            <enum name="GL_PROGRAM_BINARY_RETRIEVABLE_HINT"/>
+            <enum name="GL_PROGRAM_SEPARABLE"/>
+        </group>
+
+        <group name="BlendingFactor">
+            <enum name="GL_ZERO"/>
+            <enum name="GL_ONE"/>
+            <enum name="GL_SRC_COLOR"/>
+            <enum name="GL_ONE_MINUS_SRC_COLOR"/>
+            <enum name="GL_DST_COLOR"/>
+            <enum name="GL_ONE_MINUS_DST_COLOR"/>
+            <enum name="GL_SRC_ALPHA"/>
+            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
+            <enum name="GL_DST_ALPHA"/>
+            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
+            <enum name="GL_CONSTANT_COLOR"/>
+            <enum name="GL_ONE_MINUS_CONSTANT_COLOR"/>
+            <enum name="GL_CONSTANT_ALPHA"/>
+            <enum name="GL_ONE_MINUS_CONSTANT_ALPHA"/>
+            <enum name="GL_SRC_ALPHA_SATURATE"/>
+            <enum name="GL_SRC1_COLOR"/>
+            <enum name="GL_ONE_MINUS_SRC1_COLOR"/>
+            <enum name="GL_SRC1_ALPHA"/>
+            <enum name="GL_ONE_MINUS_SRC1_ALPHA"/>
+        </group>
+
+        <group name="BindTransformFeedbackTarget">
+            <enum name="GL_TRANSFORM_FEEDBACK"/>
+        </group>
+
+        <group name="BlitFramebufferFilter">
+            <enum name="GL_NEAREST"/>
+            <enum name="GL_LINEAR"/>
+        </group>
+
+        <group name="BufferStorageTarget">
+            <enum name="GL_ARRAY_BUFFER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER"/>
+            <enum name="GL_COPY_READ_BUFFER"/>
+            <enum name="GL_COPY_WRITE_BUFFER"/>
+            <enum name="GL_DISPATCH_INDIRECT_BUFFER"/>
+            <enum name="GL_DRAW_INDIRECT_BUFFER"/>
+            <enum name="GL_ELEMENT_ARRAY_BUFFER"/>
+            <enum name="GL_PIXEL_PACK_BUFFER"/>
+            <enum name="GL_PIXEL_UNPACK_BUFFER"/>
+            <enum name="GL_QUERY_BUFFER"/>
+            <enum name="GL_SHADER_STORAGE_BUFFER"/>
+            <enum name="GL_TEXTURE_BUFFER"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER"/>
+            <enum name="GL_UNIFORM_BUFFER"/>
+        </group>
+
+        <group name="CheckFramebufferStatusTarget">
+            <enum name="GL_DRAW_FRAMEBUFFER"/>
+            <enum name="GL_READ_FRAMEBUFFER"/>
+            <enum name="GL_FRAMEBUFFER"/>
+        </group>
+
+        <group name="Buffer">
+            <enum name="GL_COLOR"/>
+            <enum name="GL_DEPTH"/>
+            <enum name="GL_STENCIL"/>
+        </group>
+
+        <group name="ClipControlOrigin">
+            <enum name="GL_LOWER_LEFT"/>
+            <enum name="GL_UPPER_LEFT"/>
+        </group>
+
+        <group name="ClipControlDepth">
+            <enum name="GL_NEGATIVE_ONE_TO_ONE"/>
+            <enum name="GL_ZERO_TO_ONE"/>
+        </group>
+
+        <group name="CopyBufferSubDataTarget">
+            <enum name="GL_ARRAY_BUFFER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER"/>
+            <enum name="GL_COPY_READ_BUFFER"/>
+            <enum name="GL_COPY_WRITE_BUFFER"/>
+            <enum name="GL_DISPATCH_INDIRECT_BUFFER"/>
+            <enum name="GL_DRAW_INDIRECT_BUFFER"/>
+            <enum name="GL_ELEMENT_ARRAY_BUFFER"/>
+            <enum name="GL_PIXEL_PACK_BUFFER"/>
+            <enum name="GL_PIXEL_UNPACK_BUFFER"/>
+            <enum name="GL_QUERY_BUFFER"/>
+            <enum name="GL_SHADER_STORAGE_BUFFER"/>
+            <enum name="GL_TEXTURE_BUFFER"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER"/>
+            <enum name="GL_UNIFORM_BUFFER"/>
+        </group>
+
+        <group name="ShaderType">
+            <enum name="GL_COMPUTE_SHADER"/>
+            <enum name="GL_VERTEX_SHADER"/>
+            <enum name="GL_TESS_CONTROL_SHADER"/>
+            <enum name="GL_TESS_EVALUATION_SHADER"/>
+            <enum name="GL_GEOMETRY_SHADER"/>
+            <enum name="GL_FRAGMENT_SHADER"/>
+            <enum name="GL_FRAGMENT_SHADER_ARB"/>
+            <enum name="GL_VERTEX_SHADER_ARB"/>
+        </group>
+
+        <group name="DebugSource">
+            <enum name="GL_DEBUG_SOURCE_API"/>
+            <enum name="GL_DEBUG_SOURCE_WINDOW_SYSTEM"/>
+            <enum name="GL_DEBUG_SOURCE_SHADER_COMPILER"/>
+            <enum name="GL_DEBUG_SOURCE_THIRD_PARTY"/>
+            <enum name="GL_DEBUG_SOURCE_APPLICATION"/>
+            <enum name="GL_DEBUG_SOURCE_OTHER"/>
+            <enum name="GL_DONT_CARE"/>
+        </group>
+
+        <group name="DebugType">
+            <enum name="GL_DEBUG_TYPE_ERROR"/>
+            <enum name="GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR"/>
+            <enum name="GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR"/>
+            <enum name="GL_DEBUG_TYPE_PORTABILITY"/>
+            <enum name="GL_DEBUG_TYPE_PERFORMANCE"/>
+            <enum name="GL_DEBUG_TYPE_MARKER"/>
+            <enum name="GL_DEBUG_TYPE_PUSH_GROUP"/>
+            <enum name="GL_DEBUG_TYPE_POP_GROUP"/>
+            <enum name="GL_DEBUG_TYPE_OTHER"/>
+            <enum name="GL_DONT_CARE"/>
+        </group>
+
+        <group name="DebugSeverity">
+            <enum name="GL_DEBUG_SEVERITY_LOW"/>
+            <enum name="GL_DEBUG_SEVERITY_MEDIUM"/>
+            <enum name="GL_DEBUG_SEVERITY_HIGH"/>
+            <enum name="GL_DONT_CARE"/>
+        </group>
+
+        <group name="SyncCondition">
+            <enum name="GL_SYNC_GPU_COMMANDS_COMPLETE"/>
+        </group>
+
+        <group name="FogPName">
+            <enum name="GL_FOG_MODE"/>
+            <enum name="GL_FOG_DENSITY"/>
+            <enum name="GL_FOG_START"/>
+            <enum name="GL_FOG_END"/>
+            <enum name="GL_FOG_INDEX"/>
+            <enum name="GL_FOG_COORD_SRC"/>
+        </group>
+
+        <group name="AtomicCounterBufferPName">
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_BINDING"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER"/>
+            <enum name="GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER"/>
+        </group>
+
+        <group name="UniformBlockPName">
+            <enum name="GL_UNIFORM_BLOCK_BINDING"/>
+            <enum name="GL_UNIFORM_BLOCK_DATA_SIZE"/>
+            <enum name="GL_UNIFORM_BLOCK_NAME_LENGTH"/>
+            <enum name="GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS"/>
+            <enum name="GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER"/>
+            <enum name="GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER"/>
+        </group>
+
+        <group name="UniformPName">
+            <enum name="GL_UNIFORM_TYPE"/>
+            <enum name="GL_UNIFORM_SIZE"/>
+            <enum name="GL_UNIFORM_NAME_LENGTH"/>
+            <enum name="GL_UNIFORM_BLOCK_INDEX"/>
+            <enum name="GL_UNIFORM_OFFSET"/>
+            <enum name="GL_UNIFORM_ARRAY_STRIDE"/>
+            <enum name="GL_UNIFORM_MATRIX_STRIDE"/>
+            <enum name="GL_UNIFORM_IS_ROW_MAJOR"/>
+            <enum name="GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX"/>
+        </group>
+
+        <group name="SamplerParameterName">
+            <enum name="GL_TEXTURE_WRAP_S"/>
+            <enum name="GL_TEXTURE_WRAP_T"/>
+            <enum name="GL_TEXTURE_WRAP_R"/>
+            <enum name="GL_TEXTURE_MIN_FILTER"/>
+            <enum name="GL_TEXTURE_MAG_FILTER"/>
+            <enum name="GL_TEXTURE_BORDER_COLOR"/>
+            <enum name="GL_TEXTURE_MIN_LOD"/>
+            <enum name="GL_TEXTURE_MAX_LOD"/>
+            <enum name="GL_TEXTURE_COMPARE_MODE"/>
+            <enum name="GL_TEXTURE_COMPARE_FUNC"/>
+        </group>
+
+        <group name="VertexProvokingMode">
+            <enum name="GL_FIRST_VERTEX_CONVENTION"/>
+            <enum name="GL_LAST_VERTEX_CONVENTION"/>
+        </group>
+
+        <group name="PatchParameterName">
+            <enum name="GL_PATCH_VERTICES"/>
+            <enum name="GL_PATCH_DEFAULT_OUTER_LEVEL"/>
+            <enum name="GL_PATCH_DEFAULT_INNER_LEVEL"/>
+        </group>
+
+        <group name="ObjectIdentifier">
+            <enum name="GL_BUFFER"/>
+            <enum name="GL_SHADER"/>
+            <enum name="GL_PROGRAM"/>
+            <enum name="GL_VERTEX_ARRAY"/>
+            <enum name="GL_QUERY"/>
+            <enum name="GL_PROGRAM_PIPELINE"/>
+            <enum name="GL_TRANSFORM_FEEDBACK"/>
+            <enum name="GL_SAMPLER"/>
+            <enum name="GL_TEXTURE"/>
+            <enum name="GL_RENDERBUFFER"/>
+            <enum name="GL_FRAMEBUFFER"/>
+        </group>
+
+        <group name="ColorBuffer">
+            <enum name="GL_NONE"/>
+            <enum name="GL_FRONT_LEFT"/>
+            <enum name="GL_FRONT_RIGHT"/>
+            <enum name="GL_BACK_LEFT"/>
+            <enum name="GL_BACK_RIGHT"/>
+            <enum name="GL_FRONT"/>
+            <enum name="GL_BACK"/>
+            <enum name="GL_LEFT"/>
+            <enum name="GL_RIGHT"/>
+            <enum name="GL_FRONT_AND_BACK"/>
+            <enum name="GL_NONE"/>
+            <enum name="GL_COLOR_ATTACHMENT0"/>
+            <enum name="GL_COLOR_ATTACHMENT1"/>
+            <enum name="GL_COLOR_ATTACHMENT2"/>
+            <enum name="GL_COLOR_ATTACHMENT3"/>
+            <enum name="GL_COLOR_ATTACHMENT4"/>
+            <enum name="GL_COLOR_ATTACHMENT5"/>
+            <enum name="GL_COLOR_ATTACHMENT6"/>
+            <enum name="GL_COLOR_ATTACHMENT7"/>
+            <enum name="GL_COLOR_ATTACHMENT8"/>
+            <enum name="GL_COLOR_ATTACHMENT9"/>
+            <enum name="GL_COLOR_ATTACHMENT10"/>
+            <enum name="GL_COLOR_ATTACHMENT11"/>
+            <enum name="GL_COLOR_ATTACHMENT12"/>
+            <enum name="GL_COLOR_ATTACHMENT13"/>
+            <enum name="GL_COLOR_ATTACHMENT14"/>
+            <enum name="GL_COLOR_ATTACHMENT15"/>
+            <enum name="GL_COLOR_ATTACHMENT16"/>
+            <enum name="GL_COLOR_ATTACHMENT17"/>
+            <enum name="GL_COLOR_ATTACHMENT18"/>
+            <enum name="GL_COLOR_ATTACHMENT19"/>
+            <enum name="GL_COLOR_ATTACHMENT20"/>
+            <enum name="GL_COLOR_ATTACHMENT21"/>
+            <enum name="GL_COLOR_ATTACHMENT22"/>
+            <enum name="GL_COLOR_ATTACHMENT23"/>
+            <enum name="GL_COLOR_ATTACHMENT24"/>
+            <enum name="GL_COLOR_ATTACHMENT25"/>
+            <enum name="GL_COLOR_ATTACHMENT26"/>
+            <enum name="GL_COLOR_ATTACHMENT27"/>
+            <enum name="GL_COLOR_ATTACHMENT28"/>
+            <enum name="GL_COLOR_ATTACHMENT29"/>
+            <enum name="GL_COLOR_ATTACHMENT30"/>
+            <enum name="GL_COLOR_ATTACHMENT31"/>
+        </group>
+
+        <group name="MapQuery">
+            <enum name="GL_COEFF"/>
+            <enum name="GL_ORDER"/>
+            <enum name="GL_DOMAIN"/>
+        </group>
+
+        <group name="VertexArrayPName">
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_ENABLED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_SIZE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_STRIDE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_TYPE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_INTEGER"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_LONG"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_DIVISOR"/>
+            <enum name="GL_VERTEX_ATTRIB_RELATIVE_OFFSET"/>
+        </group>
+
+        <group name="TransformFeedbackPName">
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER_BINDING"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER_START"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER_SIZE"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_PAUSED"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_ACTIVE"/>
+        </group>
+
+        <group name="SyncParameterName">
+            <enum name="GL_OBJECT_TYPE"/>
+            <enum name="GL_SYNC_STATUS"/>
+            <enum name="GL_SYNC_CONDITION"/>
+            <enum name="GL_SYNC_FLAGS"/>
+        </group>
+
+        <group name="ShaderParameterName">
+            <enum name="GL_SHADER_TYPE"/>
+            <enum name="GL_DELETE_STATUS"/>
+            <enum name="GL_COMPILE_STATUS"/>
+            <enum name="GL_INFO_LOG_LENGTH"/>
+            <enum name="GL_SHADER_SOURCE_LENGTH"/>
+        </group>
+
+        <group name="QueryObjectParameterName">
+            <enum name="GL_QUERY_RESULT_AVAILABLE"/>
+            <enum name="GL_QUERY_RESULT"/>
+            <enum name="GL_QUERY_RESULT_NO_WAIT"/>
+            <enum name="GL_QUERY_TARGET"/>
+        </group>
+
+        <group name="QueryParameterName">
+            <enum name="GL_CURRENT_QUERY"/>
+            <enum name="GL_QUERY_COUNTER_BITS"/>
+        </group>
+
+        <group name="ProgramStagePName">
+            <enum name="GL_ACTIVE_SUBROUTINE_UNIFORMS"/>
+            <enum name="GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS"/>
+            <enum name="GL_ACTIVE_SUBROUTINES"/>
+            <enum name="GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH"/>
+            <enum name="GL_ACTIVE_SUBROUTINE_MAX_LENGTH"/>
+        </group>
+
+        <group name="PipelineParameterName">
+            <enum name="GL_ACTIVE_PROGRAM"/>
+            <enum name="GL_VERTEX_SHADER"/>
+            <enum name="GL_TESS_CONTROL_SHADER"/>
+            <enum name="GL_TESS_EVALUATION_SHADER"/>
+            <enum name="GL_GEOMETRY_SHADER"/>
+            <enum name="GL_FRAGMENT_SHADER"/>
+            <enum name="GL_INFO_LOG_LENGTH"/>
+        </group>
+
+        <group name="ProgramInterface">
+            <enum name="GL_UNIFORM"/>
+            <enum name="GL_UNIFORM_BLOCK"/>
+            <enum name="GL_PROGRAM_INPUT"/>
+            <enum name="GL_PROGRAM_OUTPUT"/>
+            <enum name="GL_VERTEX_SUBROUTINE"/>
+            <enum name="GL_TESS_CONTROL_SUBROUTINE"/>
+            <enum name="GL_TESS_EVALUATION_SUBROUTINE"/>
+            <enum name="GL_GEOMETRY_SUBROUTINE"/>
+            <enum name="GL_FRAGMENT_SUBROUTINE"/>
+            <enum name="GL_COMPUTE_SUBROUTINE"/>
+            <enum name="GL_VERTEX_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_TESS_CONTROL_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_TESS_EVALUATION_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_GEOMETRY_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_FRAGMENT_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_COMPUTE_SUBROUTINE_UNIFORM"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_VARYING"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER"/>
+            <enum name="GL_BUFFER_VARIABLE"/>
+            <enum name="GL_SHADER_STORAGE_BLOCK"/>
+        </group>
+
+        <group name="VertexAttribEnum">
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_ENABLED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_SIZE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_STRIDE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_TYPE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_INTEGER"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_DIVISOR"/>
+            <enum name="GL_CURRENT_VERTEX_ATTRIB"/>
+        </group>
+
+        <group name="VertexAttribType">
+            <enum name="GL_BYTE"/>
+            <enum name="GL_SHORT"/>
+            <enum name="GL_INT"/>
+            <enum name="GL_FIXED"/>
+            <enum name="GL_FLOAT"/>
+            <enum name="GL_HALF_FLOAT"/>
+            <enum name="GL_DOUBLE"/>
+            <enum name="GL_UNSIGNED_BYTE"/>
+            <enum name="GL_UNSIGNED_SHORT"/>
+            <enum name="GL_UNSIGNED_INT"/>
+            <enum name="GL_INT_2_10_10_10_REV"/>
+            <enum name="GL_UNSIGNED_INT_2_10_10_10_REV"/>
+            <enum name="GL_UNSIGNED_INT_10F_11F_11F_REV"/>
+        </group>
+
+        <group name="AttributeType">
+            <enum name="GL_FLOAT_VEC2"/>
+            <enum name="GL_FLOAT_VEC2_ARB"/>
+            <enum name="GL_FLOAT_VEC3"/>
+            <enum name="GL_FLOAT_VEC3_ARB"/>
+            <enum name="GL_FLOAT_VEC4"/>
+            <enum name="GL_FLOAT_VEC4_ARB"/>
+            <enum name="GL_INT_VEC2"/>
+            <enum name="GL_INT_VEC2_ARB"/>
+            <enum name="GL_INT_VEC3"/>
+            <enum name="GL_INT_VEC3_ARB"/>
+            <enum name="GL_INT_VEC4"/>
+            <enum name="GL_INT_VEC4_ARB"/>
+            <enum name="GL_BOOL"/>
+            <enum name="GL_BOOL_ARB"/>
+            <enum name="GL_BOOL_VEC2"/>
+            <enum name="GL_BOOL_VEC2_ARB"/>
+            <enum name="GL_BOOL_VEC3"/>
+            <enum name="GL_BOOL_VEC3_ARB"/>
+            <enum name="GL_BOOL_VEC4"/>
+            <enum name="GL_BOOL_VEC4_ARB"/>
+            <enum name="GL_FLOAT_MAT2"/>
+            <enum name="GL_FLOAT_MAT2_ARB"/>
+            <enum name="GL_FLOAT_MAT3"/>
+            <enum name="GL_FLOAT_MAT3_ARB"/>
+            <enum name="GL_FLOAT_MAT4"/>
+            <enum name="GL_FLOAT_MAT4_ARB"/>
+            <enum name="GL_SAMPLER_1D"/>
+            <enum name="GL_SAMPLER_1D_ARB"/>
+            <enum name="GL_SAMPLER_2D"/>
+            <enum name="GL_SAMPLER_2D_ARB"/>
+            <enum name="GL_SAMPLER_3D"/>
+            <enum name="GL_SAMPLER_3D_ARB"/>
+            <enum name="GL_SAMPLER_3D_OES"/>
+            <enum name="GL_SAMPLER_CUBE"/>
+            <enum name="GL_SAMPLER_CUBE_ARB"/>
+            <enum name="GL_SAMPLER_1D_SHADOW"/>
+            <enum name="GL_SAMPLER_1D_SHADOW_ARB"/>
+            <enum name="GL_SAMPLER_2D_SHADOW"/>
+            <enum name="GL_SAMPLER_2D_SHADOW_ARB"/>
+            <enum name="GL_SAMPLER_2D_SHADOW_EXT"/>
+            <enum name="GL_SAMPLER_2D_RECT"/>
+            <enum name="GL_SAMPLER_2D_RECT_ARB"/>
+            <enum name="GL_SAMPLER_2D_RECT_SHADOW"/>
+            <enum name="GL_SAMPLER_2D_RECT_SHADOW_ARB"/>
+            <enum name="GL_FLOAT_MAT2x3"/>
+            <enum name="GL_FLOAT_MAT2x3_NV"/>
+            <enum name="GL_FLOAT_MAT2x4"/>
+            <enum name="GL_FLOAT_MAT2x4_NV"/>
+            <enum name="GL_FLOAT_MAT3x2"/>
+            <enum name="GL_FLOAT_MAT3x2_NV"/>
+            <enum name="GL_FLOAT_MAT3x4"/>
+            <enum name="GL_FLOAT_MAT3x4_NV"/>
+            <enum name="GL_FLOAT_MAT4x2"/>
+            <enum name="GL_FLOAT_MAT4x2_NV"/>
+            <enum name="GL_FLOAT_MAT4x3"/>
+            <enum name="GL_FLOAT_MAT4x3_NV"/>
+        </group>
+
+        <group name="InternalFormatPName">
+            <enum name="GL_NUM_SAMPLE_COUNTS"/>
+            <enum name="GL_SAMPLES"/>
+            <enum name="GL_INTERNALFORMAT_SUPPORTED"/>
+            <enum name="GL_INTERNALFORMAT_PREFERRED"/>
+            <enum name="GL_INTERNALFORMAT_RED_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_GREEN_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_BLUE_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_ALPHA_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_DEPTH_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_STENCIL_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_SHARED_SIZE"/>
+            <enum name="GL_INTERNALFORMAT_RED_TYPE"/>
+            <enum name="GL_INTERNALFORMAT_GREEN_TYPE"/>
+            <enum name="GL_INTERNALFORMAT_BLUE_TYPE"/>
+            <enum name="GL_INTERNALFORMAT_ALPHA_TYPE"/>
+            <enum name="GL_INTERNALFORMAT_DEPTH_TYPE"/>
+            <enum name="GL_INTERNALFORMAT_STENCIL_TYPE"/>
+            <enum name="GL_MAX_WIDTH"/>
+            <enum name="GL_MAX_HEIGHT"/>
+            <enum name="GL_MAX_DEPTH"/>
+            <enum name="GL_MAX_LAYERS"/>
+            <enum name="GL_COLOR_COMPONENTS"/>
+            <enum name="GL_COLOR_RENDERABLE"/>
+            <enum name="GL_DEPTH_RENDERABLE"/>
+            <enum name="GL_STENCIL_RENDERABLE"/>
+            <enum name="GL_FRAMEBUFFER_RENDERABLE"/>
+            <enum name="GL_FRAMEBUFFER_RENDERABLE_LAYERED"/>
+            <enum name="GL_FRAMEBUFFER_BLEND"/>
+            <enum name="GL_READ_PIXELS"/>
+            <enum name="GL_READ_PIXELS_FORMAT"/>
+            <enum name="GL_READ_PIXELS_TYPE"/>
+            <enum name="GL_TEXTURE_IMAGE_FORMAT"/>
+            <enum name="GL_TEXTURE_IMAGE_TYPE"/>
+            <enum name="GL_GET_TEXTURE_IMAGE_FORMAT"/>
+            <enum name="GL_GET_TEXTURE_IMAGE_TYPE"/>
+            <enum name="GL_MIPMAP"/>
+            <enum name="GL_GENERATE_MIPMAP"/>
+            <enum name="GL_AUTO_GENERATE_MIPMAP"/>
+            <enum name="GL_COLOR_ENCODING"/>
+            <enum name="GL_SRGB_READ"/>
+            <enum name="GL_SRGB_WRITE"/>
+            <enum name="GL_FILTER"/>
+            <enum name="GL_VERTEX_TEXTURE"/>
+            <enum name="GL_TESS_CONTROL_TEXTURE"/>
+            <enum name="GL_TESS_EVALUATION_TEXTURE"/>
+            <enum name="GL_GEOMETRY_TEXTURE"/>
+            <enum name="GL_FRAGMENT_TEXTURE"/>
+            <enum name="GL_COMPUTE_TEXTURE"/>
+            <enum name="GL_TEXTURE_SHADOW"/>
+            <enum name="GL_TEXTURE_GATHER"/>
+            <enum name="GL_TEXTURE_GATHER_SHADOW"/>
+            <enum name="GL_SHADER_IMAGE_LOAD"/>
+            <enum name="GL_SHADER_IMAGE_STORE"/>
+            <enum name="GL_SHADER_IMAGE_ATOMIC"/>
+            <enum name="GL_IMAGE_TEXEL_SIZE"/>
+            <enum name="GL_IMAGE_COMPATIBILITY_CLASS"/>
+            <enum name="GL_IMAGE_PIXEL_FORMAT"/>
+            <enum name="GL_IMAGE_PIXEL_TYPE"/>
+            <enum name="GL_IMAGE_FORMAT_COMPATIBILITY_TYPE"/>
+            <enum name="GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST"/>
+            <enum name="GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST"/>
+            <enum name="GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE"/>
+            <enum name="GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE"/>
+            <enum name="GL_TEXTURE_COMPRESSED"/>
+            <enum name="GL_TEXTURE_COMPRESSED_BLOCK_WIDTH"/>
+            <enum name="GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT"/>
+            <enum name="GL_TEXTURE_COMPRESSED_BLOCK_SIZE"/>
+            <enum name="GL_CLEAR_BUFFER"/>
+            <enum name="GL_TEXTURE_VIEW"/>
+            <enum name="GL_VIEW_COMPATIBILITY_CLASS"/>
+            <enum name="GL_CLEAR_TEXTURE"/>
+        </group>
+
+        <group name="FramebufferAttachmentParameterName">
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_LAYERED"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER"/>
+        </group>
+
+        <group name="ProgramInterfacePName">
+            <enum name="GL_ACTIVE_RESOURCES"/>
+            <enum name="GL_MAX_NAME_LENGTH"/>
+            <enum name="GL_MAX_NUM_ACTIVE_VARIABLES"/>
+            <enum name="GL_MAX_NUM_COMPATIBLE_SUBROUTINES"/>
+        </group>
+
+        <group name="PrecisionType">
+            <enum name="GL_LOW_FLOAT"/>
+            <enum name="GL_MEDIUM_FLOAT"/>
+            <enum name="GL_HIGH_FLOAT"/>
+            <enum name="GL_LOW_INT"/>
+            <enum name="GL_MEDIUM_INT"/>
+            <enum name="GL_HIGH_INT"/>
+        </group>
+
+        <group name="VertexAttribPointerType">
+            <enum name="GL_BYTE"/>
+            <enum name="GL_UNSIGNED_BYTE"/>
+            <enum name="GL_SHORT"/>
+            <enum name="GL_UNSIGNED_SHORT"/>
+            <enum name="GL_INT"/>
+            <enum name="GL_UNSIGNED_INT"/>
+            <enum name="GL_FLOAT"/>
+            <enum name="GL_DOUBLE"/>
+            <enum name="GL_HALF_FLOAT"/>
+            <enum name="GL_FIXED"/>
+            <enum name="GL_INT_2_10_10_10_REV"/>
+            <enum name="GL_UNSIGNED_INT_2_10_10_10_REV"/>
+            <enum name="GL_UNSIGNED_INT_10F_11F_11F_REV"/>
+        </group>
+
+        <group name="SubroutineParameterName">
+            <enum name="GL_NUM_COMPATIBLE_SUBROUTINES"/>
+            <enum name="GL_COMPATIBLE_SUBROUTINES"/>
+            <enum name="GL_UNIFORM_SIZE"/>
+            <enum name="GL_UNIFORM_NAME_LENGTH"/>
+        </group>
+
+        <group name="GetFramebufferParameter">
+            <enum name="GL_FRAMEBUFFER_DEFAULT_WIDTH"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_HEIGHT"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_LAYERS"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_SAMPLES"/>
+            <enum name="GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS"/>
+            <enum name="GL_DOUBLEBUFFER"/>
+            <enum name="GL_IMPLEMENTATION_COLOR_READ_FORMAT"/>
+            <enum name="GL_IMPLEMENTATION_COLOR_READ_TYPE"/>
+            <enum name="GL_SAMPLES"/>
+            <enum name="GL_SAMPLE_BUFFERS"/>
+            <enum name="GL_STEREO"/>
+        </group>
+
+        <group name="PathStringFormat">
+            <enum name="GL_PATH_FORMAT_SVG_NV" />
+            <enum name="GL_PATH_FORMAT_PS_NV" />
+        </group>
+
+        <group name="PathFontTarget">
+            <enum name="GL_STANDARD_FONT_NAME_NV" />
+            <enum name="GL_SYSTEM_FONT_NAME_NV" />
+            <enum name="GL_FILE_NAME_NV" />
+        </group>
+
+        <group name="PathHandleMissingGlyphs">
+            <enum name="GL_SKIP_MISSING_GLYPH_NV" />
+            <enum name="GL_USE_MISSING_GLYPH_NV" />
+        </group>
+
+        <group name="PathParameter">
+            <enum name="GL_PATH_STROKE_WIDTH_NV" />
+            <enum name="GL_PATH_INITIAL_END_CAP_NV" />
+            <enum name="GL_PATH_TERMINAL_END_CAP_NV" />
+            <enum name="GL_PATH_JOIN_STYLE_NV" />
+            <enum name="GL_PATH_MITER_LIMIT_NV" />
+            <enum name="GL_PATH_INITIAL_DASH_CAP_NV" />
+            <enum name="GL_PATH_TERMINAL_DASH_CAP_NV" />
+            <enum name="GL_PATH_DASH_OFFSET_NV" />
+            <enum name="GL_PATH_CLIENT_LENGTH_NV" />
+            <enum name="GL_PATH_DASH_OFFSET_RESET_NV" />
+            <enum name="GL_PATH_FILL_MODE_NV" />
+            <enum name="GL_PATH_FILL_MASK_NV" />
+            <enum name="GL_PATH_FILL_COVER_MODE_NV" />
+            <enum name="GL_PATH_STROKE_COVER_MODE_NV" />
+            <enum name="GL_PATH_STROKE_MASK_NV" />
+            <!-- <enum name="GL_PATH_STROKE_BOUND_NV" comment="Removed from extension"/> -->
+            <enum name="GL_PATH_END_CAPS_NV" />
+            <enum name="GL_PATH_DASH_CAPS_NV" />
+            <enum name="GL_PATH_COMMAND_COUNT_NV" />
+            <enum name="GL_PATH_COORD_COUNT_NV" />
+            <enum name="GL_PATH_DASH_ARRAY_COUNT_NV" />
+            <enum name="GL_PATH_COMPUTED_LENGTH_NV" />
+            <enum name="GL_PATH_OBJECT_BOUNDING_BOX_NV" />
+            <enum name="GL_PATH_FILL_BOUNDING_BOX_NV" />
+            <enum name="GL_PATH_STROKE_BOUNDING_BOX_NV" />
+        </group>
+
+        <group name="PathColor">
+            <enum name="GL_PRIMARY_COLOR" />
+            <enum name="GL_PRIMARY_COLOR_NV" />
+            <enum name="GL_SECONDARY_COLOR_NV" />
+        </group>
+
+        <group name="PathGenMode">
+            <enum name="GL_NONE" />
+            <enum name="GL_EYE_LINEAR" />
+            <enum name="GL_OBJECT_LINEAR" />
+            <enum name="GL_PATH_OBJECT_BOUNDING_BOX_NV" />
+            <enum name="GL_CONSTANT" />
+        </group>
+
+        <group name="TextureLayout">
+            <enum name="GL_LAYOUT_GENERAL_EXT"/>
+            <enum name="GL_LAYOUT_COLOR_ATTACHMENT_EXT"/>
+            <enum name="GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT"/>
+            <enum name="GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT"/>
+            <enum name="GL_LAYOUT_SHADER_READ_ONLY_EXT"/>
+            <enum name="GL_LAYOUT_TRANSFER_SRC_EXT"/>
+            <enum name="GL_LAYOUT_TRANSFER_DST_EXT"/>
+            <enum name="GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT"/>
+            <enum name="GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT"/>
+        </group>
+
+        <group name="PathTransformType">
+            <enum name="GL_NONE" />
+            <enum name="GL_TRANSLATE_X_NV" />
+            <enum name="GL_TRANSLATE_Y_NV" />
+            <enum name="GL_TRANSLATE_2D_NV" />
+            <enum name="GL_TRANSLATE_3D_NV" />
+            <enum name="GL_AFFINE_2D_NV" />
+            <enum name="GL_AFFINE_3D_NV" />
+            <enum name="GL_TRANSPOSE_AFFINE_2D_NV" />
+            <enum name="GL_TRANSPOSE_AFFINE_3D_NV" />
+        </group>
+
+        <group name="PathElementType">
+            <enum name="GL_UTF8_NV" />
+            <enum name="GL_UTF16_NV" />
+        </group>
+
+        <group name="PathCoverMode">
+            <enum name="GL_CONVEX_HULL_NV" />
+            <enum name="GL_BOUNDING_BOX_NV" />
+            <enum name="GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV" />
+            <enum name="GL_PATH_FILL_COVER_MODE_NV" />
+        </group>
+
+        <group name="PathFontStyle">
+            <enum name="GL_NONE" />
+            <enum name="GL_BOLD_BIT_NV" />
+            <enum name="GL_ITALIC_BIT_NV" />
+        </group>
+
+        <group name="PathMetricMask">
+            <enum name="GL_GLYPH_WIDTH_BIT_NV" />
+            <enum name="GL_GLYPH_HEIGHT_BIT_NV" />
+            <enum name="GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV" />
+            <enum name="GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV" />
+            <enum name="GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV" />
+            <enum name="GL_GLYPH_VERTICAL_BEARING_X_BIT_NV" />
+            <enum name="GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV" />
+            <enum name="GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV" />
+            <enum name="GL_GLYPH_HAS_KERNING_BIT_NV" />
+            <enum name="GL_FONT_X_MIN_BOUNDS_BIT_NV" />
+            <enum name="GL_FONT_Y_MIN_BOUNDS_BIT_NV" />
+            <enum name="GL_FONT_X_MAX_BOUNDS_BIT_NV" />
+            <enum name="GL_FONT_Y_MAX_BOUNDS_BIT_NV" />
+            <enum name="GL_FONT_UNITS_PER_EM_BIT_NV" />
+            <enum name="GL_FONT_ASCENDER_BIT_NV" />
+            <enum name="GL_FONT_DESCENDER_BIT_NV" />
+            <enum name="GL_FONT_HEIGHT_BIT_NV" />
+            <enum name="GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV" />
+            <enum name="GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV" />
+            <enum name="GL_FONT_UNDERLINE_POSITION_BIT_NV" />
+            <enum name="GL_FONT_UNDERLINE_THICKNESS_BIT_NV" />
+            <enum name="GL_FONT_HAS_KERNING_BIT_NV" />
+            <enum name="GL_FONT_NUM_GLYPH_INDICES_BIT_NV" />
+        </group>
+
+        <group name="PathListMode">
+            <enum name="GL_ACCUM_ADJACENT_PAIRS_NV" />
+            <enum name="GL_ADJACENT_PAIRS_NV" />
+            <enum name="GL_FIRST_TO_REST_NV" />
+        </group>
+
+        <group name="ProgramPropertyARB">
+            <enum name="GL_DELETE_STATUS" />
+            <enum name="GL_LINK_STATUS" />
+            <enum name="GL_VALIDATE_STATUS" />
+            <enum name="GL_INFO_LOG_LENGTH" />
+            <enum name="GL_ATTACHED_SHADERS" />
+            <enum name="GL_ACTIVE_ATOMIC_COUNTER_BUFFERS" />
+            <enum name="GL_ACTIVE_ATTRIBUTES" />
+            <enum name="GL_ACTIVE_ATTRIBUTE_MAX_LENGTH" />
+            <enum name="GL_ACTIVE_UNIFORMS" />
+            <enum name="GL_ACTIVE_UNIFORM_BLOCKS" />
+            <enum name="GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH" />
+            <enum name="GL_ACTIVE_UNIFORM_MAX_LENGTH" />
+            <enum name="GL_COMPUTE_WORK_GROUP_SIZE" />
+            <enum name="GL_PROGRAM_BINARY_LENGTH" />
+            <enum name="GL_TRANSFORM_FEEDBACK_BUFFER_MODE" />
+            <enum name="GL_TRANSFORM_FEEDBACK_VARYINGS" />
+            <enum name="GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH" />
+            <enum name="GL_GEOMETRY_VERTICES_OUT" />
+            <enum name="GL_GEOMETRY_INPUT_TYPE" />
+            <enum name="GL_GEOMETRY_OUTPUT_TYPE" />
+        </group>
     </groups>
 
     <!-- SECTION: GL enumerant (token) definitions. -->
@@ -2043,6 +3419,10 @@
         <enum value="0xFFFFFFFF" name="GL_ALL_ATTRIB_BITS" comment="Guaranteed to mark all attribute groups at once"/>
     </enums>
 
+    <enums namespace="GL" group="BufferAccessMask" type="bitmask" comment="GL_MAP_{COHERENT,FLUSH_EXPLICIT,INVALIDATE_BUFFER,INVALIDATE_RANGE,PERSISTENT,READ,UNSYNCHRONIZED,WRITE}_{BIT,BIT_EXT} also lie in this namespace">
+      <!-- Also used: 0x000000ff for bits reused from MapBufferUsageMask below -->
+    </enums>
+
     <enums namespace="GL" group="ClearBufferMask" type="bitmask" comment="GL_{DEPTH,ACCUM,STENCIL,COLOR}_BUFFER_BIT also lie in this namespace">
         <enum value="0x00008000" name="GL_COVERAGE_BUFFER_BIT_NV" comment="Collides with AttribMask bit GL_HINT_BIT. OK since this token is for OpenGL ES 2, which doesn't have attribute groups."/>
             <!-- Also used: 0x00004700 for bits reused from AttribMask above -->
@@ -2060,7 +3440,9 @@
         <enum value="0x00000002" name="GL_CONTEXT_FLAG_DEBUG_BIT_KHR"/>
         <enum value="0x00000004" name="GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT"/>
         <enum value="0x00000004" name="GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB"/>
-        <enum value="0x00000008" name="GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR"/>
+        <enum value="0x00000008" name="GL_CONTEXT_FLAG_NO_ERROR_BIT"/>
+        <enum value="0x00000008" name="GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR" alias="GL_CONTEXT_FLAG_NO_ERROR_BIT"/>
+        <enum value="0x00000010" name="GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT"/>
     </enums>
 
     <enums namespace="GL" group="ContextProfileMask" type="bitmask">
@@ -2090,6 +3472,10 @@
         <enum value="0x0200" name="GL_CLIENT_STORAGE_BIT"/>
         <enum value="0x0200" name="GL_CLIENT_STORAGE_BIT_EXT"/>
         <enum value="0x0400" name="GL_SPARSE_STORAGE_BIT_ARB"/>
+        <enum value="0x0800" name="GL_LGPU_SEPARATE_STORAGE_BIT_NVX"/>
+        <enum value="0x0800" name="GL_PER_GPU_STORAGE_BIT_NV"/>
+            <unused start="0x1000" end="0x1000" comment="Reserved for NVIDIA"/>
+        <enum value="0x2000" name="GL_EXTERNAL_STORAGE_BIT_NVX"/>
     </enums>
 
     <enums namespace="GL" group="MemoryBarrierMask" type="bitmask">
@@ -2126,7 +3512,7 @@
         <enum value="0xFFFFFFFF" name="GL_ALL_BARRIER_BITS_EXT"/>
     </enums>
 
-    <enums namespace="OcclusionQueryEventMaskAMD">
+    <enums namespace="GL" group="OcclusionQueryEventMaskAMD" type="bitmask">
         <enum value="0x00000001" name="GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD"/>
         <enum value="0x00000002" name="GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD"/>
         <enum value="0x00000004" name="GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD"/>
@@ -2286,11 +3672,17 @@
         <enum value="0x80000000" name="GL_MULTISAMPLE_BUFFER_BIT7_QCOM"/>
     </enums>
 
+    <enums namespace="GL" group="FoveationConfigBitQCOM" type="bitmask">
+        <enum value="0x00000001" name="GL_FOVEATION_ENABLE_BIT_QCOM"/>
+        <enum value="0x00000002" name="GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM"/>
+    </enums>
+
     <enums namespace="GL" group="FfdMaskSGIX" type="bitmask">
         <enum value="0x00000001" name="GL_TEXTURE_DEFORMATION_BIT_SGIX"/>
         <enum value="0x00000002" name="GL_GEOMETRY_DEFORMATION_BIT_SGIX"/>
     </enums>
 
+
     <!-- Non-bitmask enums with their own namespace. Generally small numbers
          used for indexed access. -->
 
@@ -2404,11 +3796,14 @@
         <enum value="1" name="GL_TRUE"/>
         <enum value="1" name="GL_ONE"/>
         <enum value="0xFFFFFFFF" name="GL_INVALID_INDEX" type="u" comment="Tagged as uint"/>
+        <enum value="0xFFFFFFFF" name="GL_ALL_PIXELS_AMD"/>
         <enum value="0xFFFFFFFFFFFFFFFF" name="GL_TIMEOUT_IGNORED" type="ull" comment="Tagged as uint64"/>
         <enum value="0xFFFFFFFFFFFFFFFF" name="GL_TIMEOUT_IGNORED_APPLE" type="ull" comment="Tagged as uint64"/>
         <enum value="1" name="GL_VERSION_ES_CL_1_0" comment="Not an API enum. API definition macro for ES 1.0/1.1 headers"/>
         <enum value="1" name="GL_VERSION_ES_CM_1_1" comment="Not an API enum. API definition macro for ES 1.0/1.1 headers"/>
         <enum value="1" name="GL_VERSION_ES_CL_1_1" comment="Not an API enum. API definition macro for ES 1.0/1.1 headers"/>
+        <enum value="16" name="GL_UUID_SIZE_EXT"/>
+        <enum value="8" name="GL_LUID_SIZE_EXT"/>
     </enums>
 
     <enums namespace="GL" start="0x0000" end="0x7FFF" vendor="ARB" comment="Mostly OpenGL 1.0/1.1 enum assignments. Unused ranges should generally remain unused.">
@@ -2731,6 +4126,7 @@
         <enum value="0x0D32" name="GL_MAX_CLIP_PLANES"/>
         <enum value="0x0D32" name="GL_MAX_CLIP_PLANES_IMG"/>
         <enum value="0x0D32" name="GL_MAX_CLIP_DISTANCES" alias="GL_MAX_CLIP_PLANES"/>
+        <enum value="0x0D32" name="GL_MAX_CLIP_DISTANCES_EXT" alias="GL_MAX_CLIP_PLANES"/>
         <enum value="0x0D32" name="GL_MAX_CLIP_DISTANCES_APPLE"/>
         <enum value="0x0D33" name="GL_MAX_TEXTURE_SIZE"/>
         <enum value="0x0D34" name="GL_MAX_PIXEL_MAP_TABLE"/>
@@ -2998,30 +4394,38 @@
         <enum value="0x3000" name="GL_CLIP_PLANE0"/>
         <enum value="0x3000" name="GL_CLIP_PLANE0_IMG"/>
         <enum value="0x3000" name="GL_CLIP_DISTANCE0" alias="GL_CLIP_PLANE0"/>
+        <enum value="0x3000" name="GL_CLIP_DISTANCE0_EXT" alias="GL_CLIP_PLANE0"/>
         <enum value="0x3000" name="GL_CLIP_DISTANCE0_APPLE"/>
         <enum value="0x3001" name="GL_CLIP_PLANE1"/>
         <enum value="0x3001" name="GL_CLIP_PLANE1_IMG"/>
         <enum value="0x3001" name="GL_CLIP_DISTANCE1" alias="GL_CLIP_PLANE1"/>
+        <enum value="0x3001" name="GL_CLIP_DISTANCE1_EXT" alias="GL_CLIP_PLANE1"/>
         <enum value="0x3001" name="GL_CLIP_DISTANCE1_APPLE"/>
         <enum value="0x3002" name="GL_CLIP_PLANE2"/>
         <enum value="0x3002" name="GL_CLIP_PLANE2_IMG"/>
         <enum value="0x3002" name="GL_CLIP_DISTANCE2" alias="GL_CLIP_PLANE2"/>
+        <enum value="0x3002" name="GL_CLIP_DISTANCE2_EXT" alias="GL_CLIP_PLANE2"/>
         <enum value="0x3002" name="GL_CLIP_DISTANCE2_APPLE"/>
         <enum value="0x3003" name="GL_CLIP_PLANE3"/>
         <enum value="0x3003" name="GL_CLIP_PLANE3_IMG"/>
         <enum value="0x3003" name="GL_CLIP_DISTANCE3" alias="GL_CLIP_PLANE3"/>
+        <enum value="0x3003" name="GL_CLIP_DISTANCE3_EXT" alias="GL_CLIP_PLANE3"/>
         <enum value="0x3003" name="GL_CLIP_DISTANCE3_APPLE"/>
         <enum value="0x3004" name="GL_CLIP_PLANE4"/>
         <enum value="0x3004" name="GL_CLIP_PLANE4_IMG"/>
         <enum value="0x3004" name="GL_CLIP_DISTANCE4" alias="GL_CLIP_PLANE4"/>
+        <enum value="0x3004" name="GL_CLIP_DISTANCE4_EXT" alias="GL_CLIP_PLANE4"/>
         <enum value="0x3004" name="GL_CLIP_DISTANCE4_APPLE"/>
         <enum value="0x3005" name="GL_CLIP_PLANE5"/>
         <enum value="0x3005" name="GL_CLIP_PLANE5_IMG"/>
         <enum value="0x3005" name="GL_CLIP_DISTANCE5" alias="GL_CLIP_PLANE5"/>
+        <enum value="0x3005" name="GL_CLIP_DISTANCE5_EXT" alias="GL_CLIP_PLANE5"/>
         <enum value="0x3005" name="GL_CLIP_DISTANCE5_APPLE"/>
         <enum value="0x3006" name="GL_CLIP_DISTANCE6"/>
+        <enum value="0x3006" name="GL_CLIP_DISTANCE6_EXT" alias="GL_CLIP_DISTANCE6"/>
         <enum value="0x3006" name="GL_CLIP_DISTANCE6_APPLE"/>
         <enum value="0x3007" name="GL_CLIP_DISTANCE7"/>
+        <enum value="0x3007" name="GL_CLIP_DISTANCE7_EXT" alias="GL_CLIP_DISTANCE7"/>
         <enum value="0x3007" name="GL_CLIP_DISTANCE7_APPLE"/>
             <unused start="0x3008" end="0x3FFF" comment="Unused for ClipPlaneName"/>
         <enum value="0x4000" name="GL_LIGHT0"/>
@@ -3506,8 +4910,10 @@
         <enum value="0x80EB" name="GL_PHONG_HINT_WIN"/>
         <enum value="0x80EC" name="GL_FOG_SPECULAR_TEXTURE_WIN"/>
         <enum value="0x80ED" name="GL_TEXTURE_INDEX_SIZE_EXT"/>
-        <enum value="0x80EE" name="GL_PARAMETER_BUFFER_ARB"/>
-        <enum value="0x80EF" name="GL_PARAMETER_BUFFER_BINDING_ARB"/>
+        <enum value="0x80EE" name="GL_PARAMETER_BUFFER"/>
+        <enum value="0x80EE" name="GL_PARAMETER_BUFFER_ARB" alias="GL_PARAMETER_BUFFER"/>
+        <enum value="0x80EF" name="GL_PARAMETER_BUFFER_BINDING"/>
+        <enum value="0x80EF" name="GL_PARAMETER_BUFFER_BINDING_ARB" alias="GL_PARAMETER_BUFFER_BINDING"/>
         <enum value="0x80F0" name="GL_CLIP_VOLUME_CLIPPING_HINT_EXT"/>
             <unused start="0x80F1" end="0x810F" vendor="MS"/>
     </enums>
@@ -3955,18 +5361,22 @@
         <enum value="0x825A" name="GL_PROGRAM_PIPELINE_BINDING_EXT"/>
         <enum value="0x825B" name="GL_MAX_VIEWPORTS"/>
         <enum value="0x825B" name="GL_MAX_VIEWPORTS_NV"/>
+        <enum value="0x825B" name="GL_MAX_VIEWPORTS_OES"/>
         <enum value="0x825C" name="GL_VIEWPORT_SUBPIXEL_BITS"/>
         <enum value="0x825C" name="GL_VIEWPORT_SUBPIXEL_BITS_EXT"/>
         <enum value="0x825C" name="GL_VIEWPORT_SUBPIXEL_BITS_NV"/>
+        <enum value="0x825C" name="GL_VIEWPORT_SUBPIXEL_BITS_OES"/>
         <enum value="0x825D" name="GL_VIEWPORT_BOUNDS_RANGE"/>
         <enum value="0x825D" name="GL_VIEWPORT_BOUNDS_RANGE_EXT"/>
         <enum value="0x825D" name="GL_VIEWPORT_BOUNDS_RANGE_NV"/>
+        <enum value="0x825D" name="GL_VIEWPORT_BOUNDS_RANGE_OES"/>
         <enum value="0x825E" name="GL_LAYER_PROVOKING_VERTEX"/>
         <enum value="0x825E" name="GL_LAYER_PROVOKING_VERTEX_EXT"/>
         <enum value="0x825E" name="GL_LAYER_PROVOKING_VERTEX_OES"/>
         <enum value="0x825F" name="GL_VIEWPORT_INDEX_PROVOKING_VERTEX"/>
         <enum value="0x825F" name="GL_VIEWPORT_INDEX_PROVOKING_VERTEX_EXT"/>
         <enum value="0x825F" name="GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV"/>
+        <enum value="0x825F" name="GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES"/>
         <enum value="0x8260" name="GL_UNDEFINED_VERTEX"/>
         <enum value="0x8260" name="GL_UNDEFINED_VERTEX_EXT"/>
         <enum value="0x8260" name="GL_UNDEFINED_VERTEX_OES"/>
@@ -4139,26 +5549,41 @@
              ARB_direct_state_access in February 2015 after determining it
              was not well defined or implementable. -->
             <unused start="0x82EB" vendor="ARB" comment="Reserved. Formerly used for GL_TEXTURE_BINDING."/>
-        <enum value="0x82EC" name="GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB"/>
-        <enum value="0x82ED" name="GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB"/>
-        <enum value="0x82EE" name="GL_VERTICES_SUBMITTED_ARB"/>
-        <enum value="0x82EF" name="GL_PRIMITIVES_SUBMITTED_ARB"/>
-        <enum value="0x82F0" name="GL_VERTEX_SHADER_INVOCATIONS_ARB"/>
-        <enum value="0x82F1" name="GL_TESS_CONTROL_SHADER_PATCHES_ARB"/>
-        <enum value="0x82F2" name="GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB"/>
-        <enum value="0x82F3" name="GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB"/>
-        <enum value="0x82F4" name="GL_FRAGMENT_SHADER_INVOCATIONS_ARB"/>
-        <enum value="0x82F5" name="GL_COMPUTE_SHADER_INVOCATIONS_ARB"/>
-        <enum value="0x82F6" name="GL_CLIPPING_INPUT_PRIMITIVES_ARB"/>
-        <enum value="0x82F7" name="GL_CLIPPING_OUTPUT_PRIMITIVES_ARB"/>
+        <enum value="0x82EC" name="GL_TRANSFORM_FEEDBACK_OVERFLOW"/>
+        <enum value="0x82EC" name="GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB" alias="GL_TRANSFORM_FEEDBACK_OVERFLOW"/>
+        <enum value="0x82ED" name="GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW"/>
+        <enum value="0x82ED" name="GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB" alias="GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW"/>
+        <enum value="0x82EE" name="GL_VERTICES_SUBMITTED"/>
+        <enum value="0x82EE" name="GL_VERTICES_SUBMITTED_ARB" alias="GL_VERTICES_SUBMITTED"/>
+        <enum value="0x82EF" name="GL_PRIMITIVES_SUBMITTED"/>
+        <enum value="0x82EF" name="GL_PRIMITIVES_SUBMITTED_ARB" alias="GL_PRIMITIVES_SUBMITTED"/>
+        <enum value="0x82F0" name="GL_VERTEX_SHADER_INVOCATIONS"/>
+        <enum value="0x82F0" name="GL_VERTEX_SHADER_INVOCATIONS_ARB" alias="GL_VERTEX_SHADER_INVOCATIONS"/>
+        <enum value="0x82F1" name="GL_TESS_CONTROL_SHADER_PATCHES"/>
+        <enum value="0x82F1" name="GL_TESS_CONTROL_SHADER_PATCHES_ARB" alias="GL_TESS_CONTROL_SHADER_PATCHES"/>
+        <enum value="0x82F2" name="GL_TESS_EVALUATION_SHADER_INVOCATIONS"/>
+        <enum value="0x82F2" name="GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB" alias="GL_TESS_EVALUATION_SHADER_INVOCATIONS"/>
+        <enum value="0x82F3" name="GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED"/>
+        <enum value="0x82F3" name="GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB" alias="GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED"/>
+        <enum value="0x82F4" name="GL_FRAGMENT_SHADER_INVOCATIONS"/>
+        <enum value="0x82F4" name="GL_FRAGMENT_SHADER_INVOCATIONS_ARB" alias="GL_FRAGMENT_SHADER_INVOCATIONS"/>
+        <enum value="0x82F5" name="GL_COMPUTE_SHADER_INVOCATIONS"/>
+        <enum value="0x82F5" name="GL_COMPUTE_SHADER_INVOCATIONS_ARB" alias="GL_COMPUTE_SHADER_INVOCATIONS"/>
+        <enum value="0x82F6" name="GL_CLIPPING_INPUT_PRIMITIVES"/>
+        <enum value="0x82F6" name="GL_CLIPPING_INPUT_PRIMITIVES_ARB" alias="GL_CLIPPING_INPUT_PRIMITIVES"/>
+        <enum value="0x82F7" name="GL_CLIPPING_OUTPUT_PRIMITIVES"/>
+        <enum value="0x82F7" name="GL_CLIPPING_OUTPUT_PRIMITIVES_ARB" alias="GL_CLIPPING_OUTPUT_PRIMITIVES"/>
         <enum value="0x82F8" name="GL_SPARSE_BUFFER_PAGE_SIZE_ARB"/>
         <enum value="0x82F9" name="GL_MAX_CULL_DISTANCES"/>
+        <enum value="0x82F9" name="GL_MAX_CULL_DISTANCES_EXT" alias="GL_MAX_CULL_DISTANCES"/>
         <enum value="0x82FA" name="GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES"/>
+        <enum value="0x82FA" name="GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT" alias="GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES"/>
         <enum value="0x82FB" name="GL_CONTEXT_RELEASE_BEHAVIOR"/>
         <enum value="0x82FB" name="GL_CONTEXT_RELEASE_BEHAVIOR_KHR"/>
         <enum value="0x82FC" name="GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH"/>
         <enum value="0x82FC" name="GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR"/>
-            <unused start="0x82FD" end="0x830F" vendor="ARB"/>
+        <enum value="0x82FD" name="GL_ROBUST_GPU_TIMEOUT_MS_KHR" comment="Reserved for future"/>
+            <unused start="0x82FE" end="0x830F" vendor="ARB"/>
     </enums>
 
     <enums namespace="GL" start="0x8310" end="0x832F" vendor="SGI">
@@ -4354,7 +5779,9 @@
         <enum value="0x83F9" name="GL_PERFQUERY_DONOT_FLUSH_INTEL"/>
         <enum value="0x83FA" name="GL_PERFQUERY_FLUSH_INTEL"/>
         <enum value="0x83FB" name="GL_PERFQUERY_WAIT_INTEL"/>
-            <unused start="0x83FC" end="0x83FE" vendor="INTEL"/>
+        <enum value="0x83FC" name="GL_BLACKHOLE_RENDER_INTEL"/>
+            <unused start="0x83FD" vendor="INTEL"/>
+        <enum value="0x83FE" name="GL_CONSERVATIVE_RASTERIZATION_INTEL"/>
         <enum value="0x83FF" name="GL_TEXTURE_MEMORY_LAYOUT_INTEL"/>
     </enums>
 
@@ -4635,8 +6062,10 @@
             <unused start="0x84FB" end="0x84FC" vendor="NV"/>
         <enum value="0x84FD" name="GL_MAX_TEXTURE_LOD_BIAS"/>
         <enum value="0x84FD" name="GL_MAX_TEXTURE_LOD_BIAS_EXT"/>
-        <enum value="0x84FE" name="GL_TEXTURE_MAX_ANISOTROPY_EXT"/>
-        <enum value="0x84FF" name="GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT"/>
+        <enum value="0x84FE" name="GL_TEXTURE_MAX_ANISOTROPY"/>
+        <enum value="0x84FE" name="GL_TEXTURE_MAX_ANISOTROPY_EXT" alias="GL_TEXTURE_MAX_ANISOTROPY"/>
+        <enum value="0x84FF" name="GL_MAX_TEXTURE_MAX_ANISOTROPY"/>
+        <enum value="0x84FF" name="GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" alias="GL_MAX_TEXTURE_MAX_ANISOTROPY"/>
         <enum value="0x8500" name="GL_TEXTURE_FILTER_CONTROL"/>
         <enum value="0x8500" name="GL_TEXTURE_FILTER_CONTROL_EXT"/>
         <enum value="0x8501" name="GL_TEXTURE_LOD_BIAS"/>
@@ -5338,7 +6767,7 @@
         <enum value="0x875C" name="GL_PROXY_TEXTURE_2D_STACK_MESAX"/>
         <enum value="0x875D" name="GL_TEXTURE_1D_STACK_BINDING_MESAX"/>
         <enum value="0x875E" name="GL_TEXTURE_2D_STACK_BINDING_MESAX"/>
-            <unused start="0x875F" vendor="MESA"/>
+        <enum value="0x875F" name="GL_PROGRAM_BINARY_FORMAT_MESA"/>
     </enums>
 
     <enums namespace="GL" start="0x8760" end="0x883F" vendor="AMD">
@@ -5941,16 +7370,20 @@
         <enum value="0x88EB" name="GL_PIXEL_PACK_BUFFER"/>
         <enum value="0x88EB" name="GL_PIXEL_PACK_BUFFER_ARB"/>
         <enum value="0x88EB" name="GL_PIXEL_PACK_BUFFER_EXT"/>
+        <enum value="0x88EB" name="GL_PIXEL_PACK_BUFFER_NV"/>
         <enum value="0x88EC" name="GL_PIXEL_UNPACK_BUFFER"/>
         <enum value="0x88EC" name="GL_PIXEL_UNPACK_BUFFER_ARB"/>
         <enum value="0x88EC" name="GL_PIXEL_UNPACK_BUFFER_EXT"/>
+        <enum value="0x88EC" name="GL_PIXEL_UNPACK_BUFFER_NV"/>
         <enum value="0x88ED" name="GL_PIXEL_PACK_BUFFER_BINDING"/>
         <enum value="0x88ED" name="GL_PIXEL_PACK_BUFFER_BINDING_ARB"/>
         <enum value="0x88ED" name="GL_PIXEL_PACK_BUFFER_BINDING_EXT"/>
+        <enum value="0x88ED" name="GL_PIXEL_PACK_BUFFER_BINDING_NV"/>
         <enum value="0x88EE" name="GL_ETC1_SRGB8_NV"/>
         <enum value="0x88EF" name="GL_PIXEL_UNPACK_BUFFER_BINDING"/>
         <enum value="0x88EF" name="GL_PIXEL_UNPACK_BUFFER_BINDING_ARB"/>
         <enum value="0x88EF" name="GL_PIXEL_UNPACK_BUFFER_BINDING_EXT"/>
+        <enum value="0x88EF" name="GL_PIXEL_UNPACK_BUFFER_BINDING_NV"/>
         <enum value="0x88F0" name="GL_DEPTH24_STENCIL8"/>
         <enum value="0x88F0" name="GL_DEPTH24_STENCIL8_EXT"/>
         <enum value="0x88F0" name="GL_DEPTH24_STENCIL8_OES"/>
@@ -6397,6 +7830,9 @@
         <enum value="0x8BB5" name="GL_VERTEX_PROGRAM_CALLBACK_MESA"/>
         <enum value="0x8BB6" name="GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA"/>
         <enum value="0x8BB7" name="GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA"/>
+        <enum value="0x8BB8" name="GL_TILE_RASTER_ORDER_FIXED_MESA"/>
+        <enum value="0x8BB9" name="GL_TILE_RASTER_ORDER_INCREASING_X_MESA"/>
+        <enum value="0x8BBA" name="GL_TILE_RASTER_ORDER_INCREASING_Y_MESA"/>
     </enums>
 
     <enums namespace="GL" start="0x8BC0" end="0x8BFF" vendor="QCOM" comment="Reassigned from AMD to QCOM">
@@ -6421,7 +7857,13 @@
         <enum value="0x8BDC" name="GL_STATE_RESTORE"/>
             <unused start="0x8BDD" end="0x8BE6" vendor="QCOM"/>
         <enum value="0x8BE7" name="GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT"/>
-            <unused start="0x8BE8" end="0x8BFF" vendor="QCOM"/>
+            <unused start="0x8BE8" end="0x8BEF" vendor="QCOM"/>
+        <enum value="0x8BFA" name="GL_TEXTURE_PROTECTED_EXT"/>
+        <enum value="0x8BFB" name="GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM"/>
+        <enum value="0x8BFC" name="GL_TEXTURE_FOVEATED_MIN_PIXEL_DENSITY_QCOM"/>
+        <enum value="0x8BFD" name="GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM"/>
+        <enum value="0x8BFE" name="GL_TEXTURE_FOVEATED_NUM_FOCAL_POINTS_QUERY_QCOM"/>
+        <enum value="0x8BFF" name="GL_FRAMEBUFFER_INCOMPLETE_FOVEATION_QCOM"/>
     </enums>
 
     <enums namespace="GL" start="0x8C00" end="0x8C0F" vendor="IMG">
@@ -6631,11 +8073,12 @@
         <enum value="0x8C93" name="GL_ATC_RGBA_EXPLICIT_ALPHA_AMD"/>
             <unused start="0x8C94" end="0x8C9F" vendor="QCOM"/>
     </enums>
-
     <enums namespace="GL" start="0x8CA0" end="0x8CAF" vendor="ARB">
         <enum value="0x8CA0" name="GL_POINT_SPRITE_COORD_ORIGIN"/>
         <enum value="0x8CA1" name="GL_LOWER_LEFT"/>
+        <enum value="0x8CA1" name="GL_LOWER_LEFT_EXT" alias="GL_LOWER_LEFT"/>
         <enum value="0x8CA2" name="GL_UPPER_LEFT"/>
+        <enum value="0x8CA2" name="GL_UPPER_LEFT_EXT" alias="GL_UPPER_LEFT"/>
         <enum value="0x8CA3" name="GL_STENCIL_BACK_REF"/>
         <enum value="0x8CA4" name="GL_STENCIL_BACK_VALUE_MASK"/>
         <enum value="0x8CA5" name="GL_STENCIL_BACK_WRITEMASK"/>
@@ -7116,7 +8559,8 @@
         <enum value="0x8E18" name="GL_QUERY_NO_WAIT_INVERTED"/>
         <enum value="0x8E19" name="GL_QUERY_BY_REGION_WAIT_INVERTED"/>
         <enum value="0x8E1A" name="GL_QUERY_BY_REGION_NO_WAIT_INVERTED"/>
-        <enum value="0x8E1B" name="GL_POLYGON_OFFSET_CLAMP_EXT"/>
+        <enum value="0x8E1B" name="GL_POLYGON_OFFSET_CLAMP"/>
+        <enum value="0x8E1B" name="GL_POLYGON_OFFSET_CLAMP_EXT" alias="GL_POLYGON_OFFSET_CLAMP"/>
             <unused start="0x8E1C" end="0x8E1D" vendor="NV"/>
         <enum value="0x8E1E" name="GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS"/>
         <enum value="0x8E1E" name="GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT"/>
@@ -7288,12 +8732,16 @@
             <unused start="0x8E8B" vendor="NV"/>
         <enum value="0x8E8C" name="GL_COMPRESSED_RGBA_BPTC_UNORM"/>
         <enum value="0x8E8C" name="GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"/>
+        <enum value="0x8E8C" name="GL_COMPRESSED_RGBA_BPTC_UNORM_EXT"/>
         <enum value="0x8E8D" name="GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM"/>
         <enum value="0x8E8D" name="GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"/>
+        <enum value="0x8E8D" name="GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT"/>
         <enum value="0x8E8E" name="GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT"/>
         <enum value="0x8E8E" name="GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"/>
+        <enum value="0x8E8E" name="GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT"/>
         <enum value="0x8E8F" name="GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT"/>
         <enum value="0x8E8F" name="GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"/>
+        <enum value="0x8E8F" name="GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT"/>
     </enums>
 
     <enums namespace="GL" start="0x8E90" end="0x8E9F" vendor="QNX" comment="For QNX_texture_tiling, QNX_complex_polygon, QNX_stippled_lines (Khronos bug 696)">
@@ -7321,7 +8769,14 @@
         <enum value="0x8ED5" name="GL_COVERAGE_ALL_FRAGMENTS_NV"/>
         <enum value="0x8ED6" name="GL_COVERAGE_EDGE_FRAGMENTS_NV"/>
         <enum value="0x8ED7" name="GL_COVERAGE_AUTOMATIC_NV"/>
-            <unused start="0x8ED8" end="0x8F1C" vendor="NV"/>
+            <unused start="0x8ED8" end="0x8F0F" vendor="NV"/>
+        <enum value="0x8F10" name="GL_INCLUSIVE_EXT"/>
+        <enum value="0x8F11" name="GL_EXCLUSIVE_EXT"/>
+        <enum value="0x8F12" name="GL_WINDOW_RECTANGLE_EXT"/>
+        <enum value="0x8F13" name="GL_WINDOW_RECTANGLE_MODE_EXT"/>
+        <enum value="0x8F14" name="GL_MAX_WINDOW_RECTANGLES_EXT"/>
+        <enum value="0x8F15" name="GL_NUM_WINDOW_RECTANGLES_EXT"/>
+            <unused start="0x8F16" end="0x8F1C" vendor="NV"/>
         <enum value="0x8F1D" name="GL_BUFFER_GPU_ADDRESS_NV"/>
         <enum value="0x8F1E" name="GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV"/>
         <enum value="0x8F1F" name="GL_ELEMENT_ARRAY_UNIFIED_NV"/>
@@ -7409,7 +8864,9 @@
         <enum value="0x8F65" name="GL_FETCH_PER_SAMPLE_ARM"/>
         <enum value="0x8F66" name="GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM"/>
         <enum value="0x8F67" name="GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT"/>
-            <unused start="0x8F68" end="0x8F6F" vendor="ARM"/>
+            <unused start="0x8F68" vendor="ARM"/>
+        <enum value="0x8F69" name="GL_TEXTURE_ASTC_DECODE_PRECISION_EXT"/>
+            <unused start="0x8F6A" end="0x8F6F" vendor="ARM"/>
     </enums>
 
     <enums namespace="GL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with EGL.">
@@ -7455,7 +8912,7 @@
             <unused start="0x8FBC" vendor="QCOM"/>
         <enum value="0x8FBD" name="GL_SR8_EXT"/>
         <enum value="0x8FBE" name="GL_SRG8_EXT"/>
-            <unused start="0x8FBF" vendor="QCOM"/>
+        <enum value="0x8FBF" name="GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT"/>
     </enums>
 
     <enums namespace="GL" start="0x8FC0" end="0x8FDF" vendor="VIV" comment="For Frido Garritsen, bug 4526">
@@ -7897,7 +9354,10 @@
         <enum value="0x9139" name="GL_CUBIC_IMG"/>
         <enum value="0x913A" name="GL_CUBIC_MIPMAP_NEAREST_IMG"/>
         <enum value="0x913B" name="GL_CUBIC_MIPMAP_LINEAR_IMG"/>
-            <unused start="0x913C" end="0x913F" vendor="IMG"/>
+        <enum value="0x913C" name="GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG"/>
+        <enum value="0x913D" name="GL_NUM_DOWNSAMPLE_SCALES_IMG"/>
+        <enum value="0x913E" name="GL_DOWNSAMPLE_SCALES_IMG"/>
+        <enum value="0x913F" name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG"/>
     </enums>
 
     <enums namespace="GL" start="0x9140" end="0x923F" vendor="AMD" comment="Khronos bugs 5899, 6004">
@@ -7994,9 +9454,13 @@
         <enum value="0x91A9" name="GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT"/>
         <enum value="0x91AA" name="GL_NUM_SPARSE_LEVELS_ARB"/>
         <enum value="0x91AA" name="GL_NUM_SPARSE_LEVELS_EXT"/>
-            <unused start="0x91AB" end="0x91AF" vendor="AMD"/>
-        <enum value="0x91B0" name="GL_MAX_SHADER_COMPILER_THREADS_ARB"/>
-        <enum value="0x91B1" name="GL_COMPLETION_STATUS_ARB"/>
+            <unused start="0x91AB" end="0x91AD" vendor="AMD"/>
+        <enum value="0x91AE" name="GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD"/>
+        <enum value="0x91AF" name="GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD"/>
+        <enum value="0x91B0" name="GL_MAX_SHADER_COMPILER_THREADS_KHR"/>
+        <enum value="0x91B0" name="GL_MAX_SHADER_COMPILER_THREADS_ARB" alias="GL_MAX_SHADER_COMPILER_THREADS_KHR"/>
+        <enum value="0x91B1" name="GL_COMPLETION_STATUS_KHR"/>
+        <enum value="0x91B1" name="GL_COMPLETION_STATUS_ARB" alias="GL_COMPLETION_STATUS_KHR"/>
             <unused start="0x91B2" end="0x91B8" vendor="AMD"/>
         <enum value="0x91B9" name="GL_COMPUTE_SHADER"/>
             <unused start="0x91BA" vendor="AMD"/>
@@ -8006,7 +9470,17 @@
         <enum value="0x91BE" name="GL_MAX_COMPUTE_WORK_GROUP_COUNT"/>
         <enum value="0x91BF" name="GL_MAX_COMPUTE_WORK_GROUP_SIZE"/>
         <enum value="0x91BF" name="GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB" alias="GL_MAX_COMPUTE_WORK_GROUP_SIZE"/>
-            <unused start="0x91C0" end="0x923F" vendor="AMD"/>
+            <unused start="0x91C0" end="0x91C4" vendor="AMD"/>
+        <enum value="0x91C5" name="GL_FLOAT16_MAT2_AMD"/>
+        <enum value="0x91C6" name="GL_FLOAT16_MAT3_AMD"/>
+        <enum value="0x91C7" name="GL_FLOAT16_MAT4_AMD"/>
+        <enum value="0x91C8" name="GL_FLOAT16_MAT2x3_AMD"/>
+        <enum value="0x91C9" name="GL_FLOAT16_MAT2x4_AMD"/>
+        <enum value="0x91CA" name="GL_FLOAT16_MAT3x2_AMD"/>
+        <enum value="0x91CB" name="GL_FLOAT16_MAT3x4_AMD"/>
+        <enum value="0x91CC" name="GL_FLOAT16_MAT4x2_AMD"/>
+        <enum value="0x91CD" name="GL_FLOAT16_MAT4x3_AMD"/>
+            <unused start="0x91CE" end="0x923F" vendor="AMD"/>
     </enums>
 
     <enums namespace="GL" start="0x9240" end="0x924F" vendor="WEBGL" comment="Khronos bug 6473,6884">
@@ -8138,12 +9612,16 @@
         <enum value="0x92B2" name="GL_PLUS_CLAMPED_ALPHA_NV"/>
         <enum value="0x92B3" name="GL_MINUS_CLAMPED_NV"/>
         <enum value="0x92B4" name="GL_INVERT_OVG_NV"/>
-            <unused start="0x92B5" end="0x92BD" vendor="NV"/>
+            <unused start="0x92B5" end="0x92B9" vendor="NV"/>
+        <enum value="0x92BA" name="GL_MAX_LGPU_GPUS_NVX"/>
+        <enum value="0x92BA" name="GL_MULTICAST_GPUS_NV"/>
+        <enum value="0x92BB" name="GL_PURGED_CONTEXT_RESET_NV"/>
+            <unused start="0x92BC" end="0x92BD" vendor="NV"/>
         <enum value="0x92BE" name="GL_PRIMITIVE_BOUNDING_BOX_ARB"/>
         <enum value="0x92BE" name="GL_PRIMITIVE_BOUNDING_BOX"/>
         <enum value="0x92BE" name="GL_PRIMITIVE_BOUNDING_BOX_EXT"/>
         <enum value="0x92BE" name="GL_PRIMITIVE_BOUNDING_BOX_OES"/>
-            <unused start="0x92BF" vendor="NV"/>
+        <enum value="0x92BF" name="GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV"/>
         <enum value="0x92C0" name="GL_ATOMIC_COUNTER_BUFFER"/>
         <enum value="0x92C1" name="GL_ATOMIC_COUNTER_BUFFER_BINDING"/>
         <enum value="0x92C2" name="GL_ATOMIC_COUNTER_BUFFER_START"/>
@@ -8301,15 +9779,35 @@
         <enum value="0x934A" name="GL_LOCATION_COMPONENT"/>
         <enum value="0x934B" name="GL_TRANSFORM_FEEDBACK_BUFFER_INDEX"/>
         <enum value="0x934C" name="GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE"/>
-            <unused start="0x934D" end="0x935B" vendor="NV"/>
+        <enum value="0x934D" name="GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV"/>
+        <enum value="0x934E" name="GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV"/>
+        <enum value="0x934F" name="GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV"/>
+        <enum value="0x9350" name="GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV"/>
+        <enum value="0x9351" name="GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV"/>
+        <enum value="0x9352" name="GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV"/>
+        <enum value="0x9353" name="GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV"/>
+        <enum value="0x9354" name="GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV"/>
+        <enum value="0x9355" name="GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV"/>
+        <enum value="0x9356" name="GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV"/>
+        <enum value="0x9357" name="GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV"/>
+        <enum value="0x9358" name="GL_VIEWPORT_SWIZZLE_X_NV"/>
+        <enum value="0x9359" name="GL_VIEWPORT_SWIZZLE_Y_NV"/>
+        <enum value="0x935A" name="GL_VIEWPORT_SWIZZLE_Z_NV"/>
+        <enum value="0x935B" name="GL_VIEWPORT_SWIZZLE_W_NV"/>
         <enum value="0x935C" name="GL_CLIP_ORIGIN"/>
+        <enum value="0x935C" name="GL_CLIP_ORIGIN_EXT" alias="GL_CLIP_ORIGIN"/>
         <enum value="0x935D" name="GL_CLIP_DEPTH_MODE"/>
+        <enum value="0x935D" name="GL_CLIP_DEPTH_MODE_EXT" alias="GL_CLIP_DEPTH_MODE"/>
         <enum value="0x935E" name="GL_NEGATIVE_ONE_TO_ONE"/>
+        <enum value="0x935E" name="GL_NEGATIVE_ONE_TO_ONE_EXT" alias="GL_NEGATIVE_ONE_TO_ONE"/>
         <enum value="0x935F" name="GL_ZERO_TO_ONE"/>
+        <enum value="0x935F" name="GL_ZERO_TO_ONE_EXT" alias="GL_ZERO_TO_ONE"/>
             <unused start="0x9360" end="0x9364" vendor="NV"/>
         <enum value="0x9365" name="GL_CLEAR_TEXTURE"/>
         <enum value="0x9366" name="GL_TEXTURE_REDUCTION_MODE_ARB"/>
+        <enum value="0x9366" name="GL_TEXTURE_REDUCTION_MODE_EXT" alias="GL_TEXTURE_REDUCTION_MODE_ARB"/>
         <enum value="0x9367" name="GL_WEIGHTED_AVERAGE_ARB"/>
+        <enum value="0x9367" name="GL_WEIGHTED_AVERAGE_EXT" alias="GL_WEIGHTED_AVERAGE_ARB"/>
         <enum value="0x9368" name="GL_FONT_GLYPHS_AVAILABLE_NV"/>
         <enum value="0x9369" name="GL_FONT_TARGET_UNAVAILABLE_NV"/>
         <enum value="0x936A" name="GL_FONT_UNAVAILABLE_NV"/>
@@ -8327,7 +9825,10 @@
         <enum value="0x9379" name="GL_CONSERVATIVE_RASTER_DILATE_NV"/>
         <enum value="0x937A" name="GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV"/>
         <enum value="0x937B" name="GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV"/>
-            <unused start="0x937C" end="0x937F" vendor="NV"/>
+        <enum value="0x937C" name="GL_VIEWPORT_POSITION_W_SCALE_NV"/>
+        <enum value="0x937D" name="GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV"/>
+        <enum value="0x937E" name="GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV"/>
+            <unused start="0x937F" vendor="NV"/>
     </enums>
 
     <enums namespace="GL" start="0x9380" end="0x939F" vendor="ARB">
@@ -8464,14 +9965,70 @@
     </enums>
 
     <enums namespace="GL" start="0x9530" end="0x962F" vendor="NV" comment="Khronos bug 12977">
-            <unused start="0x9530" end="0x962F" vendor="NV"/>
+        <enum value="0x9530" name="GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT"/>
+        <enum value="0x9531" name="GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT"/>
+            <unused start="0x9532" end="0x953F" vendor="NV"/>
+        <enum value="0x9540" name="GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV"/>
+            <unused start="0x9541" vendor="NV"/>
+        <enum value="0x9542" name="GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV"/>
+            <unused start="0x9543" vendor="NV"/>
+        <enum value="0x9544" name="GL_QUERY_RESOURCE_SYS_RESERVED_NV"/>
+        <enum value="0x9545" name="GL_QUERY_RESOURCE_TEXTURE_NV"/>
+        <enum value="0x9546" name="GL_QUERY_RESOURCE_RENDERBUFFER_NV"/>
+        <enum value="0x9547" name="GL_QUERY_RESOURCE_BUFFEROBJECT_NV"/>
+        <enum value="0x9548" name="GL_PER_GPU_STORAGE_NV"/>
+        <enum value="0x9549" name="GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV"/>
+            <unused start="0x954A" end="0x954C" vendor="NV"/>
+        <enum value="0x954D" name="GL_CONSERVATIVE_RASTER_MODE_NV"/>
+        <enum value="0x954E" name="GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV"/>
+        <enum value="0x954F" name="GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV"/>
+        <enum value="0x9550" name="GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV"/>
+        <enum value="0x9551" name="GL_SHADER_BINARY_FORMAT_SPIR_V"/>
+        <enum value="0x9551" name="GL_SHADER_BINARY_FORMAT_SPIR_V_ARB" alias="GL_SHADER_BINARY_FORMAT_SPIR_V"/>
+        <enum value="0x9552" name="GL_SPIR_V_BINARY"/>
+        <enum value="0x9552" name="GL_SPIR_V_BINARY_ARB" alias="GL_SPIR_V_BINARY"/>
+        <enum value="0x9553" name="GL_SPIR_V_EXTENSIONS"/>
+        <enum value="0x9554" name="GL_NUM_SPIR_V_EXTENSIONS"/>
+            <unused start="0x9555" end="0x9557" vendor="NV"/>
+        <enum value="0x9558" name="GL_RENDER_GPU_MASK_NV"/>
+            <unused start="0x9559" end="0x957F" vendor="NV"/>
+        <enum value="0x9580" name="GL_TEXTURE_TILING_EXT"/>
+        <enum value="0x9581" name="GL_DEDICATED_MEMORY_OBJECT_EXT"/>
+        <enum value="0x9582" name="GL_NUM_TILING_TYPES_EXT"/>
+        <enum value="0x9583" name="GL_TILING_TYPES_EXT"/>
+        <enum value="0x9584" name="GL_OPTIMAL_TILING_EXT"/>
+        <enum value="0x9585" name="GL_LINEAR_TILING_EXT"/>
+        <enum value="0x9586" name="GL_HANDLE_TYPE_OPAQUE_FD_EXT"/>
+        <enum value="0x9587" name="GL_HANDLE_TYPE_OPAQUE_WIN32_EXT"/>
+        <enum value="0x9588" name="GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT"/>
+        <enum value="0x9589" name="GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT"/>
+        <enum value="0x958A" name="GL_HANDLE_TYPE_D3D12_RESOURCE_EXT"/>
+        <enum value="0x958B" name="GL_HANDLE_TYPE_D3D11_IMAGE_EXT"/>
+        <enum value="0x958C" name="GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT"/>
+        <enum value="0x958D" name="GL_LAYOUT_GENERAL_EXT"/>
+        <enum value="0x958E" name="GL_LAYOUT_COLOR_ATTACHMENT_EXT"/>
+        <enum value="0x958F" name="GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT"/>
+        <enum value="0x9590" name="GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT"/>
+        <enum value="0x9591" name="GL_LAYOUT_SHADER_READ_ONLY_EXT"/>
+        <enum value="0x9592" name="GL_LAYOUT_TRANSFER_SRC_EXT"/>
+        <enum value="0x9593" name="GL_LAYOUT_TRANSFER_DST_EXT"/>
+        <enum value="0x9594" name="GL_HANDLE_TYPE_D3D12_FENCE_EXT"/>
+        <enum value="0x9595" name="GL_D3D12_FENCE_VALUE_EXT"/>
+        <enum value="0x9596" name="GL_NUM_DEVICE_UUIDS_EXT"/>
+        <enum value="0x9597" name="GL_DEVICE_UUID_EXT"/>
+        <enum value="0x9598" name="GL_DRIVER_UUID_EXT"/>
+        <enum value="0x9599" name="GL_DEVICE_LUID_EXT"/>
+        <enum value="0x959A" name="GL_DEVICE_NODE_MASK_EXT"/>
+        <enum value="0x959B" name="GL_PROTECTED_MEMORY_OBJECT_EXT"/>
+            <unused start="0x959C" end="0x962F" vendor="NV"/>
     </enums>
 
     <enums namespace="GL" start="0x9630" end="0x963F" vendor="Oculus" comment="Email from Cass Everitt">
         <enum value="0x9630" name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR"/>
         <enum value="0x9631" name="GL_MAX_VIEWS_OVR"/>
         <enum value="0x9632" name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR"/>
-            <unused start="0x9633" end="0x963F" vendor="Oculus"/>
+        <enum value="0x9633" name="GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR"/>
+            <unused start="0x9634" end="0x963F" vendor="Oculus"/>
     </enums>
 
     <enums namespace="GL" start="0x9640" end="0x964F" vendor="Mediatek" comment="Khronos bug 14294">
@@ -8481,7 +10038,20 @@
     </enums>
 
     <enums namespace="GL" start="0x9650" end="0x968F" vendor="IMG" comment="Khronos bug 14977">
-            <unused start="0x9650" end="0x968F" vendor="IMG"/>
+        <enum value="0x9650" name="GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT"/>
+        <enum value="0x9651" name="GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT"/>
+        <enum value="0x9652" name="GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT"/>
+            <unused start="0x9653" end="0x968F" vendor="IMG"/>
+    </enums>
+
+    <enums namespace="GL" start="0x9690" end="0x969F" vendor="ANGLE" comment="Khronos bug 15423">
+            <unused start="0x9690" end="0x969F" vendor="ANGLE"/>
+    </enums>
+
+    <enums namespace="GL" start="0x96A0" end="0x96AF" vendor="Qualcomm" comment="contact Maurice Ribble">
+            <unused start="0x96A0" end="0x96A1" vendor="Qualcomm"/>
+        <enum value="0x96A2" name="GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM"/>
+            <unused start="0x96A3" end="0x96AF" vendor="Qualcomm"/>
     </enums>
 
 <!-- Enums reservable for future use. To reserve a new range, allocate one
@@ -8493,8 +10063,8 @@
      file) File requests in the Khronos Bugzilla, OpenGL project, Registry
      component. -->
 
-    <enums namespace="GL" start="0x9690" end="99999" vendor="ARB" comment="RESERVED FOR FUTURE ALLOCATIONS BY KHRONOS">
-        <unused start="0x9690" end="99999" comment="RESERVED"/>
+    <enums namespace="GL" start="0x96B0" end="99999" vendor="ARB" comment="RESERVED FOR FUTURE ALLOCATIONS BY KHRONOS">
+        <unused start="0x96B0" end="99999" comment="RESERVED"/>
     </enums>
 
 <!-- Historical large block allocations, all unused except (in older days) by IBM -->
@@ -8655,15 +10225,19 @@
         </command>
         <command>
             <proto>void <name>glAlphaFuncx</name></proto>
-            <param><ptype>GLenum</ptype> <name>func</name></param>
+            <param group="AlphaFunction"><ptype>GLenum</ptype> <name>func</name></param>
             <param><ptype>GLfixed</ptype> <name>ref</name></param>
         </command>
         <command>
             <proto>void <name>glAlphaFuncxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>func</name></param>
+            <param group="AlphaFunction"><ptype>GLenum</ptype> <name>func</name></param>
             <param group="ClampedFixed"><ptype>GLfixed</ptype> <name>ref</name></param>
         </command>
         <command>
+            <proto>void <name>glAlphaToCoverageDitherControlNV</name></proto>
+            <param><ptype>GLenum</ptype> <name>mode</name></param>
+        </command>
+        <command>
             <proto>void <name>glApplyFramebufferAttachmentCMAAINTEL</name></proto>
         </command>
         <command>
@@ -8671,6 +10245,12 @@
             <param group="LightTextureModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
         </command>
         <command>
+            <proto><ptype>GLboolean</ptype> <name>glAcquireKeyedMutexWin32EXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>key</name></param>
+            <param><ptype>GLuint</ptype> <name>timeout</name></param>
+        </command>
+        <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glAreProgramsResidentNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
             <param len="n">const <ptype>GLuint</ptype> *<name>programs</name></param>
@@ -8762,7 +10342,7 @@
         </command>
         <command>
             <proto>void <name>glBeginQuery</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <glx type="render" opcode="231"/>
         </command>
@@ -8774,27 +10354,28 @@
         </command>
         <command>
             <proto>void <name>glBeginQueryEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
         </command>
         <command>
             <proto>void <name>glBeginQueryIndexed</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
         </command>
         <command>
             <proto>void <name>glBeginTransformFeedback</name></proto>
-            <param><ptype>GLenum</ptype> <name>primitiveMode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>primitiveMode</name></param>
+            <glx type="render" opcode="357"/>
         </command>
         <command>
             <proto>void <name>glBeginTransformFeedbackEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>primitiveMode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>primitiveMode</name></param>
             <alias name="glBeginTransformFeedback"/>
         </command>
         <command>
             <proto>void <name>glBeginTransformFeedbackNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>primitiveMode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>primitiveMode</name></param>
             <alias name="glBeginTransformFeedback"/>
         </command>
         <command>
@@ -8830,34 +10411,35 @@
         </command>
         <command>
             <proto>void <name>glBindBufferBase</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
+            <glx type="render" opcode="356"/>
         </command>
         <command>
             <proto>void <name>glBindBufferBaseEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <alias name="glBindBufferBase"/>
         </command>
         <command>
             <proto>void <name>glBindBufferBaseNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <alias name="glBindBufferBase"/>
         </command>
         <command>
             <proto>void <name>glBindBufferOffsetEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
         </command>
         <command>
             <proto>void <name>glBindBufferOffsetNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
@@ -8865,15 +10447,16 @@
         </command>
         <command>
             <proto>void <name>glBindBufferRange</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <glx type="render" opcode="355"/>
         </command>
         <command>
             <proto>void <name>glBindBufferRangeEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
@@ -8882,7 +10465,7 @@
         </command>
         <command>
             <proto>void <name>glBindBufferRangeNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
@@ -8891,14 +10474,14 @@
         </command>
         <command>
             <proto>void <name>glBindBuffersBase</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>first</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>buffers</name></param>
         </command>
         <command>
             <proto>void <name>glBindBuffersRange</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>first</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>buffers</name></param>
@@ -8951,7 +10534,7 @@
         </command>
         <command>
             <proto>void <name>glBindFramebufferOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
         </command>
         <command>
@@ -8961,8 +10544,8 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>layered</name></param>
             <param><ptype>GLint</ptype> <name>layer</name></param>
-            <param><ptype>GLenum</ptype> <name>access</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="BufferAccessARB"><ptype>GLenum</ptype> <name>access</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>format</name></param>
         </command>
         <command>
             <proto>void <name>glBindImageTextureEXT</name></proto>
@@ -8971,7 +10554,7 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>layered</name></param>
             <param><ptype>GLint</ptype> <name>layer</name></param>
-            <param><ptype>GLenum</ptype> <name>access</name></param>
+            <param group="BufferAccessARB"><ptype>GLenum</ptype> <name>access</name></param>
             <param><ptype>GLint</ptype> <name>format</name></param>
         </command>
         <command>
@@ -9035,7 +10618,7 @@
         </command>
         <command>
             <proto>void <name>glBindRenderbufferOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
         </command>
         <command>
@@ -9086,7 +10669,7 @@
         </command>
         <command>
             <proto>void <name>glBindTransformFeedback</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BindTransformFeedbackTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
         </command>
         <command>
@@ -9262,7 +10845,7 @@
         </command>
         <command>
             <proto>void <name>glBlendEquation</name></proto>
-            <param group="BlendEquationMode"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
             <glx type="render" opcode="4097"/>
         </command>
         <command>
@@ -9274,12 +10857,12 @@
         <command>
             <proto>void <name>glBlendEquationIndexedAMD</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
             <alias name="glBlendEquationi"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparate</name></proto>
@@ -9297,69 +10880,69 @@
         <command>
             <proto>void <name>glBlendEquationSeparateIndexedAMD</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
             <alias name="glBlendEquationSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparateOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparatei</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparateiARB</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
             <alias name="glBlendEquationSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparateiEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
             <alias name="glBlendEquationSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationSeparateiOES</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>modeRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>modeAlpha</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeRGB</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>modeAlpha</name></param>
             <alias name="glBlendEquationSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationi</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
         </command>
         <command>
             <proto>void <name>glBlendEquationiARB</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
             <alias name="glBlendEquationi"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationiEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
             <alias name="glBlendEquationi"/>
         </command>
         <command>
             <proto>void <name>glBlendEquationiOES</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="BlendEquationModeEXT"><ptype>GLenum</ptype> <name>mode</name></param>
             <alias name="glBlendEquationi"/>
         </command>
         <command>
             <proto>void <name>glBlendFunc</name></proto>
-            <param group="BlendingFactorSrc"><ptype>GLenum</ptype> <name>sfactor</name></param>
-            <param group="BlendingFactorDest"><ptype>GLenum</ptype> <name>dfactor</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactor</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactor</name></param>
             <glx type="render" opcode="160"/>
         </command>
         <command>
@@ -9371,106 +10954,106 @@
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparate</name></proto>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
             <glx type="render" opcode="4134"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateEXT</name></proto>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
             <alias name="glBlendFuncSeparate"/>
             <glx type="render" opcode="4134"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateINGR</name></proto>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
-            <param group="BlendFuncSeparateParameterEXT"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>sfactorAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dfactorAlpha</name></param>
             <alias name="glBlendFuncSeparate"/>
             <glx type="render" opcode="4134"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateIndexedAMD</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
             <alias name="glBlendFuncSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparatei</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateiARB</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
             <alias name="glBlendFuncSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateiEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
             <alias name="glBlendFuncSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendFuncSeparateiOES</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>srcRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>dstRGB</name></param>
-            <param><ptype>GLenum</ptype> <name>srcAlpha</name></param>
-            <param><ptype>GLenum</ptype> <name>dstAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstRGB</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>srcAlpha</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dstAlpha</name></param>
             <alias name="glBlendFuncSeparatei"/>
         </command>
         <command>
             <proto>void <name>glBlendFunci</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
-            <param><ptype>GLenum</ptype> <name>dst</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dst</name></param>
         </command>
         <command>
             <proto>void <name>glBlendFunciARB</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
-            <param><ptype>GLenum</ptype> <name>dst</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dst</name></param>
             <alias name="glBlendFunci"/>
         </command>
         <command>
             <proto>void <name>glBlendFunciEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
-            <param><ptype>GLenum</ptype> <name>dst</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dst</name></param>
             <alias name="glBlendFunci"/>
         </command>
         <command>
             <proto>void <name>glBlendFunciOES</name></proto>
             <param><ptype>GLuint</ptype> <name>buf</name></param>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
-            <param><ptype>GLenum</ptype> <name>dst</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="BlendingFactor"><ptype>GLenum</ptype> <name>dst</name></param>
             <alias name="glBlendFunci"/>
         </command>
         <command>
@@ -9489,7 +11072,7 @@
             <param><ptype>GLint</ptype> <name>dstX1</name></param>
             <param><ptype>GLint</ptype> <name>dstY1</name></param>
             <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
-            <param><ptype>GLenum</ptype> <name>filter</name></param>
+            <param group="BlitFramebufferFilter"><ptype>GLenum</ptype> <name>filter</name></param>
             <glx type="render" opcode="4330"/>
         </command>
         <command>
@@ -9502,8 +11085,8 @@
             <param><ptype>GLint</ptype> <name>dstY0</name></param>
             <param><ptype>GLint</ptype> <name>dstX1</name></param>
             <param><ptype>GLint</ptype> <name>dstY1</name></param>
-            <param><ptype>GLbitfield</ptype> <name>mask</name></param>
-            <param><ptype>GLenum</ptype> <name>filter</name></param>
+            <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
+            <param group="BlitFramebufferFilter"><ptype>GLenum</ptype> <name>filter</name></param>
         </command>
         <command>
             <proto>void <name>glBlitFramebufferEXT</name></proto>
@@ -9516,7 +11099,7 @@
             <param><ptype>GLint</ptype> <name>dstX1</name></param>
             <param><ptype>GLint</ptype> <name>dstY1</name></param>
             <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
-            <param><ptype>GLenum</ptype> <name>filter</name></param>
+            <param group="BlitFramebufferFilter"><ptype>GLenum</ptype> <name>filter</name></param>
             <alias name="glBlitFramebuffer"/>
             <glx type="render" opcode="4330"/>
         </command>
@@ -9530,8 +11113,8 @@
             <param><ptype>GLint</ptype> <name>dstY0</name></param>
             <param><ptype>GLint</ptype> <name>dstX1</name></param>
             <param><ptype>GLint</ptype> <name>dstY1</name></param>
-            <param><ptype>GLbitfield</ptype> <name>mask</name></param>
-            <param><ptype>GLenum</ptype> <name>filter</name></param>
+            <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
+            <param group="BlitFramebufferFilter"><ptype>GLenum</ptype> <name>filter</name></param>
             <alias name="glBlitFramebuffer"/>
         </command>
         <command>
@@ -9546,8 +11129,8 @@
             <param><ptype>GLint</ptype> <name>dstY0</name></param>
             <param><ptype>GLint</ptype> <name>dstX1</name></param>
             <param><ptype>GLint</ptype> <name>dstY1</name></param>
-            <param><ptype>GLbitfield</ptype> <name>mask</name></param>
-            <param><ptype>GLenum</ptype> <name>filter</name></param>
+            <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
+            <param group="BlitFramebufferFilter"><ptype>GLenum</ptype> <name>filter</name></param>
         </command>
         <command>
             <proto>void <name>glBufferAddressRangeNV</name></proto>
@@ -9586,20 +11169,35 @@
         </command>
         <command>
             <proto>void <name>glBufferStorage</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferStorageTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <param len="size">const void *<name>data</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
         </command>
         <command>
             <proto>void <name>glBufferStorageEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferStorageTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <param len="size">const void *<name>data</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
             <alias name="glBufferStorage"/>
         </command>
         <command>
+            <proto>void <name>glBufferStorageExternalEXT</name></proto>
+            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLintptr</ptype> <name>offset</name></param>
+            <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param><ptype>GLeglClientBufferEXT</ptype> <name>clientBuffer</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
+        </command>
+        <command>
+            <proto>void <name>glBufferStorageMemEXT</name></proto>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
             <proto>void <name>glBufferSubData</name></proto>
             <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
@@ -9631,24 +11229,24 @@
             <glx type="render" opcode="2"/>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glCheckFramebufferStatus</name></proto>
+            <proto group="FramebufferStatus"><ptype>GLenum</ptype> <name>glCheckFramebufferStatus</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <glx type="vendor" opcode="1427"/>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glCheckFramebufferStatusEXT</name></proto>
+            <proto group="FramebufferStatus"><ptype>GLenum</ptype> <name>glCheckFramebufferStatusEXT</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <alias name="glCheckFramebufferStatus"/>
             <glx type="vendor" opcode="1427"/>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glCheckFramebufferStatusOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <proto group="FramebufferStatus"><ptype>GLenum</ptype> <name>glCheckFramebufferStatusOES</name></proto>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glCheckNamedFramebufferStatus</name></proto>
+            <proto group="FramebufferStatus"><ptype>GLenum</ptype> <name>glCheckNamedFramebufferStatus</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
         </command>
         <command>
             <proto group="FramebufferStatus"><ptype>GLenum</ptype> <name>glCheckNamedFramebufferStatusEXT</name></proto>
@@ -9690,46 +11288,50 @@
         </command>
         <command>
             <proto>void <name>glClearBufferData</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="BufferStorageTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glClearBufferSubData</name></proto>
             <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glClearBufferfi</name></proto>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param group="DrawBufferName"><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param><ptype>GLfloat</ptype> <name>depth</name></param>
             <param><ptype>GLint</ptype> <name>stencil</name></param>
+            <glx type="render" opcode="360"/>
         </command>
         <command>
             <proto>void <name>glClearBufferfv</name></proto>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param group="DrawBufferName"><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param len="COMPSIZE(buffer)">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <glx type="render" opcode="361"/>
         </command>
         <command>
             <proto>void <name>glClearBufferiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param group="DrawBufferName"><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param len="COMPSIZE(buffer)">const <ptype>GLint</ptype> *<name>value</name></param>
+            <glx type="render" opcode="362"/>
         </command>
         <command>
             <proto>void <name>glClearBufferuiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param group="DrawBufferName"><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param len="COMPSIZE(buffer)">const <ptype>GLuint</ptype> *<name>value</name></param>
+            <glx type="render" opcode="363"/>
         </command>
         <command>
             <proto>void <name>glClearColor</name></proto>
@@ -9805,15 +11407,15 @@
         <command>
             <proto>void <name>glClearNamedBufferData</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glClearNamedBufferDataEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
@@ -9821,11 +11423,11 @@
         <command>
             <proto>void <name>glClearNamedBufferSubData</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>data</name></param>
         </command>
         <command>
@@ -9841,7 +11443,7 @@
         <command>
             <proto>void <name>glClearNamedFramebufferfi</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param><ptype>GLfloat</ptype> <name>depth</name></param>
             <param><ptype>GLint</ptype> <name>stencil</name></param>
@@ -9849,25 +11451,31 @@
         <command>
             <proto>void <name>glClearNamedFramebufferfv</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param>const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glClearNamedFramebufferiv</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param>const <ptype>GLint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glClearNamedFramebufferuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>buffer</name></param>
+            <param group="Buffer"><ptype>GLenum</ptype> <name>buffer</name></param>
             <param><ptype>GLint</ptype> <name>drawbuffer</name></param>
             <param>const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
+            <proto>void <name>glClearPixelLocalStorageuiEXT</name></proto>
+            <param><ptype>GLsizei</ptype> <name>offset</name></param>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n">const <ptype>GLuint</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto>void <name>glClearStencil</name></proto>
             <param group="StencilValue"><ptype>GLint</ptype> <name>s</name></param>
             <glx type="render" opcode="131"/>
@@ -9876,11 +11484,20 @@
             <proto>void <name>glClearTexImage</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
         </command>
         <command>
+            <proto>void <name>glClearTexImageEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLint</ptype> <name>level</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
+            <alias name="glClearTexImage"/>
+        </command>
+        <command>
             <proto>void <name>glClearTexSubImage</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
@@ -9890,11 +11507,26 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
         </command>
         <command>
+            <proto>void <name>glClearTexSubImageEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLint</ptype> <name>level</name></param>
+            <param><ptype>GLint</ptype> <name>xoffset</name></param>
+            <param><ptype>GLint</ptype> <name>yoffset</name></param>
+            <param><ptype>GLint</ptype> <name>zoffset</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param len="COMPSIZE(format,type)">const void *<name>data</name></param>
+            <alias name="glClearTexSubImage"/>
+        </command>
+        <command>
             <proto>void <name>glClientActiveTexture</name></proto>
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
         </command>
@@ -9912,22 +11544,28 @@
             <param group="ClientAttribMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glClientWaitSync</name></proto>
+            <proto group="SyncStatus"><ptype>GLenum</ptype> <name>glClientWaitSync</name></proto>
             <param group="sync"><ptype>GLsync</ptype> <name>sync</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="SyncObjectMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
             <param><ptype>GLuint64</ptype> <name>timeout</name></param>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glClientWaitSyncAPPLE</name></proto>
+            <proto group="SyncStatus"><ptype>GLenum</ptype> <name>glClientWaitSyncAPPLE</name></proto>
             <param><ptype>GLsync</ptype> <name>sync</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="SyncObjectMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
             <param><ptype>GLuint64</ptype> <name>timeout</name></param>
             <alias name="glClientWaitSync"/>
         </command>
         <command>
             <proto>void <name>glClipControl</name></proto>
+            <param group="ClipControlOrigin"><ptype>GLenum</ptype> <name>origin</name></param>
+            <param group="ClipControlDepth"><ptype>GLenum</ptype> <name>depth</name></param>
+        </command>
+        <command>
+            <proto>void <name>glClipControlEXT</name></proto>
             <param><ptype>GLenum</ptype> <name>origin</name></param>
             <param><ptype>GLenum</ptype> <name>depth</name></param>
+            <alias name="glClipControl"/>
         </command>
         <command>
             <proto>void <name>glClipPlane</name></proto>
@@ -9937,33 +11575,33 @@
         </command>
         <command>
             <proto>void <name>glClipPlanef</name></proto>
-            <param><ptype>GLenum</ptype> <name>p</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>p</name></param>
             <param len="4">const <ptype>GLfloat</ptype> *<name>eqn</name></param>
         </command>
         <command>
             <proto>void <name>glClipPlanefIMG</name></proto>
-            <param><ptype>GLenum</ptype> <name>p</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>p</name></param>
             <param len="4">const <ptype>GLfloat</ptype> *<name>eqn</name></param>
         </command>
         <command>
             <proto>void <name>glClipPlanefOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4">const <ptype>GLfloat</ptype> *<name>equation</name></param>
             <glx type="render" opcode="4312"/>
         </command>
         <command>
             <proto>void <name>glClipPlanex</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4">const <ptype>GLfixed</ptype> *<name>equation</name></param>
         </command>
         <command>
             <proto>void <name>glClipPlanexIMG</name></proto>
-            <param><ptype>GLenum</ptype> <name>p</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>p</name></param>
             <param len="4">const <ptype>GLfixed</ptype> *<name>eqn</name></param>
         </command>
         <command>
             <proto>void <name>glClipPlanexOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4">const <ptype>GLfixed</ptype> *<name>equation</name></param>
         </command>
         <command>
@@ -10342,6 +11980,7 @@
             <param group="Boolean"><ptype>GLboolean</ptype> <name>b</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>a</name></param>
             <alias name="glColorMaski"/>
+            <glx type="render" opcode="352"/>
         </command>
         <command>
             <proto>void <name>glColorMaski</name></proto>
@@ -10377,22 +12016,22 @@
         </command>
         <command>
             <proto>void <name>glColorP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>color</name></param>
         </command>
         <command>
             <proto>void <name>glColorP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>color</name></param>
         </command>
         <command>
             <proto>void <name>glColorP4ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>color</name></param>
         </command>
         <command>
             <proto>void <name>glColorP4uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>color</name></param>
         </command>
         <command>
@@ -10448,7 +12087,7 @@
         <command>
             <proto>void <name>glColorTable</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -10459,7 +12098,7 @@
         <command>
             <proto>void <name>glColorTableEXT</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalFormat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -10469,7 +12108,7 @@
         <command>
             <proto>void <name>glColorTableParameterfv</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedFloat32" len="COMPSIZE(pname)">const <ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="render" opcode="2054"/>
         </command>
@@ -10484,7 +12123,7 @@
         <command>
             <proto>void <name>glColorTableParameteriv</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedInt32" len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>params</name></param>
             <glx type="render" opcode="2055"/>
         </command>
@@ -10499,7 +12138,7 @@
         <command>
             <proto>void <name>glColorTableSGI</name></proto>
             <param group="ColorTableTargetSGI"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -10591,7 +12230,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
@@ -10602,7 +12241,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -10614,7 +12253,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -10665,7 +12304,7 @@
             <proto>void <name>glCompressedTexImage1D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
@@ -10677,7 +12316,7 @@
             <proto>void <name>glCompressedTexImage1DARB</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
@@ -10689,7 +12328,7 @@
             <proto>void <name>glCompressedTexImage2D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -10702,7 +12341,7 @@
             <proto>void <name>glCompressedTexImage2DARB</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -10715,7 +12354,7 @@
             <proto>void <name>glCompressedTexImage3D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -10729,7 +12368,7 @@
             <proto>void <name>glCompressedTexImage3DARB</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -10741,16 +12380,15 @@
         </command>
         <command>
             <proto>void <name>glCompressedTexImage3DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
             <param><ptype>GLint</ptype> <name>border</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
             <param len="imageSize">const void *<name>data</name></param>
-            <alias name="glCompressedTexImage3D"/>
         </command>
         <command>
             <proto>void <name>glCompressedTexSubImage1D</name></proto>
@@ -10838,7 +12476,7 @@
         </command>
         <command>
             <proto>void <name>glCompressedTexSubImage3DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>xoffset</name></param>
             <param><ptype>GLint</ptype> <name>yoffset</name></param>
@@ -10846,17 +12484,16 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
             <param len="imageSize">const void *<name>data</name></param>
-            <alias name="glCompressedTexSubImage3D"/>
         </command>
         <command>
             <proto>void <name>glCompressedTextureImage1DEXT</name></proto>
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
@@ -10867,7 +12504,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -10879,7 +12516,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -10893,7 +12530,7 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>xoffset</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
             <param>const void *<name>data</name></param>
         </command>
@@ -10916,7 +12553,7 @@
             <param><ptype>GLint</ptype> <name>yoffset</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
             <param>const void *<name>data</name></param>
         </command>
@@ -10943,7 +12580,7 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param><ptype>GLsizei</ptype> <name>imageSize</name></param>
             <param>const void *<name>data</name></param>
         </command>
@@ -10968,9 +12605,14 @@
             <param><ptype>GLfloat</ptype> <name>value</name></param>
         </command>
         <command>
+            <proto>void <name>glConservativeRasterParameteriNV</name></proto>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLint</ptype> <name>param</name></param>
+        </command>
+        <command>
             <proto>void <name>glConvolutionFilter1D</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -10981,7 +12623,7 @@
         <command>
             <proto>void <name>glConvolutionFilter1DEXT</name></proto>
             <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -10992,7 +12634,7 @@
         <command>
             <proto>void <name>glConvolutionFilter2D</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -11004,7 +12646,7 @@
         <command>
             <proto>void <name>glConvolutionFilter2DEXT</name></proto>
             <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -11016,7 +12658,7 @@
         <command>
             <proto>void <name>glConvolutionParameterf</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ConvolutionParameter"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>params</name></param>
             <glx type="render" opcode="4103"/>
         </command>
@@ -11031,7 +12673,7 @@
         <command>
             <proto>void <name>glConvolutionParameterfv</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ConvolutionParameter"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedFloat32" len="COMPSIZE(pname)">const <ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="render" opcode="4104"/>
         </command>
@@ -11046,7 +12688,7 @@
         <command>
             <proto>void <name>glConvolutionParameteri</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ConvolutionParameter"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>params</name></param>
             <glx type="render" opcode="4105"/>
         </command>
@@ -11061,7 +12703,7 @@
         <command>
             <proto>void <name>glConvolutionParameteriv</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ConvolutionParameter"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedInt32" len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>params</name></param>
             <glx type="render" opcode="4106"/>
         </command>
@@ -11075,28 +12717,29 @@
         </command>
         <command>
             <proto>void <name>glConvolutionParameterxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glConvolutionParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glCopyBufferSubData</name></proto>
-            <param><ptype>GLenum</ptype> <name>readTarget</name></param>
-            <param><ptype>GLenum</ptype> <name>writeTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>readTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>writeTarget</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>readOffset</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>writeOffset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <glx type="single" opcode="221"/>
         </command>
         <command>
             <proto>void <name>glCopyBufferSubDataNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>readTarget</name></param>
-            <param><ptype>GLenum</ptype> <name>writeTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>readTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>writeTarget</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>readOffset</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>writeOffset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
@@ -11123,7 +12766,7 @@
         <command>
             <proto>void <name>glCopyColorTable</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11132,7 +12775,7 @@
         <command>
             <proto>void <name>glCopyColorTableSGI</name></proto>
             <param group="ColorTableTargetSGI"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11142,7 +12785,7 @@
         <command>
             <proto>void <name>glCopyConvolutionFilter1D</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11151,7 +12794,7 @@
         <command>
             <proto>void <name>glCopyConvolutionFilter1DEXT</name></proto>
             <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11161,7 +12804,7 @@
         <command>
             <proto>void <name>glCopyConvolutionFilter2D</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11171,7 +12814,7 @@
         <command>
             <proto>void <name>glCopyConvolutionFilter2DEXT</name></proto>
             <param group="ConvolutionTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11182,13 +12825,13 @@
         <command>
             <proto>void <name>glCopyImageSubData</name></proto>
             <param><ptype>GLuint</ptype> <name>srcName</name></param>
-            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>srcTarget</name></param>
             <param><ptype>GLint</ptype> <name>srcLevel</name></param>
             <param><ptype>GLint</ptype> <name>srcX</name></param>
             <param><ptype>GLint</ptype> <name>srcY</name></param>
             <param><ptype>GLint</ptype> <name>srcZ</name></param>
             <param><ptype>GLuint</ptype> <name>dstName</name></param>
-            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>dstTarget</name></param>
             <param><ptype>GLint</ptype> <name>dstLevel</name></param>
             <param><ptype>GLint</ptype> <name>dstX</name></param>
             <param><ptype>GLint</ptype> <name>dstY</name></param>
@@ -11200,13 +12843,13 @@
         <command>
             <proto>void <name>glCopyImageSubDataEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>srcName</name></param>
-            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>srcTarget</name></param>
             <param><ptype>GLint</ptype> <name>srcLevel</name></param>
             <param><ptype>GLint</ptype> <name>srcX</name></param>
             <param><ptype>GLint</ptype> <name>srcY</name></param>
             <param><ptype>GLint</ptype> <name>srcZ</name></param>
             <param><ptype>GLuint</ptype> <name>dstName</name></param>
-            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>dstTarget</name></param>
             <param><ptype>GLint</ptype> <name>dstLevel</name></param>
             <param><ptype>GLint</ptype> <name>dstX</name></param>
             <param><ptype>GLint</ptype> <name>dstY</name></param>
@@ -11219,13 +12862,13 @@
         <command>
             <proto>void <name>glCopyImageSubDataNV</name></proto>
             <param><ptype>GLuint</ptype> <name>srcName</name></param>
-            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>srcTarget</name></param>
             <param><ptype>GLint</ptype> <name>srcLevel</name></param>
             <param><ptype>GLint</ptype> <name>srcX</name></param>
             <param><ptype>GLint</ptype> <name>srcY</name></param>
             <param><ptype>GLint</ptype> <name>srcZ</name></param>
             <param><ptype>GLuint</ptype> <name>dstName</name></param>
-            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>dstTarget</name></param>
             <param><ptype>GLint</ptype> <name>dstLevel</name></param>
             <param><ptype>GLint</ptype> <name>dstX</name></param>
             <param><ptype>GLint</ptype> <name>dstY</name></param>
@@ -11238,13 +12881,13 @@
         <command>
             <proto>void <name>glCopyImageSubDataOES</name></proto>
             <param><ptype>GLuint</ptype> <name>srcName</name></param>
-            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>srcTarget</name></param>
             <param><ptype>GLint</ptype> <name>srcLevel</name></param>
             <param><ptype>GLint</ptype> <name>srcX</name></param>
             <param><ptype>GLint</ptype> <name>srcY</name></param>
             <param><ptype>GLint</ptype> <name>srcZ</name></param>
             <param><ptype>GLuint</ptype> <name>dstName</name></param>
-            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param group="CopyBufferSubDataTarget"><ptype>GLenum</ptype> <name>dstTarget</name></param>
             <param><ptype>GLint</ptype> <name>dstLevel</name></param>
             <param><ptype>GLint</ptype> <name>dstX</name></param>
             <param><ptype>GLint</ptype> <name>dstY</name></param>
@@ -11259,7 +12902,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11270,7 +12913,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11338,7 +12981,7 @@
             <proto>void <name>glCopyTexImage1D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11349,7 +12992,7 @@
             <proto>void <name>glCopyTexImage1DEXT</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11361,7 +13004,7 @@
             <proto>void <name>glCopyTexImage2D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11373,7 +13016,7 @@
             <proto>void <name>glCopyTexImage2DEXT</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11466,14 +13109,13 @@
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <alias name="glCopyTexSubImage3D"/>
         </command>
         <command>
             <proto>void <name>glCopyTextureImage1DEXT</name></proto>
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11484,7 +13126,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>x</name></param>
             <param group="WinCoord"><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -11606,7 +13248,7 @@
         <command>
             <proto>void <name>glCoverageModulationTableNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
+            <param len="n">const <ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glCoverageOperationNV</name></proto>
@@ -11615,17 +13257,22 @@
         <command>
             <proto>void <name>glCreateBuffers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>buffers</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>buffers</name></param>
         </command>
         <command>
             <proto>void <name>glCreateCommandListsNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>lists</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>lists</name></param>
         </command>
         <command>
             <proto>void <name>glCreateFramebuffers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>framebuffers</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>framebuffers</name></param>
+        </command>
+        <command>
+            <proto>void <name>glCreateMemoryObjectsEXT</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param><ptype>GLuint</ptype> *<name>memoryObjects</name></param>
         </command>
         <command>
             <proto>void <name>glCreatePerfQueryINTEL</name></proto>
@@ -11642,54 +13289,54 @@
         <command>
             <proto>void <name>glCreateProgramPipelines</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>pipelines</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>pipelines</name></param>
         </command>
         <command>
             <proto>void <name>glCreateQueries</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>ids</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>ids</name></param>
         </command>
         <command>
             <proto>void <name>glCreateRenderbuffers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>renderbuffers</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>renderbuffers</name></param>
         </command>
         <command>
             <proto>void <name>glCreateSamplers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>samplers</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>samplers</name></param>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glCreateShader</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>type</name></param>
         </command>
         <command>
             <proto group="handleARB"><ptype>GLhandleARB</ptype> <name>glCreateShaderObjectARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>shaderType</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shaderType</name></param>
             <alias name="glCreateShader"/>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glCreateShaderProgramEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const <ptype>GLchar</ptype> *<name>string</name></param>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glCreateShaderProgramv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLchar</ptype> *const*<name>strings</name></param>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glCreateShaderProgramvEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLchar</ptype> **<name>strings</name></param>
         </command>
         <command>
             <proto>void <name>glCreateStatesNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>states</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>states</name></param>
         </command>
         <command>
             <proto group="sync"><ptype>GLsync</ptype> <name>glCreateSyncFromCLeventARB</name></proto>
@@ -11699,19 +13346,19 @@
         </command>
         <command>
             <proto>void <name>glCreateTextures</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>textures</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>textures</name></param>
         </command>
         <command>
             <proto>void <name>glCreateTransformFeedbacks</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>ids</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>ids</name></param>
         </command>
         <command>
             <proto>void <name>glCreateVertexArrays</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param><ptype>GLuint</ptype> *<name>arrays</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>arrays</name></param>
         </command>
         <command>
             <proto>void <name>glCullFace</name></proto>
@@ -11761,18 +13408,18 @@
         </command>
         <command>
             <proto>void <name>glDebugMessageControl</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>ids</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>enabled</name></param>
         </command>
         <command>
             <proto>void <name>glDebugMessageControlARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>ids</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>enabled</name></param>
@@ -11780,9 +13427,9 @@
         </command>
         <command>
             <proto>void <name>glDebugMessageControlKHR</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param>const <ptype>GLuint</ptype> *<name>ids</name></param>
             <param><ptype>GLboolean</ptype> <name>enabled</name></param>
@@ -11791,44 +13438,44 @@
         <command>
             <proto>void <name>glDebugMessageEnableAMD</name></proto>
             <param><ptype>GLenum</ptype> <name>category</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>ids</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>enabled</name></param>
         </command>
         <command>
             <proto>void <name>glDebugMessageInsert</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param len="COMPSIZE(buf,length)">const <ptype>GLchar</ptype> *<name>buf</name></param>
         </command>
         <command>
             <proto>void <name>glDebugMessageInsertAMD</name></proto>
             <param><ptype>GLenum</ptype> <name>category</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param len="length">const <ptype>GLchar</ptype> *<name>buf</name></param>
         </command>
         <command>
             <proto>void <name>glDebugMessageInsertARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param len="length">const <ptype>GLchar</ptype> *<name>buf</name></param>
             <alias name="glDebugMessageInsert"/>
         </command>
         <command>
             <proto>void <name>glDebugMessageInsertKHR</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>severity</name></param>
+            <param group="DebugSeverity"><ptype>GLenum</ptype> <name>severity</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param>const <ptype>GLchar</ptype> *<name>buf</name></param>
             <alias name="glDebugMessageInsert"/>
@@ -11893,7 +13540,7 @@
         <command>
             <proto>void <name>glDeleteCommandListsNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param>const <ptype>GLuint</ptype> *<name>lists</name></param>
+            <param len="n">const <ptype>GLuint</ptype> *<name>lists</name></param>
         </command>
         <command>
             <proto>void <name>glDeleteFencesAPPLE</name></proto>
@@ -11935,6 +13582,11 @@
             <glx type="single" opcode="103"/>
         </command>
         <command>
+            <proto>void <name>glDeleteMemoryObjectsEXT</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n">const <ptype>GLuint</ptype> *<name>memoryObjects</name></param>
+        </command>
+        <command>
             <proto>void <name>glDeleteNamedStringARB</name></proto>
             <param><ptype>GLint</ptype> <name>namelen</name></param>
             <param len="namelen">const <ptype>GLchar</ptype> *<name>name</name></param>
@@ -12014,6 +13666,11 @@
             <param len="n">const <ptype>GLuint</ptype> *<name>ids</name></param>
         </command>
         <command>
+            <proto>void <name>glDeleteQueryResourceTagNV</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n">const <ptype>GLint</ptype> *<name>tagIds</name></param>
+        </command>
+        <command>
             <proto>void <name>glDeleteRenderbuffers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
             <param len="n">const <ptype>GLuint</ptype> *<name>renderbuffers</name></param>
@@ -12037,6 +13694,11 @@
             <param len="count">const <ptype>GLuint</ptype> *<name>samplers</name></param>
         </command>
         <command>
+            <proto>void <name>glDeleteSemaphoresEXT</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n">const <ptype>GLuint</ptype> *<name>semaphores</name></param>
+        </command>
+        <command>
             <proto>void <name>glDeleteShader</name></proto>
             <param><ptype>GLuint</ptype> <name>shader</name></param>
             <glx type="single" opcode="195"/>
@@ -12044,7 +13706,7 @@
         <command>
             <proto>void <name>glDeleteStatesNV</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param>const <ptype>GLuint</ptype> *<name>states</name></param>
+            <param len="n">const <ptype>GLuint</ptype> *<name>states</name></param>
         </command>
         <command>
             <proto>void <name>glDeleteSync</name></proto>
@@ -12124,8 +13786,8 @@
         </command>
         <command>
             <proto>void <name>glDepthRange</name></proto>
-            <param><ptype>GLdouble</ptype> <name>near</name></param>
-            <param><ptype>GLdouble</ptype> <name>far</name></param>
+            <param><ptype>GLdouble</ptype> <name>n</name></param>
+            <param><ptype>GLdouble</ptype> <name>f</name></param>
             <glx type="render" opcode="174"/>
         </command>
         <command>
@@ -12135,6 +13797,12 @@
             <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
+            <proto>void <name>glDepthRangeArrayfvOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>first</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
+        </command>
+        <command>
             <proto>void <name>glDepthRangeArrayv</name></proto>
             <param><ptype>GLuint</ptype> <name>first</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
@@ -12153,6 +13821,12 @@
             <param><ptype>GLfloat</ptype> <name>f</name></param>
         </command>
         <command>
+            <proto>void <name>glDepthRangeIndexedfOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param><ptype>GLfloat</ptype> <name>n</name></param>
+            <param><ptype>GLfloat</ptype> <name>f</name></param>
+        </command>
+        <command>
             <proto>void <name>glDepthRangedNV</name></proto>
             <param><ptype>GLdouble</ptype> <name>zNear</name></param>
             <param><ptype>GLdouble</ptype> <name>zFar</name></param>
@@ -12223,9 +13897,10 @@
         </command>
         <command>
             <proto>void <name>glDisableIndexedEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glDisablei"/>
+            <glx type="render" opcode="354"/>
         </command>
         <command>
             <proto>void <name>glDisableVariantClientStateEXT</name></proto>
@@ -12262,24 +13937,24 @@
         </command>
         <command>
             <proto>void <name>glDisablei</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
         </command>
         <command>
             <proto>void <name>glDisableiEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glDisablei"/>
         </command>
         <command>
             <proto>void <name>glDisableiNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glDisablei"/>
         </command>
         <command>
             <proto>void <name>glDisableiOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glDisablei"/>
         </command>
@@ -12411,7 +14086,7 @@
         <command>
             <proto>void <name>glDrawBuffersEXT</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param>const <ptype>GLenum</ptype> *<name>bufs</name></param>
+            <param len="n">const <ptype>GLenum</ptype> *<name>bufs</name></param>
             <alias name="glDrawBuffers"/>
         </command>
         <command>
@@ -12504,7 +14179,7 @@
         <command>
             <proto>void <name>glDrawElementsIndirect</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>indirect</name></param>
         </command>
         <command>
@@ -12519,7 +14194,7 @@
             <proto>void <name>glDrawElementsInstancedANGLE</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(count,type)">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>primcount</name></param>
             <alias name="glDrawElementsInstanced"/>
@@ -12537,7 +14212,7 @@
             <proto>void <name>glDrawElementsInstancedBaseInstance</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="count">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
             <param><ptype>GLuint</ptype> <name>baseinstance</name></param>
@@ -12546,7 +14221,7 @@
             <proto>void <name>glDrawElementsInstancedBaseInstanceEXT</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="count">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
             <param><ptype>GLuint</ptype> <name>baseinstance</name></param>
@@ -12565,7 +14240,7 @@
             <proto>void <name>glDrawElementsInstancedBaseVertexBaseInstance</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="count">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
             <param><ptype>GLint</ptype> <name>basevertex</name></param>
@@ -12575,7 +14250,7 @@
             <proto>void <name>glDrawElementsInstancedBaseVertexBaseInstanceEXT</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="count">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
             <param><ptype>GLint</ptype> <name>basevertex</name></param>
@@ -12615,7 +14290,7 @@
             <proto>void <name>glDrawElementsInstancedNV</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(count,type)">const void *<name>indices</name></param>
             <param><ptype>GLsizei</ptype> <name>primcount</name></param>
             <alias name="glDrawElementsInstanced"/>
@@ -12710,10 +14385,11 @@
             <param><ptype>GLfloat</ptype> <name>z</name></param>
             <param><ptype>GLfloat</ptype> <name>width</name></param>
             <param><ptype>GLfloat</ptype> <name>height</name></param>
+            <vecequiv name="glDrawTexfvOES"/>
         </command>
         <command>
             <proto>void <name>glDrawTexfvOES</name></proto>
-            <param>const <ptype>GLfloat</ptype> *<name>coords</name></param>
+            <param len="5">const <ptype>GLfloat</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glDrawTexiOES</name></proto>
@@ -12722,10 +14398,11 @@
             <param><ptype>GLint</ptype> <name>z</name></param>
             <param><ptype>GLint</ptype> <name>width</name></param>
             <param><ptype>GLint</ptype> <name>height</name></param>
+            <vecequiv name="glDrawTexivOES"/>
         </command>
         <command>
             <proto>void <name>glDrawTexivOES</name></proto>
-            <param>const <ptype>GLint</ptype> *<name>coords</name></param>
+            <param len="5">const <ptype>GLint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glDrawTexsOES</name></proto>
@@ -12734,10 +14411,11 @@
             <param><ptype>GLshort</ptype> <name>z</name></param>
             <param><ptype>GLshort</ptype> <name>width</name></param>
             <param><ptype>GLshort</ptype> <name>height</name></param>
+            <vecequiv name="glDrawTexsvOES"/>
         </command>
         <command>
             <proto>void <name>glDrawTexsvOES</name></proto>
-            <param>const <ptype>GLshort</ptype> *<name>coords</name></param>
+            <param len="5">const <ptype>GLshort</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glDrawTextureNV</name></proto>
@@ -12760,10 +14438,11 @@
             <param><ptype>GLfixed</ptype> <name>z</name></param>
             <param><ptype>GLfixed</ptype> <name>width</name></param>
             <param><ptype>GLfixed</ptype> <name>height</name></param>
+            <vecequiv name="glDrawTexxvOES"/>
         </command>
         <command>
             <proto>void <name>glDrawTexxvOES</name></proto>
-            <param>const <ptype>GLfixed</ptype> *<name>coords</name></param>
+            <param len="5">const <ptype>GLfixed</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glDrawTransformFeedback</name></proto>
@@ -12771,12 +14450,25 @@
             <param><ptype>GLuint</ptype> <name>id</name></param>
         </command>
         <command>
+            <proto>void <name>glDrawTransformFeedbackEXT</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <alias name="glDrawTransformFeedback"/>
+        </command>
+        <command>
             <proto>void <name>glDrawTransformFeedbackInstanced</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
         </command>
         <command>
+            <proto>void <name>glDrawTransformFeedbackInstancedEXT</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <param><ptype>GLsizei</ptype> <name>instancecount</name></param>
+            <alias name="glDrawTransformFeedbackInstanced"/>
+        </command>
+        <command>
             <proto>void <name>glDrawTransformFeedbackNV</name></proto>
             <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
@@ -12801,11 +14493,23 @@
             <param><ptype>GLeglImageOES</ptype> <name>image</name></param>
         </command>
         <command>
+            <proto>void <name>glEGLImageTargetTexStorageEXT</name></proto>
+            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLeglImageOES</ptype> <name>image</name></param>
+            <param>const <ptype>GLint</ptype>* <name>attrib_list</name></param>
+        </command>
+        <command>
             <proto>void <name>glEGLImageTargetTexture2DOES</name></proto>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLeglImageOES</ptype> <name>image</name></param>
         </command>
         <command>
+            <proto>void <name>glEGLImageTargetTextureStorageEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLeglImageOES</ptype> <name>image</name></param>
+            <param>const <ptype>GLint</ptype>* <name>attrib_list</name></param>
+        </command>
+        <command>
             <proto>void <name>glEdgeFlag</name></proto>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>flag</name></param>
             <vecequiv name="glEdgeFlagv"/>
@@ -12871,9 +14575,10 @@
         </command>
         <command>
             <proto>void <name>glEnableIndexedEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glEnablei"/>
+            <glx type="render" opcode="353"/>
         </command>
         <command>
             <proto>void <name>glEnableVariantClientStateEXT</name></proto>
@@ -12910,24 +14615,24 @@
         </command>
         <command>
             <proto>void <name>glEnablei</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
         </command>
         <command>
             <proto>void <name>glEnableiEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glEnablei"/>
         </command>
         <command>
             <proto>void <name>glEnableiNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glEnablei"/>
         </command>
         <command>
             <proto>void <name>glEnableiOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glEnablei"/>
         </command>
@@ -12967,29 +14672,30 @@
         </command>
         <command>
             <proto>void <name>glEndQuery</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <glx type="render" opcode="232"/>
         </command>
         <command>
             <proto>void <name>glEndQueryARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <alias name="glEndQuery"/>
         </command>
         <command>
             <proto>void <name>glEndQueryEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
         </command>
         <command>
             <proto>void <name>glEndQueryIndexed</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
         </command>
         <command>
             <proto>void <name>glEndTilingQCOM</name></proto>
-            <param><ptype>GLbitfield</ptype> <name>preserveMask</name></param>
+            <param group="BufferBitQCOM"><ptype>GLbitfield</ptype> <name>preserveMask</name></param>
         </command>
         <command>
             <proto>void <name>glEndTransformFeedback</name></proto>
+            <glx type="render" opcode="358"/>
         </command>
         <command>
             <proto>void <name>glEndTransformFeedbackEXT</name></proto>
@@ -13127,7 +14833,7 @@
         <command>
             <proto>void <name>glExtGetProgramBinarySourceQCOM</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLchar</ptype> *<name>source</name></param>
             <param><ptype>GLint</ptype> *<name>length</name></param>
         </command>
@@ -13167,8 +14873,8 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>void *<name>texels</name></param>
         </command>
         <command>
@@ -13208,12 +14914,12 @@
         </command>
         <command>
             <proto group="sync"><ptype>GLsync</ptype> <name>glFenceSync</name></proto>
-            <param><ptype>GLenum</ptype> <name>condition</name></param>
+            <param group="SyncCondition"><ptype>GLenum</ptype> <name>condition</name></param>
             <param><ptype>GLbitfield</ptype> <name>flags</name></param>
         </command>
         <command>
             <proto><ptype>GLsync</ptype> <name>glFenceSyncAPPLE</name></proto>
-            <param><ptype>GLenum</ptype> <name>condition</name></param>
+            <param group="SyncCondition"><ptype>GLenum</ptype> <name>condition</name></param>
             <param><ptype>GLbitfield</ptype> <name>flags</name></param>
             <alias name="glFenceSync"/>
         </command>
@@ -13262,14 +14968,14 @@
         </command>
         <command>
             <proto>void <name>glFlushMappedBufferRangeAPPLE</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <alias name="glFlushMappedBufferRange"/>
         </command>
         <command>
             <proto>void <name>glFlushMappedBufferRangeEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
             <param><ptype>GLsizeiptr</ptype> <name>length</name></param>
             <alias name="glFlushMappedBufferRange"/>
@@ -13417,22 +15123,22 @@
         </command>
         <command>
             <proto>void <name>glFogx</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FogPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glFogxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FogPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glFogxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FogPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glFogxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FogPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -13532,12 +15238,42 @@
             <param group="DrawBufferMode" len="n">const <ptype>GLenum</ptype> *<name>bufs</name></param>
         </command>
         <command>
+            <proto>void <name>glFramebufferFetchBarrierEXT</name></proto>
+        </command>
+        <command>
+            <proto>void <name>glFramebufferFetchBarrierQCOM</name></proto>
+        </command>
+        <command>
+            <proto>void <name>glFramebufferFoveationConfigQCOM</name></proto>
+            <param group="Framebuffer"><ptype>GLuint</ptype> <name>framebuffer</name></param>
+            <param><ptype>GLuint</ptype> <name>numLayers</name></param>
+            <param><ptype>GLuint</ptype> <name>focalPointsPerLayer</name></param>
+            <param><ptype>GLuint</ptype> <name>requestedFeatures</name></param>
+            <param len="1"><ptype>GLuint</ptype> *<name>providedFeatures</name></param>
+        </command>
+        <command>
+            <proto>void <name>glFramebufferFoveationParametersQCOM</name></proto>
+            <param group="Framebuffer"><ptype>GLuint</ptype> <name>framebuffer</name></param>
+            <param><ptype>GLuint</ptype> <name>layer</name></param>
+            <param><ptype>GLuint</ptype> <name>focalPoint</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>focalX</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>focalY</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>gainX</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>gainY</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>foveaArea</name></param>
+        </command>
+        <command>
             <proto>void <name>glFramebufferParameteri</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>param</name></param>
         </command>
         <command>
+            <proto>void <name>glFramebufferPixelLocalStorageSizeEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>size</name></param>
+        </command>
+        <command>
             <proto>void <name>glFramebufferReadBufferEXT</name></proto>
             <param group="Framebuffer"><ptype>GLuint</ptype> <name>framebuffer</name></param>
             <param group="ReadBufferMode"><ptype>GLenum</ptype> <name>mode</name></param>
@@ -13561,29 +15297,36 @@
         </command>
         <command>
             <proto>void <name>glFramebufferRenderbufferOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>renderbuffertarget</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>renderbuffertarget</name></param>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
         </command>
         <command>
             <proto>void <name>glFramebufferSampleLocationsfvARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>start</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glFramebufferSampleLocationsfvNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>start</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
+            <proto>void <name>glFramebufferSamplePositionsfvAMD</name></proto>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLuint</ptype> <name>numsamples</name></param>
+            <param><ptype>GLuint</ptype> <name>pixelindex</name></param>
+            <param>const <ptype>GLfloat</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto>void <name>glFramebufferTexture</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
         </command>
@@ -13591,7 +15334,7 @@
             <proto>void <name>glFramebufferTexture1D</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <glx type="render" opcode="4321"/>
@@ -13600,7 +15343,7 @@
             <proto>void <name>glFramebufferTexture1DEXT</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <alias name="glFramebufferTexture1D"/>
@@ -13610,7 +15353,7 @@
             <proto>void <name>glFramebufferTexture2D</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <glx type="render" opcode="4322"/>
@@ -13619,35 +15362,45 @@
             <proto>void <name>glFramebufferTexture2DEXT</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <alias name="glFramebufferTexture2D"/>
             <glx type="render" opcode="4322"/>
         </command>
         <command>
+            <proto>void <name>glFramebufferTexture2DDownsampleIMG</name></proto>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLint</ptype> <name>level</name></param>
+            <param><ptype>GLint</ptype> <name>xscale</name></param>
+            <param><ptype>GLint</ptype> <name>yscale</name></param>
+        </command>
+        <command>
             <proto>void <name>glFramebufferTexture2DMultisampleEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
         </command>
         <command>
             <proto>void <name>glFramebufferTexture2DMultisampleIMG</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
         </command>
         <command>
             <proto>void <name>glFramebufferTexture2DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
         </command>
@@ -13655,7 +15408,7 @@
             <proto>void <name>glFramebufferTexture3D</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>zoffset</name></param>
@@ -13665,7 +15418,7 @@
             <proto>void <name>glFramebufferTexture3DEXT</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>zoffset</name></param>
@@ -13674,13 +15427,12 @@
         </command>
         <command>
             <proto>void <name>glFramebufferTexture3DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>textarget</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>textarget</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>zoffset</name></param>
-            <alias name="glFramebufferTexture3D"/>
         </command>
         <command>
             <proto>void <name>glFramebufferTextureARB</name></proto>
@@ -13743,6 +15495,16 @@
             <alias name="glFramebufferTextureLayer"/>
         </command>
         <command>
+            <proto>void <name>glFramebufferTextureLayerDownsampleIMG</name></proto>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
+            <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
+            <param group="CheckedInt32"><ptype>GLint</ptype> <name>layer</name></param>
+            <param><ptype>GLint</ptype> <name>xscale</name></param>
+            <param><ptype>GLint</ptype> <name>yscale</name></param>
+        </command>
+        <command>
             <proto>void <name>glFramebufferTextureMultisampleMultiviewOVR</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
@@ -13939,6 +15701,11 @@
             <param len="n"><ptype>GLuint</ptype> *<name>ids</name></param>
         </command>
         <command>
+            <proto>void <name>glGenQueryResourceTagNV</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n"><ptype>GLint</ptype> *<name>tagIds</name></param>
+        </command>
+        <command>
             <proto>void <name>glGenRenderbuffers</name></proto>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
             <param len="n"><ptype>GLuint</ptype> *<name>renderbuffers</name></param>
@@ -13962,6 +15729,11 @@
             <param len="count"><ptype>GLuint</ptype> *<name>samplers</name></param>
         </command>
         <command>
+            <proto>void <name>glGenSemaphoresEXT</name></proto>
+            <param><ptype>GLsizei</ptype> <name>n</name></param>
+            <param len="n"><ptype>GLuint</ptype> *<name>semaphores</name></param>
+        </command>
+        <command>
             <proto><ptype>GLuint</ptype> <name>glGenSymbolsEXT</name></proto>
             <param group="DataTypeEXT"><ptype>GLenum</ptype> <name>datatype</name></param>
             <param group="VertexShaderStorageTypeEXT"><ptype>GLenum</ptype> <name>storagetype</name></param>
@@ -14015,18 +15787,18 @@
         </command>
         <command>
             <proto>void <name>glGenerateMipmap</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <glx type="render" opcode="4325"/>
         </command>
         <command>
             <proto>void <name>glGenerateMipmapEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <alias name="glGenerateMipmap"/>
             <glx type="render" opcode="4325"/>
         </command>
         <command>
             <proto>void <name>glGenerateMipmapOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
         </command>
         <command>
             <proto>void <name>glGenerateMultiTexMipmapEXT</name></proto>
@@ -14046,7 +15818,7 @@
             <proto>void <name>glGetActiveAtomicCounterBufferiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLuint</ptype> <name>bufferIndex</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="AtomicCounterBufferPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -14056,7 +15828,7 @@
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>size</name></param>
-            <param len="1"><ptype>GLenum</ptype> *<name>type</name></param>
+            <param group="AttributeType" len="1"><ptype>GLenum</ptype> *<name>type</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
@@ -14066,14 +15838,14 @@
             <param><ptype>GLsizei</ptype> <name>maxLength</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>size</name></param>
-            <param len="1"><ptype>GLenum</ptype> *<name>type</name></param>
+            <param len="1" group="AttributeType"><ptype>GLenum</ptype> *<name>type</name></param>
             <param len="maxLength"><ptype>GLcharARB</ptype> *<name>name</name></param>
             <alias name="glGetActiveAttrib"/>
         </command>
         <command>
             <proto>void <name>glGetActiveSubroutineName</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLsizei</ptype> <name>bufsize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
@@ -14082,7 +15854,7 @@
         <command>
             <proto>void <name>glGetActiveSubroutineUniformName</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLsizei</ptype> <name>bufsize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
@@ -14091,9 +15863,9 @@
         <command>
             <proto>void <name>glGetActiveSubroutineUniformiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SubroutineParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>values</name></param>
         </command>
         <command>
@@ -14103,7 +15875,7 @@
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>size</name></param>
-            <param len="1"><ptype>GLenum</ptype> *<name>type</name></param>
+            <param len="1" group="AttributeType"><ptype>GLenum</ptype> *<name>type</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
@@ -14113,7 +15885,7 @@
             <param><ptype>GLsizei</ptype> <name>maxLength</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>size</name></param>
-            <param len="1"><ptype>GLenum</ptype> *<name>type</name></param>
+            <param len="1" group="AttributeType"><ptype>GLenum</ptype> *<name>type</name></param>
             <param len="maxLength"><ptype>GLcharARB</ptype> *<name>name</name></param>
             <alias name="glGetActiveUniform"/>
         </command>
@@ -14124,13 +15896,15 @@
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>uniformBlockName</name></param>
+            <glx type="single" opcode="220"/>
         </command>
         <command>
             <proto>void <name>glGetActiveUniformBlockiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLuint</ptype> <name>uniformBlockIndex</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="UniformBlockPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(program,uniformBlockIndex,pname)"><ptype>GLint</ptype> *<name>params</name></param>
+            <glx type="single" opcode="219"/>
         </command>
         <command>
             <proto>void <name>glGetActiveUniformName</name></proto>
@@ -14139,14 +15913,16 @@
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>uniformName</name></param>
+            <glx type="single" opcode="217"/>
         </command>
         <command>
             <proto>void <name>glGetActiveUniformsiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLsizei</ptype> <name>uniformCount</name></param>
             <param len="uniformCount">const <ptype>GLuint</ptype> *<name>uniformIndices</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="UniformPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(uniformCount,pname)"><ptype>GLint</ptype> *<name>params</name></param>
+            <glx type="single" opcode="216"/>
         </command>
         <command>
             <proto>void <name>glGetActiveVaryingNV</name></proto>
@@ -14197,14 +15973,15 @@
         </command>
         <command>
             <proto>void <name>glGetBooleanIndexedvEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param group="Boolean" len="COMPSIZE(target)"><ptype>GLboolean</ptype> *<name>data</name></param>
             <alias name="glGetBooleani_v"/>
+            <glx type="single" opcode="210"/>
         </command>
         <command>
             <proto>void <name>glGetBooleani_v</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param group="Boolean" len="COMPSIZE(target)"><ptype>GLboolean</ptype> *<name>data</name></param>
         </command>
@@ -14235,7 +16012,7 @@
         </command>
         <command>
             <proto>void <name>glGetBufferParameterui64vNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint64EXT</ptype> *<name>params</name></param>
         </command>
@@ -14254,8 +16031,8 @@
         </command>
         <command>
             <proto>void <name>glGetBufferPointervOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferPointerNameARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>void **<name>params</name></param>
             <alias name="glGetBufferPointerv"/>
         </command>
@@ -14282,23 +16059,23 @@
         </command>
         <command>
             <proto>void <name>glGetClipPlanef</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4"><ptype>GLfloat</ptype> *<name>equation</name></param>
         </command>
         <command>
             <proto>void <name>glGetClipPlanefOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4"><ptype>GLfloat</ptype> *<name>equation</name></param>
             <glx type="vendor" opcode="1421"/>
         </command>
         <command>
             <proto>void <name>glGetClipPlanex</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4"><ptype>GLfixed</ptype> *<name>equation</name></param>
         </command>
         <command>
             <proto>void <name>glGetClipPlanexOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>plane</name></param>
+            <param group="ClipPlaneName"><ptype>GLenum</ptype> <name>plane</name></param>
             <param len="4"><ptype>GLfixed</ptype> *<name>equation</name></param>
         </command>
         <command>
@@ -14321,14 +16098,14 @@
         <command>
             <proto>void <name>glGetColorTableParameterfv</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="single" opcode="148"/>
         </command>
         <command>
             <proto>void <name>glGetColorTableParameterfvEXT</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <alias name="glGetColorTableParameterfv"/>
         </command>
@@ -14342,14 +16119,14 @@
         <command>
             <proto>void <name>glGetColorTableParameteriv</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="149"/>
         </command>
         <command>
             <proto>void <name>glGetColorTableParameterivEXT</name></proto>
             <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetColorTableParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetColorTableParameterPNameSGI"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetColorTableParameteriv"/>
         </command>
@@ -14483,7 +16260,7 @@
         <command>
             <proto>void <name>glGetConvolutionParameterfv</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetConvolutionParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="single" opcode="151"/>
         </command>
@@ -14497,7 +16274,7 @@
         <command>
             <proto>void <name>glGetConvolutionParameteriv</name></proto>
             <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetConvolutionParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ConvolutionParameterEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="152"/>
         </command>
@@ -14523,10 +16300,10 @@
             <proto><ptype>GLuint</ptype> <name>glGetDebugMessageLog</name></proto>
             <param><ptype>GLuint</ptype> <name>count</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>sources</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>types</name></param>
+            <param len="count" group="DebugSource"><ptype>GLenum</ptype> *<name>sources</name></param>
+            <param len="count" group="DebugType"><ptype>GLenum</ptype> *<name>types</name></param>
             <param len="count"><ptype>GLuint</ptype> *<name>ids</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>severities</name></param>
+            <param len="count" group="DebugSeverity"><ptype>GLenum</ptype> *<name>severities</name></param>
             <param len="count"><ptype>GLsizei</ptype> *<name>lengths</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>messageLog</name></param>
         </command>
@@ -14535,7 +16312,7 @@
             <param><ptype>GLuint</ptype> <name>count</name></param>
             <param><ptype>GLsizei</ptype> <name>bufsize</name></param>
             <param len="count"><ptype>GLenum</ptype> *<name>categories</name></param>
-            <param len="count"><ptype>GLuint</ptype> *<name>severities</name></param>
+            <param len="count" group="DebugSeverity"><ptype>GLuint</ptype> *<name>severities</name></param>
             <param len="count"><ptype>GLuint</ptype> *<name>ids</name></param>
             <param len="count"><ptype>GLsizei</ptype> *<name>lengths</name></param>
             <param len="bufsize"><ptype>GLchar</ptype> *<name>message</name></param>
@@ -14544,10 +16321,10 @@
             <proto><ptype>GLuint</ptype> <name>glGetDebugMessageLogARB</name></proto>
             <param><ptype>GLuint</ptype> <name>count</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>sources</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>types</name></param>
+            <param len="count" group="DebugSource"><ptype>GLenum</ptype> *<name>sources</name></param>
+            <param len="count" group="DebugType"><ptype>GLenum</ptype> *<name>types</name></param>
             <param len="count"><ptype>GLuint</ptype> *<name>ids</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>severities</name></param>
+            <param len="count" group="DebugSeverity"><ptype>GLenum</ptype> *<name>severities</name></param>
             <param len="count"><ptype>GLsizei</ptype> *<name>lengths</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>messageLog</name></param>
             <alias name="glGetDebugMessageLog"/>
@@ -14556,10 +16333,10 @@
             <proto><ptype>GLuint</ptype> <name>glGetDebugMessageLogKHR</name></proto>
             <param><ptype>GLuint</ptype> <name>count</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>sources</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>types</name></param>
+            <param len="count" group="DebugSource"><ptype>GLenum</ptype> *<name>sources</name></param>
+            <param len="count" group="DebugType"><ptype>GLenum</ptype> *<name>types</name></param>
             <param len="count"><ptype>GLuint</ptype> *<name>ids</name></param>
-            <param len="count"><ptype>GLenum</ptype> *<name>severities</name></param>
+            <param len="count" group="DebugSeverity"><ptype>GLenum</ptype> *<name>severities</name></param>
             <param len="count"><ptype>GLsizei</ptype> *<name>lengths</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>messageLog</name></param>
             <alias name="glGetDebugMessageLog"/>
@@ -14579,7 +16356,7 @@
         </command>
         <command>
             <proto>void <name>glGetDoublei_v</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="COMPSIZE(target)"><ptype>GLdouble</ptype> *<name>data</name></param>
         </command>
@@ -14640,12 +16417,12 @@
         </command>
         <command>
             <proto>void <name>glGetFixedv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetFixedvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -14676,6 +16453,13 @@
             <alias name="glGetFloati_v"/>
         </command>
         <command>
+            <proto>void <name>glGetFloati_vOES</name></proto>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param len="COMPSIZE(target)"><ptype>GLfloat</ptype> *<name>data</name></param>
+            <alias name="glGetFloati_v"/>
+        </command>
+        <command>
             <proto>void <name>glGetFloatv</name></proto>
             <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>data</name></param>
@@ -14735,7 +16519,7 @@
             <proto>void <name>glGetFramebufferAttachmentParameteriv</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="1428"/>
         </command>
@@ -14743,22 +16527,31 @@
             <proto>void <name>glGetFramebufferAttachmentParameterivEXT</name></proto>
             <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetFramebufferAttachmentParameteriv"/>
             <glx type="vendor" opcode="1428"/>
         </command>
         <command>
             <proto>void <name>glGetFramebufferAttachmentParameterivOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
+            <proto>void <name>glGetFramebufferParameterfvAMD</name></proto>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLuint</ptype> <name>numsamples</name></param>
+            <param><ptype>GLuint</ptype> <name>pixelindex</name></param>
+            <param><ptype>GLsizei</ptype> <name>size</name></param>
+            <param><ptype>GLfloat</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto>void <name>glGetFramebufferParameteriv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -14768,16 +16561,20 @@
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glGetGraphicsResetStatus</name></proto>
+            <proto><ptype>GLsizei</ptype> <name>glGetFramebufferPixelLocalStorageSizeEXT</name></proto>
+            <param group="FramebufferTarget"><ptype>GLuint</ptype> <name>target</name></param>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusARB</name></proto>
+            <proto group="GraphicsResetStatus"><ptype>GLenum</ptype> <name>glGetGraphicsResetStatus</name></proto>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusEXT</name></proto>
+            <proto group="GraphicsResetStatus"><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusARB</name></proto>
         </command>
         <command>
-            <proto><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusKHR</name></proto>
+            <proto group="GraphicsResetStatus"><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusEXT</name></proto>
+        </command>
+        <command>
+            <proto group="GraphicsResetStatus"><ptype>GLenum</ptype> <name>glGetGraphicsResetStatusKHR</name></proto>
             <alias name="glGetGraphicsResetStatus"/>
         </command>
         <command>
@@ -14786,7 +16583,7 @@
         </command>
         <command>
             <proto>void <name>glGetHistogram</name></proto>
-            <param group="HistogramTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>reset</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -14805,8 +16602,8 @@
         </command>
         <command>
             <proto>void <name>glGetHistogramParameterfv</name></proto>
-            <param group="HistogramTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetHistogramParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetHistogramParameterPNameEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="single" opcode="155"/>
         </command>
@@ -14819,8 +16616,8 @@
         </command>
         <command>
             <proto>void <name>glGetHistogramParameteriv</name></proto>
-            <param group="HistogramTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetHistogramParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetHistogramParameterPNameEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="156"/>
         </command>
@@ -14833,8 +16630,8 @@
         </command>
         <command>
             <proto>void <name>glGetHistogramParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetHistogramParameterPNameEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -14843,7 +16640,7 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLboolean</ptype> <name>layered</name></param>
             <param><ptype>GLint</ptype> <name>layer</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
         </command>
         <command>
             <proto><ptype>GLuint64</ptype> <name>glGetImageHandleNV</name></proto>
@@ -14851,7 +16648,7 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>layered</name></param>
             <param><ptype>GLint</ptype> <name>layer</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
         </command>
         <command>
             <proto>void <name>glGetImageTransformParameterfvHP</name></proto>
@@ -14878,18 +16675,18 @@
         </command>
         <command>
             <proto>void <name>glGetInteger64i_v</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="COMPSIZE(target)"><ptype>GLint64</ptype> *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glGetInteger64v</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint64</ptype> *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glGetInteger64vAPPLE</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint64</ptype> *<name>params</name></param>
             <alias name="glGetInteger64v"/>
         </command>
@@ -14899,16 +16696,17 @@
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="COMPSIZE(target)"><ptype>GLint</ptype> *<name>data</name></param>
             <alias name="glGetIntegeri_v"/>
+            <glx type="single" opcode="211"/>
         </command>
         <command>
             <proto>void <name>glGetIntegeri_v</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="COMPSIZE(target)"><ptype>GLint</ptype> *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glGetIntegeri_vEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> *<name>data</name></param>
         </command>
@@ -14931,26 +16729,26 @@
         </command>
         <command>
             <proto>void <name>glGetInternalformatSampleivNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="InternalFormatPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetInternalformati64v</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormatPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetInternalformativ</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormatPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
@@ -14988,20 +16786,20 @@
         </command>
         <command>
             <proto>void <name>glGetLightxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetLightxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetLightxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -15093,8 +16891,8 @@
         </command>
         <command>
             <proto>void <name>glGetMapxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetMapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param len="COMPSIZE(query)"><ptype>GLfixed</ptype> *<name>v</name></param>
         </command>
         <command>
@@ -15113,25 +16911,31 @@
         </command>
         <command>
             <proto>void <name>glGetMaterialxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetMaterialxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetMaterialxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
+            <proto>void <name>glGetMemoryObjectParameterivEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memoryObject</name></param>
+            <param group="MemoryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLint</ptype> *<name>params</name></param>
+        </command>
+        <command>
             <proto>void <name>glGetMinmax</name></proto>
-            <param group="MinmaxTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>reset</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
@@ -15150,8 +16954,8 @@
         </command>
         <command>
             <proto>void <name>glGetMinmaxParameterfv</name></proto>
-            <param group="MinmaxTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetMinmaxParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetMinmaxParameterPNameEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="single" opcode="158"/>
         </command>
@@ -15164,8 +16968,8 @@
         </command>
         <command>
             <proto>void <name>glGetMinmaxParameteriv</name></proto>
-            <param group="MinmaxTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="GetMinmaxParameterPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetMinmaxParameterPNameEXT"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="159"/>
         </command>
@@ -15266,7 +17070,7 @@
         </command>
         <command>
             <proto>void <name>glGetMultisamplefv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetMultisamplePNameNV"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>val</name></param>
         </command>
@@ -15280,13 +17084,13 @@
         <command>
             <proto>void <name>glGetNamedBufferParameteri64v</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexBufferObjectParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetNamedBufferParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexBufferObjectParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -15304,7 +17108,7 @@
         <command>
             <proto>void <name>glGetNamedBufferPointerv</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexBufferObjectParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>void **<name>params</name></param>
         </command>
         <command>
@@ -15328,10 +17132,19 @@
             <param len="COMPSIZE(size)">void *<name>data</name></param>
         </command>
         <command>
+            <proto>void <name>glGetNamedFramebufferParameterfvAMD</name></proto>
+            <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLuint</ptype> <name>numsamples</name></param>
+            <param><ptype>GLuint</ptype> <name>pixelindex</name></param>
+            <param><ptype>GLsizei</ptype> <name>size</name></param>
+            <param><ptype>GLfloat</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto>void <name>glGetNamedFramebufferAttachmentParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="FramebufferAttachmentParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -15344,7 +17157,7 @@
         <command>
             <proto>void <name>glGetNamedFramebufferParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetFramebufferParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -15392,13 +17205,13 @@
             <proto>void <name>glGetNamedProgramivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param group="ProgramTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="ProgramProperty"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ProgramPropertyARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetNamedRenderbufferParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="RenderbufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -15660,7 +17473,7 @@
             <param><ptype>GLuint</ptype> <name>queryHandle</name></param>
             <param><ptype>GLuint</ptype> <name>flags</name></param>
             <param><ptype>GLsizei</ptype> <name>dataSize</name></param>
-            <param><ptype>GLvoid</ptype> *<name>data</name></param>
+            <param>void *<name>data</name></param>
             <param><ptype>GLuint</ptype> *<name>bytesWritten</name></param>
         </command>
         <command>
@@ -15701,7 +17514,7 @@
         </command>
         <command>
             <proto>void <name>glGetPixelMapxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
             <param len="size"><ptype>GLfixed</ptype> *<name>values</name></param>
         </command>
@@ -15717,14 +17530,14 @@
         </command>
         <command>
             <proto>void <name>glGetPixelTransformParameterfvEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="2051"/>
         </command>
         <command>
             <proto>void <name>glGetPixelTransformParameterivEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TypeEnum"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="2052"/>
@@ -15817,8 +17630,8 @@
         <command>
             <proto>void <name>glGetProgramInterfaceiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterfacePName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -15894,43 +17707,43 @@
         <command>
             <proto>void <name>glGetProgramPipelineiv</name></proto>
             <param><ptype>GLuint</ptype> <name>pipeline</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PipelineParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetProgramPipelineivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>pipeline</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PipelineParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glGetProgramResourceIndex</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param len="COMPSIZE(name)">const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetProgramResourceLocation</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param len="COMPSIZE(name)">const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetProgramResourceLocationIndex</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param len="COMPSIZE(name)">const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetProgramResourceLocationIndexEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param len="COMPSIZE(name)">const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto>void <name>glGetProgramResourceName</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
@@ -15939,7 +17752,7 @@
         <command>
             <proto>void <name>glGetProgramResourcefvNV</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLsizei</ptype> <name>propCount</name></param>
             <param>const <ptype>GLenum</ptype> *<name>props</name></param>
@@ -15950,7 +17763,7 @@
         <command>
             <proto>void <name>glGetProgramResourceiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>programInterface</name></param>
+            <param group="ProgramInterface"><ptype>GLenum</ptype> <name>programInterface</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLsizei</ptype> <name>propCount</name></param>
             <param len="propCount">const <ptype>GLenum</ptype> *<name>props</name></param>
@@ -15961,8 +17774,8 @@
         <command>
             <proto>void <name>glGetProgramStageiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ProgramStagePName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="1"><ptype>GLint</ptype> *<name>values</name></param>
         </command>
         <command>
@@ -15987,7 +17800,7 @@
         <command>
             <proto>void <name>glGetProgramiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ProgramPropertyARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="199"/>
         </command>
@@ -16008,47 +17821,47 @@
             <proto>void <name>glGetQueryBufferObjecti64v</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryBufferObjectiv</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryBufferObjectui64v</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryBufferObjectuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryIndexediv</name></proto>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryObjecti64v</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryObjecti64vEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint64</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="1328"/>
             <alias name="glGetQueryObjecti64v"/>
@@ -16056,34 +17869,34 @@
         <command>
             <proto>void <name>glGetQueryObjectiv</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="165"/>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectivARB</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetQueryObjectiv"/>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
-            <param><ptype>GLint</ptype> *<name>params</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetQueryObjectiv"/>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectui64v</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectui64vEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint64</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="1329"/>
             <alias name="glGetQueryObjectui64v"/>
@@ -16091,119 +17904,125 @@
         <command>
             <proto>void <name>glGetQueryObjectuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
             <glx type="single" opcode="166"/>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectuivARB</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
             <alias name="glGetQueryObjectuiv"/>
         </command>
         <command>
             <proto>void <name>glGetQueryObjectuivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
-            <param><ptype>GLuint</ptype> *<name>params</name></param>
+            <param group="QueryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetQueryiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="164"/>
         </command>
         <command>
             <proto>void <name>glGetQueryivARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetQueryiv"/>
         </command>
         <command>
             <proto>void <name>glGetQueryivEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
-            <param><ptype>GLint</ptype> *<name>params</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetRenderbufferParameteriv</name></proto>
             <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="RenderbufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="vendor" opcode="1424"/>
         </command>
         <command>
             <proto>void <name>glGetRenderbufferParameterivEXT</name></proto>
             <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="RenderbufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetRenderbufferParameteriv"/>
             <glx type="vendor" opcode="1424"/>
         </command>
         <command>
             <proto>void <name>glGetRenderbufferParameterivOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIiv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetSamplerParameterIiv"/>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIivOES</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetSamplerParameterIiv"/>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIuivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
             <alias name="glGetSamplerParameterIuiv"/>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterIuivOES</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint</ptype> *<name>params</name></param>
             <alias name="glGetSamplerParameterIuiv"/>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameterfv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetSamplerParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
+            <proto>void <name>glGetSemaphoreParameterui64vEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param group="SemaphoreParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLuint64</ptype> *<name>params</name></param>
+        </command>
+        <command>
             <proto>void <name>glGetSeparableFilter</name></proto>
-            <param group="SeparableTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="SeparableTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
             <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(target,format,type)">void *<name>row</name></param>
@@ -16232,10 +18051,10 @@
         </command>
         <command>
             <proto>void <name>glGetShaderPrecisionFormat</name></proto>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
-            <param><ptype>GLenum</ptype> <name>precisiontype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="PrecisionType"><ptype>GLenum</ptype> <name>precisiontype</name></param>
             <param len="2"><ptype>GLint</ptype> *<name>range</name></param>
-            <param len="2"><ptype>GLint</ptype> *<name>precision</name></param>
+            <param len="1"><ptype>GLint</ptype> *<name>precision</name></param>
         </command>
         <command>
             <proto>void <name>glGetShaderSource</name></proto>
@@ -16255,7 +18074,7 @@
         <command>
             <proto>void <name>glGetShaderiv</name></proto>
             <param><ptype>GLuint</ptype> <name>shader</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="ShaderParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
             <glx type="single" opcode="198"/>
         </command>
@@ -16267,7 +18086,7 @@
         </command>
         <command>
             <proto><ptype>GLushort</ptype> <name>glGetStageIndexNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
         </command>
         <command>
             <proto group="String">const <ptype>GLubyte</ptype> *<name>glGetString</name></proto>
@@ -16276,25 +18095,26 @@
         </command>
         <command>
             <proto group="String">const <ptype>GLubyte</ptype> *<name>glGetStringi</name></proto>
-            <param><ptype>GLenum</ptype> <name>name</name></param>
+            <param group="StringName"><ptype>GLenum</ptype> <name>name</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
+            <glx type="single" opcode="214"/>
         </command>
         <command>
             <proto><ptype>GLuint</ptype> <name>glGetSubroutineIndex</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param>const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetSubroutineUniformLocation</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param>const <ptype>GLchar</ptype> *<name>name</name></param>
         </command>
         <command>
             <proto>void <name>glGetSynciv</name></proto>
             <param group="sync"><ptype>GLsync</ptype> <name>sync</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SyncParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="1"><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>values</name></param>
@@ -16302,7 +18122,7 @@
         <command>
             <proto>void <name>glGetSyncivAPPLE</name></proto>
             <param><ptype>GLsync</ptype> <name>sync</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SyncParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLsizei</ptype> *<name>length</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>values</name></param>
@@ -16334,14 +18154,14 @@
         </command>
         <command>
             <proto>void <name>glGetTexEnvxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetTexEnvxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16367,8 +18187,8 @@
         </command>
         <command>
             <proto>void <name>glGetTexGenfvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16380,14 +18200,14 @@
         </command>
         <command>
             <proto>void <name>glGetTexGenivOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetTexGenxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16418,9 +18238,9 @@
         </command>
         <command>
             <proto>void <name>glGetTexLevelParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16487,14 +18307,14 @@
         </command>
         <command>
             <proto>void <name>glGetTexParameterxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetTexParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16502,6 +18322,11 @@
             <param><ptype>GLuint</ptype> <name>texture</name></param>
         </command>
         <command>
+            <proto><ptype>GLuint64</ptype> <name>glGetTextureHandleIMG</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <alias name="glGetTextureHandleARB"/>
+        </command>
+        <command>
             <proto><ptype>GLuint64</ptype> <name>glGetTextureHandleNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
         </command>
@@ -16509,8 +18334,8 @@
             <proto>void <name>glGetTextureImage</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>pixels</name></param>
         </command>
@@ -16527,7 +18352,7 @@
             <proto>void <name>glGetTextureLevelParameterfv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16542,7 +18367,7 @@
             <proto>void <name>glGetTextureLevelParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16556,7 +18381,7 @@
         <command>
             <proto>void <name>glGetTextureParameterIiv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16569,7 +18394,7 @@
         <command>
             <proto>void <name>glGetTextureParameterIuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLuint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16582,7 +18407,7 @@
         <command>
             <proto>void <name>glGetTextureParameterfv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16595,7 +18420,7 @@
         <command>
             <proto>void <name>glGetTextureParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -16611,6 +18436,12 @@
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
         </command>
         <command>
+            <proto><ptype>GLuint64</ptype> <name>glGetTextureSamplerHandleIMG</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLuint</ptype> <name>sampler</name></param>
+            <alias name="glGetTextureSamplerHandleARB"/>
+        </command>
+        <command>
             <proto><ptype>GLuint64</ptype> <name>glGetTextureSamplerHandleNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
@@ -16625,8 +18456,8 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>pixels</name></param>
         </command>
@@ -16647,6 +18478,7 @@
             <param len="1"><ptype>GLsizei</ptype> *<name>size</name></param>
             <param len="1"><ptype>GLenum</ptype> *<name>type</name></param>
             <param len="bufSize"><ptype>GLchar</ptype> *<name>name</name></param>
+            <glx type="single" opcode="213"/>
         </command>
         <command>
             <proto>void <name>glGetTransformFeedbackVaryingEXT</name></proto>
@@ -16668,21 +18500,21 @@
         <command>
             <proto>void <name>glGetTransformFeedbacki64_v</name></proto>
             <param><ptype>GLuint</ptype> <name>xfb</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TransformFeedbackPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint64</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetTransformFeedbacki_v</name></proto>
             <param><ptype>GLuint</ptype> <name>xfb</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TransformFeedbackPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetTransformFeedbackiv</name></proto>
             <param><ptype>GLuint</ptype> <name>xfb</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TransformFeedbackPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -16696,6 +18528,7 @@
             <proto><ptype>GLuint</ptype> <name>glGetUniformBlockIndex</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param len="COMPSIZE()">const <ptype>GLchar</ptype> *<name>uniformBlockName</name></param>
+            <glx type="single" opcode="218"/>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetUniformBufferSizeEXT</name></proto>
@@ -16708,6 +18541,7 @@
             <param><ptype>GLsizei</ptype> <name>uniformCount</name></param>
             <param len="COMPSIZE(uniformCount)">const <ptype>GLchar</ptype> *const*<name>uniformNames</name></param>
             <param len="COMPSIZE(uniformCount)"><ptype>GLuint</ptype> *<name>uniformIndices</name></param>
+            <glx type="single" opcode="215"/>
         </command>
         <command>
             <proto><ptype>GLint</ptype> <name>glGetUniformLocation</name></proto>
@@ -16727,7 +18561,7 @@
         </command>
         <command>
             <proto>void <name>glGetUniformSubroutineuiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param len="1"><ptype>GLuint</ptype> *<name>params</name></param>
         </command>
@@ -16801,6 +18635,17 @@
             <alias name="glGetUniformuiv"/>
         </command>
         <command>
+            <proto>void <name>glGetUnsignedBytevEXT</name></proto>
+            <param group="GetPName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param len="COMPSIZE(pname)"><ptype>GLubyte</ptype> *<name>data</name></param>
+        </command>
+        <command>
+            <proto>void <name>glGetUnsignedBytei_vEXT</name></proto>
+            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param len="COMPSIZE(target)"><ptype>GLubyte</ptype> *<name>data</name></param>
+        </command>
+        <command>
             <proto>void <name>glGetVariantArrayObjectfvATI</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param group="ArrayObjectPNameATI"><ptype>GLenum</ptype> <name>pname</name></param>
@@ -16845,46 +18690,46 @@
             <proto>void <name>glGetVertexArrayIndexed64iv</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint64</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayIndexediv</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayIntegeri_vEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayIntegervEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayPointeri_vEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>void **<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayPointervEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="1">void **<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexArrayiv</name></proto>
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexArrayPName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -16928,32 +18773,32 @@
         <command>
             <proto>void <name>glGetVertexAttribLdv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLdouble</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexAttribLdvEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLdouble</ptype> *<name>params</name></param>
             <alias name="glGetVertexAttribLdv"/>
         </command>
         <command>
             <proto>void <name>glGetVertexAttribLi64vNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLint64EXT</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexAttribLui64vARB</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLuint64EXT</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetVertexAttribLui64vNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)"><ptype>GLuint64EXT</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -17099,161 +18944,161 @@
         </command>
         <command>
             <proto>void <name>glGetnColorTable</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>table</name></param>
         </command>
         <command>
             <proto>void <name>glGetnColorTableARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorTableTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>table</name></param>
         </command>
         <command>
             <proto>void <name>glGetnCompressedTexImage</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>lod</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>pixels</name></param>
         </command>
         <command>
             <proto>void <name>glGetnCompressedTexImageARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>lod</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>img</name></param>
         </command>
         <command>
             <proto>void <name>glGetnConvolutionFilter</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>image</name></param>
         </command>
         <command>
             <proto>void <name>glGetnConvolutionFilterARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ConvolutionTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>image</name></param>
         </command>
         <command>
             <proto>void <name>glGetnHistogram</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLboolean</ptype> <name>reset</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnHistogramARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>reset</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapdv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLdouble</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapdvARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLdouble</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapfv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapfvARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLint</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMapivARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>query</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapQuery"><ptype>GLenum</ptype> <name>query</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>v</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMinmax</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLboolean</ptype> <name>reset</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param>void *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnMinmaxARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>reset</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapfv</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLfloat</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapfvARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLfloat</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapuiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLuint</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapuivARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLuint</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapusv</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param><ptype>GLushort</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glGetnPixelMapusvARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLushort</ptype> *<name>values</name></param>
         </command>
@@ -17269,9 +19114,9 @@
         </command>
         <command>
             <proto>void <name>glGetnSeparableFilter</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="SeparableTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>rowBufSize</name></param>
             <param>void *<name>row</name></param>
             <param><ptype>GLsizei</ptype> <name>columnBufSize</name></param>
@@ -17280,9 +19125,9 @@
         </command>
         <command>
             <proto>void <name>glGetnSeparableFilterARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="SeparableTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>rowBufSize</name></param>
             <param len="rowBufSize">void *<name>row</name></param>
             <param><ptype>GLsizei</ptype> <name>columnBufSize</name></param>
@@ -17291,19 +19136,19 @@
         </command>
         <command>
             <proto>void <name>glGetnTexImage</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param>void *<name>pixels</name></param>
+            <param len="bufSize">void *<name>pixels</name></param>
         </command>
         <command>
             <proto>void <name>glGetnTexImageARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>img</name></param>
         </command>
@@ -17312,7 +19157,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLdouble</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLdouble</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformdvARB</name></proto>
@@ -17326,7 +19171,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLfloat</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformfvARB</name></proto>
@@ -17341,13 +19186,14 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLfloat</ptype> *<name>params</name></param>
+            <alias name="glGetnUniformfv"/>
         </command>
         <command>
             <proto>void <name>glGetnUniformfvKHR</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLfloat</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLfloat</ptype> *<name>params</name></param>
             <alias name="glGetnUniformfv"/>
         </command>
         <command>
@@ -17355,14 +19201,14 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLint64</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLint</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformivARB</name></proto>
@@ -17377,13 +19223,14 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize"><ptype>GLint</ptype> *<name>params</name></param>
+            <alias name="glGetnUniformiv"/>
         </command>
         <command>
             <proto>void <name>glGetnUniformivKHR</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLint</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLint</ptype> *<name>params</name></param>
             <alias name="glGetnUniformiv"/>
         </command>
         <command>
@@ -17391,14 +19238,14 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLuint64</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLuint64</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLuint</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLuint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glGetnUniformuivARB</name></proto>
@@ -17412,7 +19259,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param><ptype>GLuint</ptype> *<name>params</name></param>
+            <param len="bufSize"><ptype>GLuint</ptype> *<name>params</name></param>
             <alias name="glGetnUniformuiv"/>
         </command>
         <command>
@@ -17460,9 +19307,9 @@
         </command>
         <command>
             <proto>void <name>glHistogram</name></proto>
-            <param group="HistogramTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>sink</name></param>
             <glx type="render" opcode="4110"/>
         </command>
@@ -17470,7 +19317,7 @@
             <proto>void <name>glHistogramEXT</name></proto>
             <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>sink</name></param>
             <alias name="glHistogram"/>
             <glx type="render" opcode="4110"/>
@@ -17506,6 +19353,45 @@
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
+            <proto>void <name>glImportMemoryFdEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>size</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param><ptype>GLint</ptype> <name>fd</name></param>
+        </command>
+        <command>
+            <proto>void <name>glImportMemoryWin32HandleEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>size</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param>void *<name>handle</name></param>
+        </command>
+        <command>
+            <proto>void <name>glImportMemoryWin32NameEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>size</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param>const void *<name>name</name></param>
+        </command>
+        <command>
+            <proto>void <name>glImportSemaphoreFdEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param><ptype>GLint</ptype> <name>fd</name></param>
+        </command>
+        <command>
+            <proto>void <name>glImportSemaphoreWin32HandleEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param>void *<name>handle</name></param>
+        </command>
+        <command>
+            <proto>void <name>glImportSemaphoreWin32NameEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param group="ExternalHandleType"><ptype>GLenum</ptype> <name>handleType</name></param>
+            <param>const void *<name>name</name></param>
+        </command>
+        <command>
             <proto group="sync"><ptype>GLsync</ptype> <name>glImportSyncEXT</name></proto>
             <param><ptype>GLenum</ptype> <name>external_sync_type</name></param>
             <param><ptype>GLintptr</ptype> <name>external_sync</name></param>
@@ -17655,7 +19541,7 @@
         </command>
         <command>
             <proto>void <name>glInvalidateFramebuffer</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="FramebufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>numAttachments</name></param>
             <param len="numAttachments">const <ptype>GLenum</ptype> *<name>attachments</name></param>
         </command>
@@ -17663,13 +19549,13 @@
             <proto>void <name>glInvalidateNamedFramebufferData</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>numAttachments</name></param>
-            <param>const <ptype>GLenum</ptype> *<name>attachments</name></param>
+            <param group="FramebufferAttachment">const <ptype>GLenum</ptype> *<name>attachments</name></param>
         </command>
         <command>
             <proto>void <name>glInvalidateNamedFramebufferSubData</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>numAttachments</name></param>
-            <param>const <ptype>GLenum</ptype> *<name>attachments</name></param>
+            <param group="FramebufferAttachment">const <ptype>GLenum</ptype> *<name>attachments</name></param>
             <param><ptype>GLint</ptype> <name>x</name></param>
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -17679,7 +19565,7 @@
             <proto>void <name>glInvalidateSubFramebuffer</name></proto>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>numAttachments</name></param>
-            <param len="numAttachments">const <ptype>GLenum</ptype> *<name>attachments</name></param>
+            <param len="numAttachments" group="FramebufferAttachment">const <ptype>GLenum</ptype> *<name>attachments</name></param>
             <param><ptype>GLint</ptype> <name>x</name></param>
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -17729,30 +19615,31 @@
         </command>
         <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsEnabledIndexedEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glIsEnabledi"/>
+            <glx type="single" opcode="212"/>
         </command>
         <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsEnabledi</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
         </command>
         <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsEnablediEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glIsEnabledi"/>
         </command>
         <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsEnablediNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glIsEnabledi"/>
         </command>
         <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsEnablediOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="EnableCap"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <alias name="glIsEnabledi"/>
         </command>
@@ -17794,6 +19681,10 @@
             <glx type="single" opcode="141"/>
         </command>
         <command>
+            <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsMemoryObjectEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memoryObject</name></param>
+        </command>
+        <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsNameAMD</name></proto>
             <param><ptype>GLenum</ptype> <name>identifier</name></param>
             <param><ptype>GLuint</ptype> <name>name</name></param>
@@ -17886,6 +19777,10 @@
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
         </command>
         <command>
+            <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsSemaphoreEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+        </command>
+        <command>
             <proto group="Boolean"><ptype>GLboolean</ptype> <name>glIsSampler</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
         </command>
@@ -17960,6 +19855,37 @@
             <param><ptype>GLenum</ptype> <name>pname</name></param>
         </command>
         <command>
+            <proto>void <name>glLGPUCopyImageSubDataNVX</name></proto>
+            <param><ptype>GLuint</ptype> <name>sourceGpu</name></param>
+            <param><ptype>GLbitfield</ptype> <name>destinationGpuMask</name></param>
+            <param><ptype>GLuint</ptype> <name>srcName</name></param>
+            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param><ptype>GLint</ptype> <name>srcLevel</name></param>
+            <param><ptype>GLint</ptype> <name>srcX</name></param>
+            <param><ptype>GLint</ptype> <name>srxY</name></param>
+            <param><ptype>GLint</ptype> <name>srcZ</name></param>
+            <param><ptype>GLuint</ptype> <name>dstName</name></param>
+            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param><ptype>GLint</ptype> <name>dstLevel</name></param>
+            <param><ptype>GLint</ptype> <name>dstX</name></param>
+            <param><ptype>GLint</ptype> <name>dstY</name></param>
+            <param><ptype>GLint</ptype> <name>dstZ</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
+        </command>
+        <command>
+            <proto>void <name>glLGPUInterlockNVX</name></proto>
+        </command>
+        <command>
+            <proto>void <name>glLGPUNamedBufferSubDataNVX</name></proto>
+            <param><ptype>GLbitfield</ptype> <name>gpuMask</name></param>
+            <param><ptype>GLuint</ptype> <name>buffer</name></param>
+            <param><ptype>GLintptr</ptype> <name>offset</name></param>
+            <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param>const void *<name>data</name></param>
+        </command>
+        <command>
             <proto>void <name>glLabelObjectEXT</name></proto>
             <param><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>object</name></param>
@@ -17997,22 +19923,22 @@
         </command>
         <command>
             <proto>void <name>glLightModelx</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightModelParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glLightModelxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightModelParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glLightModelxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightModelParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glLightModelxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightModelParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -18045,26 +19971,26 @@
         </command>
         <command>
             <proto>void <name>glLightx</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glLightxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glLightxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glLightxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>light</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="LightName"><ptype>GLenum</ptype> <name>light</name></param>
+            <param group="LightParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -18287,7 +20213,7 @@
         </command>
         <command>
             <proto>void <name>glMap1xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLfixed</ptype> <name>u1</name></param>
             <param><ptype>GLfixed</ptype> <name>u2</name></param>
             <param><ptype>GLint</ptype> <name>stride</name></param>
@@ -18324,7 +20250,7 @@
         </command>
         <command>
             <proto>void <name>glMap2xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MapTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLfixed</ptype> <name>u1</name></param>
             <param><ptype>GLfixed</ptype> <name>u2</name></param>
             <param><ptype>GLint</ptype> <name>ustride</name></param>
@@ -18348,8 +20274,8 @@
         </command>
         <command>
             <proto>void *<name>glMapBufferOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>access</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferAccessARB"><ptype>GLenum</ptype> <name>access</name></param>
             <alias name="glMapBuffer"/>
         </command>
         <command>
@@ -18362,10 +20288,10 @@
         </command>
         <command>
             <proto>void *<name>glMapBufferRangeEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="BufferTargetARB"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
             <param><ptype>GLsizeiptr</ptype> <name>length</name></param>
-            <param><ptype>GLbitfield</ptype> <name>access</name></param>
+            <param group="BufferAccessMask"><ptype>GLbitfield</ptype> <name>access</name></param>
             <alias name="glMapBufferRange"/>
         </command>
         <command>
@@ -18431,19 +20357,19 @@
         <command>
             <proto>void *<name>glMapNamedBuffer</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param><ptype>GLenum</ptype> <name>access</name></param>
+            <param group="BufferAccessARB"><ptype>GLenum</ptype> <name>access</name></param>
         </command>
         <command>
             <proto>void *<name>glMapNamedBufferEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
-            <param group="VertexBufferObjectAccess"><ptype>GLenum</ptype> <name>access</name></param>
+            <param group="BufferAccessARB"><ptype>GLenum</ptype> <name>access</name></param>
         </command>
         <command>
             <proto>void *<name>glMapNamedBufferRange</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>length</name></param>
-            <param><ptype>GLbitfield</ptype> <name>access</name></param>
+            <param group="BufferAccessMask"><ptype>GLbitfield</ptype> <name>access</name></param>
         </command>
         <command>
             <proto>void *<name>glMapNamedBufferRangeEXT</name></proto>
@@ -18554,26 +20480,26 @@
         </command>
         <command>
             <proto>void <name>glMaterialx</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glMaterialxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glMaterialxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glMaterialxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>face</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="MaterialFace"><ptype>GLenum</ptype> <name>face</name></param>
+            <param group="MaterialParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -18596,7 +20522,7 @@
         <command>
             <proto>void <name>glMatrixIndexPointerOES</name></proto>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="MatrixIndexPointerTypeARB"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param len="COMPSIZE(size,type,stride)">const void *<name>pointer</name></param>
         </command>
@@ -18760,23 +20686,34 @@
             <param><ptype>GLfloat</ptype> <name>z</name></param>
         </command>
         <command>
-            <proto>void <name>glMaxShaderCompilerThreadsARB</name></proto>
+            <proto>void <name>glMaxShaderCompilerThreadsKHR</name></proto>
             <param><ptype>GLuint</ptype> <name>count</name></param>
         </command>
         <command>
+            <proto>void <name>glMaxShaderCompilerThreadsARB</name></proto>
+            <param><ptype>GLuint</ptype> <name>count</name></param>
+            <alias name="glMaxShaderCompilerThreadsKHR"/>
+        </command>
+        <command>
             <proto>void <name>glMemoryBarrier</name></proto>
-            <param><ptype>GLbitfield</ptype> <name>barriers</name></param>
+            <param group="MemoryBarrierMask"><ptype>GLbitfield</ptype> <name>barriers</name></param>
         </command>
         <command>
             <proto>void <name>glMemoryBarrierByRegion</name></proto>
-            <param><ptype>GLbitfield</ptype> <name>barriers</name></param>
+            <param group="MemoryBarrierMask"><ptype>GLbitfield</ptype> <name>barriers</name></param>
         </command>
         <command>
             <proto>void <name>glMemoryBarrierEXT</name></proto>
-            <param><ptype>GLbitfield</ptype> <name>barriers</name></param>
+            <param group="MemoryBarrierMask"><ptype>GLbitfield</ptype> <name>barriers</name></param>
             <alias name="glMemoryBarrier"/>
         </command>
         <command>
+            <proto>void <name>glMemoryObjectParameterivEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memoryObject</name></param>
+            <param group="MemoryObjectParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param>const <ptype>GLint</ptype> *<name>params</name></param>
+        </command>
+        <command>
             <proto>void <name>glMinSampleShading</name></proto>
             <param group="ColorF"><ptype>GLfloat</ptype> <name>value</name></param>
         </command>
@@ -18792,15 +20729,15 @@
         </command>
         <command>
             <proto>void <name>glMinmax</name></proto>
-            <param group="MinmaxTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>sink</name></param>
             <glx type="render" opcode="4111"/>
         </command>
         <command>
             <proto>void <name>glMinmaxEXT</name></proto>
             <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>sink</name></param>
             <alias name="glMinmax"/>
             <glx type="render" opcode="4111"/>
@@ -18862,14 +20799,14 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawArraysIndirect</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param len="COMPSIZE(drawcount,stride)">const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
             <proto>void <name>glMultiDrawArraysIndirectAMD</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>primcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
@@ -18877,7 +20814,7 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawArraysIndirectBindlessCountNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawCount</name></param>
             <param><ptype>GLsizei</ptype> <name>maxDrawCount</name></param>
@@ -18886,23 +20823,32 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawArraysIndirectBindlessNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawCount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param><ptype>GLint</ptype> <name>vertexBufferCount</name></param>
         </command>
         <command>
-            <proto>void <name>glMultiDrawArraysIndirectCountARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLintptr</ptype> <name>indirect</name></param>
+            <proto>void <name>glMultiDrawArraysIndirectCount</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param>const void *<name>indirect</name></param>
             <param><ptype>GLintptr</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>maxdrawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
+            <proto>void <name>glMultiDrawArraysIndirectCountARB</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param>const void *<name>indirect</name></param>
+            <param><ptype>GLintptr</ptype> <name>drawcount</name></param>
+            <param><ptype>GLsizei</ptype> <name>maxdrawcount</name></param>
+            <param><ptype>GLsizei</ptype> <name>stride</name></param>
+            <alias name="glMultiDrawArraysIndirectCount"/>
+        </command>
+        <command>
             <proto>void <name>glMultiDrawArraysIndirectEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param len="COMPSIZE(drawcount,stride)">const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
@@ -18925,7 +20871,7 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsBaseVertex</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param len="COMPSIZE(drawcount)">const <ptype>GLsizei</ptype> *<name>count</name></param>
             <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(drawcount)">const void *const*<name>indices</name></param>
@@ -18934,17 +20880,7 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsBaseVertexEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param len="COMPSIZE(drawcount)">const <ptype>GLsizei</ptype> *<name>count</name></param>
-            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
-            <param len="COMPSIZE(drawcount)">const void *const*<name>indices</name></param>
-            <param><ptype>GLsizei</ptype> <name>primcount</name></param>
-            <param len="COMPSIZE(drawcount)">const <ptype>GLint</ptype> *<name>basevertex</name></param>
-            <alias name="glMultiDrawElementsBaseVertex"/>
-        </command>
-        <command>
-            <proto>void <name>glMultiDrawElementsBaseVertexOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param len="COMPSIZE(drawcount)">const <ptype>GLsizei</ptype> *<name>count</name></param>
             <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(drawcount)">const void *const*<name>indices</name></param>
@@ -18963,16 +20899,16 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsIndirect</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(drawcount,stride)">const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsIndirectAMD</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>primcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
@@ -18980,8 +20916,8 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsIndirectBindlessCountNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawCount</name></param>
             <param><ptype>GLsizei</ptype> <name>maxDrawCount</name></param>
@@ -18990,26 +20926,36 @@
         </command>
         <command>
             <proto>void <name>glMultiDrawElementsIndirectBindlessNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawCount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param><ptype>GLint</ptype> <name>vertexBufferCount</name></param>
         </command>
         <command>
-            <proto>void <name>glMultiDrawElementsIndirectCountARB</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <proto>void <name>glMultiDrawElementsIndirectCount</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
             <param><ptype>GLenum</ptype> <name>type</name></param>
-            <param><ptype>GLintptr</ptype> <name>indirect</name></param>
+            <param>const void *<name>indirect</name></param>
             <param><ptype>GLintptr</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>maxdrawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
+            <proto>void <name>glMultiDrawElementsIndirectCountARB</name></proto>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
+            <param>const void *<name>indirect</name></param>
+            <param><ptype>GLintptr</ptype> <name>drawcount</name></param>
+            <param><ptype>GLsizei</ptype> <name>maxdrawcount</name></param>
+            <param><ptype>GLsizei</ptype> <name>stride</name></param>
+            <alias name="glMultiDrawElementsIndirectCount"/>
+        </command>
+        <command>
             <proto>void <name>glMultiDrawElementsIndirectEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PrimitiveType"><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="DrawElementsType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(drawcount,stride)">const void *<name>indirect</name></param>
             <param><ptype>GLsizei</ptype> <name>drawcount</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
@@ -19050,12 +20996,12 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord1bOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLbyte</ptype> <name>s</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord1bvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="1">const <ptype>GLbyte</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -19176,23 +21122,23 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord1xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLfixed</ptype> <name>s</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord1xvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="1">const <ptype>GLfixed</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord2bOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLbyte</ptype> <name>s</name></param>
             <param><ptype>GLbyte</ptype> <name>t</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord2bvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="2">const <ptype>GLbyte</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -19322,25 +21268,25 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord2xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLfixed</ptype> <name>s</name></param>
             <param><ptype>GLfixed</ptype> <name>t</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord2xvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="2">const <ptype>GLfixed</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord3bOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLbyte</ptype> <name>s</name></param>
             <param><ptype>GLbyte</ptype> <name>t</name></param>
             <param><ptype>GLbyte</ptype> <name>r</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord3bvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="3">const <ptype>GLbyte</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -19479,19 +21425,19 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord3xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLfixed</ptype> <name>s</name></param>
             <param><ptype>GLfixed</ptype> <name>t</name></param>
             <param><ptype>GLfixed</ptype> <name>r</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord3xvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="3">const <ptype>GLfixed</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoord4bOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLbyte</ptype> <name>s</name></param>
             <param><ptype>GLbyte</ptype> <name>t</name></param>
             <param><ptype>GLbyte</ptype> <name>r</name></param>
@@ -19499,7 +21445,7 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord4bvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="4">const <ptype>GLbyte</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -19647,7 +21593,7 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord4x</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLfixed</ptype> <name>s</name></param>
             <param><ptype>GLfixed</ptype> <name>t</name></param>
             <param><ptype>GLfixed</ptype> <name>r</name></param>
@@ -19655,7 +21601,7 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord4xOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param><ptype>GLfixed</ptype> <name>s</name></param>
             <param><ptype>GLfixed</ptype> <name>t</name></param>
             <param><ptype>GLfixed</ptype> <name>r</name></param>
@@ -19663,55 +21609,55 @@
         </command>
         <command>
             <proto>void <name>glMultiTexCoord4xvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
             <param len="4">const <ptype>GLfixed</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP1ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP1uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP2ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP2uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP4ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glMultiTexCoordP4uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TextureUnit"><ptype>GLenum</ptype> <name>texture</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -19802,7 +21748,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -19814,7 +21760,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -19827,7 +21773,7 @@
             <param group="TextureUnit"><ptype>GLenum</ptype> <name>texunit</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -19926,11 +21872,108 @@
             <param len="COMPSIZE(format,type,width,height,depth)">const void *<name>pixels</name></param>
         </command>
         <command>
+            <proto>void <name>glMulticastBarrierNV</name></proto>
+        </command>
+        <command>
+            <proto>void <name>glMulticastBlitFramebufferNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>srcGpu</name></param>
+            <param><ptype>GLuint</ptype> <name>dstGpu</name></param>
+            <param><ptype>GLint</ptype> <name>srcX0</name></param>
+            <param><ptype>GLint</ptype> <name>srcY0</name></param>
+            <param><ptype>GLint</ptype> <name>srcX1</name></param>
+            <param><ptype>GLint</ptype> <name>srcY1</name></param>
+            <param><ptype>GLint</ptype> <name>dstX0</name></param>
+            <param><ptype>GLint</ptype> <name>dstY0</name></param>
+            <param><ptype>GLint</ptype> <name>dstX1</name></param>
+            <param><ptype>GLint</ptype> <name>dstY1</name></param>
+            <param group="ClearBufferMask"><ptype>GLbitfield</ptype> <name>mask</name></param>
+            <param><ptype>GLenum</ptype> <name>filter</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastBufferSubDataNV</name></proto>
+            <param><ptype>GLbitfield</ptype> <name>gpuMask</name></param>
+            <param><ptype>GLuint</ptype> <name>buffer</name></param>
+            <param><ptype>GLintptr</ptype> <name>offset</name></param>
+            <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param>const void *<name>data</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastCopyBufferSubDataNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>readGpu</name></param>
+            <param><ptype>GLbitfield</ptype> <name>writeGpuMask</name></param>
+            <param><ptype>GLuint</ptype> <name>readBuffer</name></param>
+            <param><ptype>GLuint</ptype> <name>writeBuffer</name></param>
+            <param><ptype>GLintptr</ptype> <name>readOffset</name></param>
+            <param><ptype>GLintptr</ptype> <name>writeOffset</name></param>
+            <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastCopyImageSubDataNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>srcGpu</name></param>
+            <param><ptype>GLbitfield</ptype> <name>dstGpuMask</name></param>
+            <param><ptype>GLuint</ptype> <name>srcName</name></param>
+            <param><ptype>GLenum</ptype> <name>srcTarget</name></param>
+            <param><ptype>GLint</ptype> <name>srcLevel</name></param>
+            <param><ptype>GLint</ptype> <name>srcX</name></param>
+            <param><ptype>GLint</ptype> <name>srcY</name></param>
+            <param><ptype>GLint</ptype> <name>srcZ</name></param>
+            <param><ptype>GLuint</ptype> <name>dstName</name></param>
+            <param><ptype>GLenum</ptype> <name>dstTarget</name></param>
+            <param><ptype>GLint</ptype> <name>dstLevel</name></param>
+            <param><ptype>GLint</ptype> <name>dstX</name></param>
+            <param><ptype>GLint</ptype> <name>dstY</name></param>
+            <param><ptype>GLint</ptype> <name>dstZ</name></param>
+            <param><ptype>GLsizei</ptype> <name>srcWidth</name></param>
+            <param><ptype>GLsizei</ptype> <name>srcHeight</name></param>
+            <param><ptype>GLsizei</ptype> <name>srcDepth</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastFramebufferSampleLocationsfvNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>gpu</name></param>
+            <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
+            <param><ptype>GLuint</ptype> <name>start</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param>const <ptype>GLfloat</ptype> *<name>v</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastGetQueryObjecti64vNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>gpu</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLint64</ptype> *<name>params</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastGetQueryObjectivNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>gpu</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLint</ptype> *<name>params</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastGetQueryObjectui64vNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>gpu</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLuint64</ptype> *<name>params</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastGetQueryObjectuivNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>gpu</name></param>
+            <param><ptype>GLuint</ptype> <name>id</name></param>
+            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param><ptype>GLuint</ptype> *<name>params</name></param>
+        </command>
+        <command>
+            <proto>void <name>glMulticastWaitSyncNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>signalGpu</name></param>
+            <param><ptype>GLbitfield</ptype> <name>waitGpuMask</name></param>
+        </command>
+        <command>
             <proto>void <name>glNamedBufferData</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <param>const void *<name>data</name></param>
-            <param><ptype>GLenum</ptype> <name>usage</name></param>
+            <param group="VertexBufferObjectUsage"><ptype>GLenum</ptype> <name>usage</name></param>
         </command>
         <command>
             <proto>void <name>glNamedBufferDataEXT</name></proto>
@@ -19958,17 +22001,32 @@
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <param len="size">const void *<name>data</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
+        </command>
+        <command>
+            <proto>void <name>glNamedBufferStorageExternalEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>buffer</name></param>
+            <param><ptype>GLintptr</ptype> <name>offset</name></param>
+            <param><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param><ptype>GLeglClientBufferEXT</ptype> <name>clientBuffer</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
         </command>
         <command>
             <proto>void <name>glNamedBufferStorageEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
             <param len="size">const void *<name>data</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="MapBufferUsageMask"><ptype>GLbitfield</ptype> <name>flags</name></param>
             <alias name="glNamedBufferStorage"/>
         </command>
         <command>
+            <proto>void <name>glNamedBufferStorageMemEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>buffer</name></param>
+            <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
             <proto>void <name>glNamedBufferSubData</name></proto>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
@@ -19994,18 +22052,18 @@
         <command>
             <proto>void <name>glNamedFramebufferDrawBuffer</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>buf</name></param>
+            <param group="ColorBuffer"><ptype>GLenum</ptype> <name>buf</name></param>
         </command>
         <command>
             <proto>void <name>glNamedFramebufferDrawBuffers</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>n</name></param>
-            <param>const <ptype>GLenum</ptype> *<name>bufs</name></param>
+            <param group="ColorBuffer">const <ptype>GLenum</ptype> *<name>bufs</name></param>
         </command>
         <command>
             <proto>void <name>glNamedFramebufferParameteri</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="FramebufferParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>param</name></param>
         </command>
         <command>
@@ -20017,13 +22075,13 @@
         <command>
             <proto>void <name>glNamedFramebufferReadBuffer</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="ColorBuffer"><ptype>GLenum</ptype> <name>src</name></param>
         </command>
         <command>
             <proto>void <name>glNamedFramebufferRenderbuffer</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
-            <param><ptype>GLenum</ptype> <name>renderbuffertarget</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>renderbuffertarget</name></param>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
         </command>
         <command>
@@ -20050,11 +22108,18 @@
         <command>
             <proto>void <name>glNamedFramebufferTexture</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
         </command>
         <command>
+            <proto>void <name>glNamedFramebufferSamplePositionsfvAMD</name></proto>
+            <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
+            <param><ptype>GLuint</ptype> <name>numsamples</name></param>
+            <param><ptype>GLuint</ptype> <name>pixelindex</name></param>
+            <param>const <ptype>GLfloat</ptype> *<name>values</name></param>
+        </command>
+        <command>
             <proto>void <name>glNamedFramebufferTexture1DEXT</name></proto>
             <param group="Framebuffer"><ptype>GLuint</ptype> <name>framebuffer</name></param>
             <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
@@ -20097,7 +22162,7 @@
         <command>
             <proto>void <name>glNamedFramebufferTextureLayer</name></proto>
             <param><ptype>GLuint</ptype> <name>framebuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>attachment</name></param>
+            <param group="FramebufferAttachment"><ptype>GLenum</ptype> <name>attachment</name></param>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>layer</name></param>
@@ -20217,14 +22282,14 @@
         <command>
             <proto>void <name>glNamedRenderbufferStorage</name></proto>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
         <command>
             <proto>void <name>glNamedRenderbufferStorageEXT</name></proto>
             <param group="Renderbuffer"><ptype>GLuint</ptype> <name>renderbuffer</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -20232,7 +22297,7 @@
             <proto>void <name>glNamedRenderbufferStorageMultisample</name></proto>
             <param><ptype>GLuint</ptype> <name>renderbuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -20241,7 +22306,7 @@
             <param group="Renderbuffer"><ptype>GLuint</ptype> <name>renderbuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -20249,7 +22314,7 @@
             <proto>void <name>glNamedRenderbufferStorageMultisampleEXT</name></proto>
             <param group="Renderbuffer"><ptype>GLuint</ptype> <name>renderbuffer</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -20382,12 +22447,12 @@
         </command>
         <command>
             <proto>void <name>glNormalP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="NormalPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glNormalP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="NormalPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -20477,14 +22542,14 @@
         </command>
         <command>
             <proto>void <name>glObjectLabel</name></proto>
-            <param><ptype>GLenum</ptype> <name>identifier</name></param>
+            <param group="ObjectIdentifier"><ptype>GLenum</ptype> <name>identifier</name></param>
             <param><ptype>GLuint</ptype> <name>name</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param len="COMPSIZE(label,length)">const <ptype>GLchar</ptype> *<name>label</name></param>
         </command>
         <command>
             <proto>void <name>glObjectLabelKHR</name></proto>
-            <param><ptype>GLenum</ptype> <name>identifier</name></param>
+            <param group="ObjectIdentifier"><ptype>GLenum</ptype> <name>identifier</name></param>
             <param><ptype>GLuint</ptype> <name>name</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param>const <ptype>GLchar</ptype> *<name>label</name></param>
@@ -20589,23 +22654,23 @@
         </command>
         <command>
             <proto>void <name>glPatchParameterfv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PatchParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfloat</ptype> *<name>values</name></param>
         </command>
         <command>
             <proto>void <name>glPatchParameteri</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PatchParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glPatchParameteriEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PatchParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>value</name></param>
             <alias name="glPatchParameteri"/>
         </command>
         <command>
             <proto>void <name>glPatchParameteriOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PatchParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>value</name></param>
             <alias name="glPatchParameteri"/>
         </command>
@@ -20651,7 +22716,7 @@
             <param><ptype>GLuint</ptype> <name>firstPathName</name></param>
             <param><ptype>GLenum</ptype> <name>fontTarget</name></param>
             <param>const void *<name>fontName</name></param>
-            <param><ptype>GLbitfield</ptype> <name>fontStyle</name></param>
+            <param group="PathFontStyle"><ptype>GLbitfield</ptype> <name>fontStyle</name></param>
             <param><ptype>GLuint</ptype> <name>firstGlyphIndex</name></param>
             <param><ptype>GLsizei</ptype> <name>numGlyphs</name></param>
             <param><ptype>GLuint</ptype> <name>pathParameterTemplate</name></param>
@@ -20661,7 +22726,7 @@
             <proto><ptype>GLenum</ptype> <name>glPathGlyphIndexRangeNV</name></proto>
             <param><ptype>GLenum</ptype> <name>fontTarget</name></param>
             <param>const void *<name>fontName</name></param>
-            <param><ptype>GLbitfield</ptype> <name>fontStyle</name></param>
+            <param group="PathFontStyle"><ptype>GLbitfield</ptype> <name>fontStyle</name></param>
             <param><ptype>GLuint</ptype> <name>pathParameterTemplate</name></param>
             <param><ptype>GLfloat</ptype> <name>emScale</name></param>
             <param><ptype>GLuint</ptype> <name>baseAndCount</name>[2]</param>
@@ -20810,7 +22875,7 @@
         </command>
         <command>
             <proto>void <name>glPixelMapx</name></proto>
-            <param><ptype>GLenum</ptype> <name>map</name></param>
+            <param group="PixelMap"><ptype>GLenum</ptype> <name>map</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
             <param len="size">const <ptype>GLfixed</ptype> *<name>values</name></param>
         </command>
@@ -20828,7 +22893,7 @@
         </command>
         <command>
             <proto>void <name>glPixelStorex</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PixelStoreParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
@@ -20870,7 +22935,7 @@
         </command>
         <command>
             <proto>void <name>glPixelTransferxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PixelTransferParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
@@ -20999,22 +23064,22 @@
         </command>
         <command>
             <proto>void <name>glPointParameterx</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PointParameterNameARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glPointParameterxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PointParameterNameARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glPointParameterxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PointParameterNameARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glPointParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="PointParameterNameARB"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -21064,13 +23129,20 @@
             <glx type="render" opcode="192"/>
         </command>
         <command>
-            <proto>void <name>glPolygonOffsetClampEXT</name></proto>
+            <proto>void <name>glPolygonOffsetClamp</name></proto>
             <param><ptype>GLfloat</ptype> <name>factor</name></param>
             <param><ptype>GLfloat</ptype> <name>units</name></param>
             <param><ptype>GLfloat</ptype> <name>clamp</name></param>
             <glx type="render" opcode="4225"/>
         </command>
         <command>
+            <proto>void <name>glPolygonOffsetClampEXT</name></proto>
+            <param><ptype>GLfloat</ptype> <name>factor</name></param>
+            <param><ptype>GLfloat</ptype> <name>units</name></param>
+            <param><ptype>GLfloat</ptype> <name>clamp</name></param>
+            <alias name="glPolygonOffsetClamp"/>
+        </command>
+        <command>
             <proto>void <name>glPolygonOffsetEXT</name></proto>
             <param><ptype>GLfloat</ptype> <name>factor</name></param>
             <param><ptype>GLfloat</ptype> <name>bias</name></param>
@@ -21201,9 +23273,11 @@
         <command>
             <proto>void <name>glPrimitiveRestartIndexNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
+            <glx type="render" opcode="365"/>
         </command>
         <command>
             <proto>void <name>glPrimitiveRestartNV</name></proto>
+            <glx type="render" opcode="364"/>
         </command>
         <command>
             <proto>void <name>glPrioritizeTextures</name></proto>
@@ -21583,7 +23657,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="1">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform1dvEXT</name></proto>
@@ -21610,7 +23684,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="1">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform1fvEXT</name></proto>
@@ -21664,7 +23738,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="1">const <ptype>GLint</ptype> *<name>value</name></param>
+            <param len="count">const <ptype>GLint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform1ivEXT</name></proto>
@@ -21718,7 +23792,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
+            <param len="count">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform1uivEXT</name></proto>
@@ -21747,14 +23821,14 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="2">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*2">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform2dvEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*2">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform2f</name></proto>
@@ -21776,7 +23850,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="2">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*2">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform2fvEXT</name></proto>
@@ -21834,7 +23908,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="2">const <ptype>GLint</ptype> *<name>value</name></param>
+            <param len="count*2">const <ptype>GLint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform2ivEXT</name></proto>
@@ -21892,7 +23966,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="2">const <ptype>GLuint</ptype> *<name>value</name></param>
+            <param len="count*2">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform2uivEXT</name></proto>
@@ -21923,14 +23997,14 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="3">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*3">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform3dvEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*3">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform3f</name></proto>
@@ -21954,7 +24028,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="3">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*3">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform3fvEXT</name></proto>
@@ -22016,7 +24090,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="3">const <ptype>GLint</ptype> *<name>value</name></param>
+            <param len="count*3">const <ptype>GLint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform3ivEXT</name></proto>
@@ -22078,7 +24152,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="3">const <ptype>GLuint</ptype> *<name>value</name></param>
+            <param len="count*3">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform3uivEXT</name></proto>
@@ -22111,14 +24185,14 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="4">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform4dvEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform4f</name></proto>
@@ -22144,7 +24218,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="4">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform4fvEXT</name></proto>
@@ -22210,7 +24284,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="4">const <ptype>GLint</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform4ivEXT</name></proto>
@@ -22276,7 +24350,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
-            <param len="4">const <ptype>GLuint</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniform4uivEXT</name></proto>
@@ -22293,6 +24367,13 @@
             <param><ptype>GLuint64</ptype> <name>value</name></param>
         </command>
         <command>
+            <proto>void <name>glProgramUniformHandleui64IMG</name></proto>
+            <param><ptype>GLuint</ptype> <name>program</name></param>
+            <param><ptype>GLint</ptype> <name>location</name></param>
+            <param><ptype>GLuint64</ptype> <name>value</name></param>
+            <alias name="glProgramUniformHandleui64ARB"/>
+        </command>
+        <command>
             <proto>void <name>glProgramUniformHandleui64NV</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
@@ -22306,6 +24387,14 @@
             <param len="count">const <ptype>GLuint64</ptype> *<name>values</name></param>
         </command>
         <command>
+            <proto>void <name>glProgramUniformHandleui64vIMG</name></proto>
+            <param><ptype>GLuint</ptype> <name>program</name></param>
+            <param><ptype>GLint</ptype> <name>location</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param len="count">const <ptype>GLuint64</ptype> *<name>values</name></param>
+            <alias name="glProgramUniformHandleui64vARB"/>
+        </command>
+        <command>
             <proto>void <name>glProgramUniformHandleui64vNV</name></proto>
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLint</ptype> <name>location</name></param>
@@ -22318,7 +24407,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="2">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2dvEXT</name></proto>
@@ -22326,7 +24415,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2fv</name></proto>
@@ -22334,7 +24423,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="2">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*4">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2fvEXT</name></proto>
@@ -22351,7 +24440,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x3dvEXT</name></proto>
@@ -22359,7 +24448,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x3fv</name></proto>
@@ -22367,7 +24456,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x3fvEXT</name></proto>
@@ -22384,7 +24473,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x4dvEXT</name></proto>
@@ -22392,7 +24481,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x4fv</name></proto>
@@ -22400,7 +24489,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix2x4fvEXT</name></proto>
@@ -22417,7 +24506,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="3">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*9">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3dvEXT</name></proto>
@@ -22425,7 +24514,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*9">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3fv</name></proto>
@@ -22433,7 +24522,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="3">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*9">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3fvEXT</name></proto>
@@ -22450,7 +24539,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x2dvEXT</name></proto>
@@ -22458,7 +24547,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x2fv</name></proto>
@@ -22466,7 +24555,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*6">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x2fvEXT</name></proto>
@@ -22483,7 +24572,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x4dvEXT</name></proto>
@@ -22491,7 +24580,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x4fv</name></proto>
@@ -22499,7 +24588,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix3x4fvEXT</name></proto>
@@ -22516,7 +24605,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="4">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*16">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4dvEXT</name></proto>
@@ -22524,7 +24613,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*16">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4fv</name></proto>
@@ -22532,7 +24621,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="4">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*16">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4fvEXT</name></proto>
@@ -22549,7 +24638,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x2dvEXT</name></proto>
@@ -22557,7 +24646,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x2fv</name></proto>
@@ -22565,7 +24654,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*8">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x2fvEXT</name></proto>
@@ -22582,7 +24671,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x3dvEXT</name></proto>
@@ -22590,7 +24679,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLdouble</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLdouble</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x3fv</name></proto>
@@ -22598,7 +24687,7 @@
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>transpose</name></param>
-            <param len="count">const <ptype>GLfloat</ptype> *<name>value</name></param>
+            <param len="count*12">const <ptype>GLfloat</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glProgramUniformMatrix4x3fvEXT</name></proto>
@@ -22629,11 +24718,11 @@
         </command>
         <command>
             <proto>void <name>glProvokingVertex</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="VertexProvokingMode"><ptype>GLenum</ptype> <name>mode</name></param>
         </command>
         <command>
             <proto>void <name>glProvokingVertexEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param group="VertexProvokingMode"><ptype>GLenum</ptype> <name>mode</name></param>
             <alias name="glProvokingVertex"/>
         </command>
         <command>
@@ -22651,14 +24740,14 @@
         </command>
         <command>
             <proto>void <name>glPushDebugGroup</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param len="COMPSIZE(message,length)">const <ptype>GLchar</ptype> *<name>message</name></param>
         </command>
         <command>
             <proto>void <name>glPushDebugGroupKHR</name></proto>
-            <param><ptype>GLenum</ptype> <name>source</name></param>
+            <param group="DebugSource"><ptype>GLenum</ptype> <name>source</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLsizei</ptype> <name>length</name></param>
             <param>const <ptype>GLchar</ptype> *<name>message</name></param>
@@ -22681,12 +24770,12 @@
         <command>
             <proto>void <name>glQueryCounter</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
         </command>
         <command>
             <proto>void <name>glQueryCounterEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>id</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <alias name="glQueryCounter"/>
         </command>
         <command>
@@ -22696,12 +24785,24 @@
         </command>
         <command>
             <proto>void <name>glQueryObjectParameteruiAMD</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="QueryTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>id</name></param>
             <param><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="OcclusionQueryEventMaskAMD"><ptype>GLuint</ptype> <name>param</name></param>
         </command>
         <command>
+            <proto><ptype>GLint</ptype> <name>glQueryResourceNV</name></proto>
+            <param><ptype>GLenum</ptype> <name>queryType</name></param>
+            <param><ptype>GLint</ptype> <name>tagId</name></param>
+            <param><ptype>GLuint</ptype> <name>bufSize</name></param>
+            <param><ptype>GLint</ptype> *<name>buffer</name></param>
+        </command>
+        <command>
+            <proto>void <name>glQueryResourceTagNV</name></proto>
+            <param><ptype>GLint</ptype> <name>tagId</name></param>
+            <param>const <ptype>GLchar</ptype> *<name>tagString</name></param>
+        </command>
+        <command>
             <proto>void <name>glRasterPos2d</name></proto>
             <param group="CoordD"><ptype>GLdouble</ptype> <name>x</name></param>
             <param group="CoordD"><ptype>GLdouble</ptype> <name>y</name></param>
@@ -22887,7 +24988,7 @@
         </command>
         <command>
             <proto>void <name>glReadBufferIndexedEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>src</name></param>
+            <param group="ReadBufferMode"><ptype>GLenum</ptype> <name>src</name></param>
             <param><ptype>GLint</ptype> <name>index</name></param>
         </command>
         <command>
@@ -22917,10 +25018,10 @@
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
-            <param>void *<name>data</name></param>
+            <param len="bufSize">void *<name>data</name></param>
         </command>
         <command>
             <proto>void <name>glReadnPixelsARB</name></proto>
@@ -22928,8 +25029,8 @@
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>data</name></param>
             <alias name="glReadnPixels"/>
@@ -22940,8 +25041,8 @@
             <param><ptype>GLint</ptype> <name>y</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>bufSize</name></param>
             <param len="bufSize">void *<name>data</name></param>
             <alias name="glReadnPixels"/>
@@ -22959,6 +25060,11 @@
             <alias name="glReadnPixels"/>
         </command>
         <command>
+            <proto><ptype>GLboolean</ptype> <name>glReleaseKeyedMutexWin32EXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>key</name></param>
+        </command>
+        <command>
             <proto>void <name>glRectd</name></proto>
             <param group="CoordD"><ptype>GLdouble</ptype> <name>x1</name></param>
             <param group="CoordD"><ptype>GLdouble</ptype> <name>y1</name></param>
@@ -23035,6 +25141,10 @@
             <proto>void <name>glReleaseShaderCompiler</name></proto>
         </command>
         <command>
+            <proto>void <name>glRenderGpuMaskNV</name></proto>
+            <param><ptype>GLbitfield</ptype> <name>mask</name></param>
+        </command>
+        <command>
             <proto><ptype>GLint</ptype> <name>glRenderMode</name></proto>
             <param group="RenderingMode"><ptype>GLenum</ptype> <name>mode</name></param>
             <glx type="single" opcode="107"/>
@@ -23042,7 +25152,7 @@
         <command>
             <proto>void <name>glRenderbufferStorage</name></proto>
             <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <glx type="render" opcode="4318"/>
@@ -23050,7 +25160,7 @@
         <command>
             <proto>void <name>glRenderbufferStorageEXT</name></proto>
             <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <alias name="glRenderbufferStorage"/>
@@ -23058,26 +25168,26 @@
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisample</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <glx type="render" opcode="4331"/>
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisampleANGLE</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisampleAPPLE</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -23086,15 +25196,15 @@
             <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisampleEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <alias name="glRenderbufferStorageMultisample"/>
@@ -23102,25 +25212,25 @@
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisampleIMG</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageMultisampleNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <alias name="glRenderbufferStorageMultisample"/>
         </command>
         <command>
             <proto>void <name>glRenderbufferStorageOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="RenderbufferTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -23302,7 +25412,7 @@
         </command>
         <command>
             <proto>void <name>glResetHistogram</name></proto>
-            <param group="HistogramTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="HistogramTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <glx type="render" opcode="4112"/>
         </command>
         <command>
@@ -23313,7 +25423,7 @@
         </command>
         <command>
             <proto>void <name>glResetMinmax</name></proto>
-            <param group="MinmaxTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="MinmaxTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
             <glx type="render" opcode="4113"/>
         </command>
         <command>
@@ -23431,65 +25541,65 @@
         <command>
             <proto>void <name>glSamplerParameterIiv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glSamplerParameterIivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>param</name></param>
             <alias name="glSamplerParameterIiv"/>
         </command>
         <command>
             <proto>void <name>glSamplerParameterIivOES</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>param</name></param>
             <alias name="glSamplerParameterIiv"/>
         </command>
         <command>
             <proto>void <name>glSamplerParameterIuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLuint</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glSamplerParameterIuivEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLuint</ptype> *<name>param</name></param>
             <alias name="glSamplerParameterIuiv"/>
         </command>
         <command>
             <proto>void <name>glSamplerParameterIuivOES</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLuint</ptype> *<name>param</name></param>
             <alias name="glSamplerParameterIuiv"/>
         </command>
         <command>
             <proto>void <name>glSamplerParameterf</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfloat</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glSamplerParameterfv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfloat</ptype> *<name>param</name></param>
         </command>
         <command>
             <proto>void <name>glSamplerParameteri</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glSamplerParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>sampler</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="SamplerParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -23540,6 +25650,13 @@
             <alias name="glScissorArrayv"/>
         </command>
         <command>
+            <proto>void <name>glScissorArrayvOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>first</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param len="COMPSIZE(count)">const <ptype>GLint</ptype> *<name>v</name></param>
+            <alias name="glScissorArrayv"/>
+        </command>
+        <command>
             <proto>void <name>glScissorIndexed</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>left</name></param>
@@ -23557,6 +25674,15 @@
             <alias name="glScissorIndexed"/>
         </command>
         <command>
+            <proto>void <name>glScissorIndexedOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param><ptype>GLint</ptype> <name>left</name></param>
+            <param><ptype>GLint</ptype> <name>bottom</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <alias name="glScissorIndexed"/>
+        </command>
+        <command>
             <proto>void <name>glScissorIndexedv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="4">const <ptype>GLint</ptype> *<name>v</name></param>
@@ -23568,6 +25694,12 @@
             <alias name="glScissorIndexedv"/>
         </command>
         <command>
+            <proto>void <name>glScissorIndexedvOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param len="4">const <ptype>GLint</ptype> *<name>v</name></param>
+            <alias name="glScissorIndexedv"/>
+        </command>
+        <command>
             <proto>void <name>glSecondaryColor3b</name></proto>
             <param group="ColorB"><ptype>GLbyte</ptype> <name>red</name></param>
             <param group="ColorB"><ptype>GLbyte</ptype> <name>green</name></param>
@@ -23790,17 +25922,17 @@
         <command>
             <proto>void <name>glSecondaryColorFormatNV</name></proto>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
             <proto>void <name>glSecondaryColorP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>color</name></param>
         </command>
         <command>
             <proto>void <name>glSecondaryColorP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="ColorPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>color</name></param>
         </command>
         <command>
@@ -23841,9 +25973,15 @@
             <param len="numCounters"><ptype>GLuint</ptype> *<name>counterList</name></param>
         </command>
         <command>
+            <proto>void <name>glSemaphoreParameterui64vEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param group="SemaphoreParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
+            <param>const <ptype>GLuint64</ptype> *<name>params</name></param>
+        </command>
+        <command>
             <proto>void <name>glSeparableFilter2D</name></proto>
-            <param group="SeparableTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="SeparableTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -23856,7 +25994,7 @@
         <command>
             <proto>void <name>glSeparableFilter2DEXT</name></proto>
             <param group="SeparableTargetEXT"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -23961,6 +26099,32 @@
             <glx type="render" opcode="2052"/>
         </command>
         <command>
+            <proto>void <name>glSignalSemaphoreEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param><ptype>GLuint</ptype> <name>numBufferBarriers</name></param>
+            <param len="COMPSIZE(numBufferBarriers)">const <ptype>GLuint</ptype> *<name>buffers</name></param>
+            <param><ptype>GLuint</ptype> <name>numTextureBarriers</name></param>
+            <param len="COMPSIZE(numTextureBarriers)">const <ptype>GLuint</ptype> *<name>textures</name></param>
+            <param group="TextureLayout" len="COMPSIZE(numTextureBarriers)">const <ptype>GLenum</ptype> *<name>dstLayouts</name></param>
+        </command>
+        <command>
+            <proto>void <name>glSpecializeShader</name></proto>
+            <param><ptype>GLuint</ptype> <name>shader</name></param>
+            <param>const <ptype>GLchar</ptype> *<name>pEntryPoint</name></param>
+            <param><ptype>GLuint</ptype> <name>numSpecializationConstants</name></param>
+            <param>const <ptype>GLuint</ptype> *<name>pConstantIndex</name></param>
+            <param>const <ptype>GLuint</ptype> *<name>pConstantValue</name></param>
+        </command>
+        <command>
+            <proto>void <name>glSpecializeShaderARB</name></proto>
+            <param><ptype>GLuint</ptype> <name>shader</name></param>
+            <param>const <ptype>GLchar</ptype> *<name>pEntryPoint</name></param>
+            <param><ptype>GLuint</ptype> <name>numSpecializationConstants</name></param>
+            <param>const <ptype>GLuint</ptype> *<name>pConstantIndex</name></param>
+            <param>const <ptype>GLuint</ptype> *<name>pConstantValue</name></param>
+            <alias name="glSpecializeShader"/>
+        </command>
+        <command>
             <proto>void <name>glSpriteParameterfSGIX</name></proto>
             <param group="SpriteParameterNameSGIX"><ptype>GLenum</ptype> <name>pname</name></param>
             <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>param</name></param>
@@ -23994,7 +26158,7 @@
             <param><ptype>GLuint</ptype> <name>y</name></param>
             <param><ptype>GLuint</ptype> <name>width</name></param>
             <param><ptype>GLuint</ptype> <name>height</name></param>
-            <param><ptype>GLbitfield</ptype> <name>preserveMask</name></param>
+            <param group="BufferBitQCOM"><ptype>GLbitfield</ptype> <name>preserveMask</name></param>
         </command>
         <command>
             <proto>void <name>glStateCaptureNV</name></proto>
@@ -24259,42 +26423,43 @@
         <command>
             <proto>void <name>glTexBuffer</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
         </command>
         <command>
             <proto>void <name>glTexBufferARB</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <alias name="glTexBuffer"/>
+            <glx type="render" opcode="367"/>
         </command>
         <command>
             <proto>void <name>glTexBufferEXT</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <alias name="glTexBuffer"/>
         </command>
         <command>
             <proto>void <name>glTexBufferOES</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <alias name="glTexBuffer"/>
         </command>
         <command>
             <proto>void <name>glTexBufferRange</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
         </command>
         <command>
             <proto>void <name>glTexBufferRangeEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
@@ -24302,8 +26467,8 @@
         </command>
         <command>
             <proto>void <name>glTexBufferRangeOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
@@ -24761,42 +26926,42 @@
         </command>
         <command>
             <proto>void <name>glTexCoordP1ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP1uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP2ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP2uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP4ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>coords</name></param>
         </command>
         <command>
             <proto>void <name>glTexCoordP4uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="TexCoordPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>coords</name></param>
         </command>
         <command>
@@ -24858,26 +27023,26 @@
         </command>
         <command>
             <proto>void <name>glTexEnvx</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glTexEnvxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glTexEnvxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glTexEnvxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureEnvTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureEnvParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -24911,8 +27076,8 @@
         </command>
         <command>
             <proto>void <name>glTexGenfOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfloat</ptype> <name>param</name></param>
         </command>
         <command>
@@ -24924,8 +27089,8 @@
         </command>
         <command>
             <proto>void <name>glTexGenfvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfloat</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -24937,8 +27102,8 @@
         </command>
         <command>
             <proto>void <name>glTexGeniOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>param</name></param>
         </command>
         <command>
@@ -24950,27 +27115,27 @@
         </command>
         <command>
             <proto>void <name>glTexGenivOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glTexGenxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glTexGenxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>coord</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureCoordName"><ptype>GLenum</ptype> <name>coord</name></param>
+            <param group="TextureGenParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glTexImage1D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -24983,7 +27148,7 @@
             <proto>void <name>glTexImage2D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -24995,16 +27160,16 @@
         </command>
         <command>
             <proto>void <name>glTexImage2DMultisample</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>fixedsamplelocations</name></param>
         </command>
         <command>
             <proto>void <name>glTexImage2DMultisampleCoverageNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
@@ -25016,7 +27181,7 @@
             <proto>void <name>glTexImage3D</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25031,7 +27196,7 @@
             <proto>void <name>glTexImage3DEXT</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25044,9 +27209,9 @@
         </command>
         <command>
             <proto>void <name>glTexImage3DMultisample</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25054,7 +27219,7 @@
         </command>
         <command>
             <proto>void <name>glTexImage3DMultisampleCoverageNV</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
@@ -25065,23 +27230,22 @@
         </command>
         <command>
             <proto>void <name>glTexImage3DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
             <param><ptype>GLint</ptype> <name>border</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type,width,height,depth)">const void *<name>pixels</name></param>
-            <alias name="glTexImage3D"/>
         </command>
         <command>
             <proto>void <name>glTexImage4DSGIS</name></proto>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="PixelInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25189,26 +27353,26 @@
         </command>
         <command>
             <proto>void <name>glTexParameterx</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glTexParameterxOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfixed</ptype> <name>param</name></param>
         </command>
         <command>
             <proto>void <name>glTexParameterxv</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
             <proto>void <name>glTexParameterxvOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="GetTextureParameter"><ptype>GLenum</ptype> <name>pname</name></param>
             <param len="COMPSIZE(pname)">const <ptype>GLfixed</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -25218,59 +27382,59 @@
         </command>
         <command>
             <proto>void <name>glTexStorage1D</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
         </command>
         <command>
             <proto>void <name>glTexStorage1DEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <alias name="glTexStorage1D"/>
         </command>
         <command>
             <proto>void <name>glTexStorage2D</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
         <command>
             <proto>void <name>glTexStorage2DEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <alias name="glTexStorage2D"/>
         </command>
         <command>
             <proto>void <name>glTexStorage2DMultisample</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>fixedsamplelocations</name></param>
         </command>
         <command>
             <proto>void <name>glTexStorage3D</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
         </command>
         <command>
             <proto>void <name>glTexStorage3DEXT</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25278,9 +27442,9 @@
         </command>
         <command>
             <proto>void <name>glTexStorage3DMultisample</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25288,9 +27452,9 @@
         </command>
         <command>
             <proto>void <name>glTexStorage3DMultisampleOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25298,14 +27462,67 @@
             <alias name="glTexStorage3DMultisample"/>
         </command>
         <command>
-            <proto>void <name>glTexStorageSparseAMD</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <proto>void <name>glTexStorageMem1DEXT</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTexStorageMem2DEXT</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTexStorageMem2DMultisampleEXT</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>samples</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLboolean</ptype> <name>fixedSampleLocations</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTexStorageMem3DEXT</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
             <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTexStorageMem3DMultisampleEXT</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>samples</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
+            <param><ptype>GLboolean</ptype> <name>fixedSampleLocations</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTexStorageSparseAMD</name></proto>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
             <param><ptype>GLsizei</ptype> <name>layers</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="TextureStorageMaskAMD"><ptype>GLbitfield</ptype> <name>flags</name></param>
         </command>
         <command>
             <proto>void <name>glTexSubImage1D</name></proto>
@@ -25393,7 +27610,7 @@
         </command>
         <command>
             <proto>void <name>glTexSubImage3DOES</name></proto>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>xoffset</name></param>
             <param><ptype>GLint</ptype> <name>yoffset</name></param>
@@ -25401,10 +27618,9 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="COMPSIZE(format,type,width,height,depth)">const void *<name>pixels</name></param>
-            <alias name="glTexSubImage3D"/>
         </command>
         <command>
             <proto>void <name>glTexSubImage4DSGIS</name></proto>
@@ -25433,20 +27649,20 @@
         <command>
             <proto>void <name>glTextureBuffer</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
         </command>
         <command>
             <proto>void <name>glTextureBufferEXT</name></proto>
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
         </command>
         <command>
             <proto>void <name>glTextureBufferRange</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
@@ -25455,7 +27671,7 @@
             <proto>void <name>glTextureBufferRangeEXT</name></proto>
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>buffer</name></param>
             <param group="BufferOffset"><ptype>GLintptr</ptype> <name>offset</name></param>
             <param group="BufferSize"><ptype>GLsizeiptr</ptype> <name>size</name></param>
@@ -25469,11 +27685,22 @@
             <glx type="render" opcode="2082"/>
         </command>
         <command>
+            <proto>void <name>glTextureFoveationParametersQCOM</name></proto>
+            <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLuint</ptype> <name>layer</name></param>
+            <param><ptype>GLuint</ptype> <name>focalPoint</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>focalX</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>focalY</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>gainX</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>gainY</name></param>
+            <param group="CheckedFloat32"><ptype>GLfloat</ptype> <name>foveaArea</name></param>
+        </command>
+        <command>
             <proto>void <name>glTextureImage1DEXT</name></proto>
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
             <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
@@ -25485,7 +27712,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>border</name></param>
@@ -25496,7 +27723,7 @@
         <command>
             <proto>void <name>glTextureImage2DMultisampleCoverageNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
@@ -25507,7 +27734,7 @@
         <command>
             <proto>void <name>glTextureImage2DMultisampleNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -25519,7 +27746,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param group="CheckedInt32"><ptype>GLint</ptype> <name>level</name></param>
-            <param group="TextureComponentCount"><ptype>GLint</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLint</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25531,7 +27758,7 @@
         <command>
             <proto>void <name>glTextureImage3DMultisampleCoverageNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>coverageSamples</name></param>
             <param><ptype>GLsizei</ptype> <name>colorSamples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
@@ -25543,7 +27770,7 @@
         <command>
             <proto>void <name>glTextureImage3DMultisampleNV</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
             <param><ptype>GLint</ptype> <name>internalFormat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
@@ -25579,7 +27806,7 @@
         <command>
             <proto>void <name>glTextureParameterIiv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>const <ptype>GLint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -25592,7 +27819,7 @@
         <command>
             <proto>void <name>glTextureParameterIuiv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>const <ptype>GLuint</ptype> *<name>params</name></param>
         </command>
         <command>
@@ -25605,7 +27832,7 @@
         <command>
             <proto>void <name>glTextureParameterf</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLfloat</ptype> <name>param</name></param>
         </command>
         <command>
@@ -25619,7 +27846,7 @@
         <command>
             <proto>void <name>glTextureParameterfv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>const <ptype>GLfloat</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -25632,7 +27859,7 @@
         <command>
             <proto>void <name>glTextureParameteri</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param><ptype>GLint</ptype> <name>param</name></param>
         </command>
         <command>
@@ -25646,7 +27873,7 @@
         <command>
             <proto>void <name>glTextureParameteriv</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>pname</name></param>
+            <param group="TextureParameterName"><ptype>GLenum</ptype> <name>pname</name></param>
             <param>const <ptype>GLint</ptype> *<name>param</name></param>
         </command>
         <command>
@@ -25672,7 +27899,7 @@
             <proto>void <name>glTextureStorage1D</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
         </command>
         <command>
@@ -25680,14 +27907,14 @@
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
         </command>
         <command>
             <proto>void <name>glTextureStorage2D</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -25696,7 +27923,7 @@
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
         </command>
@@ -25704,7 +27931,7 @@
             <proto>void <name>glTextureStorage2DMultisample</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLboolean</ptype> <name>fixedsamplelocations</name></param>
@@ -25714,7 +27941,7 @@
             <param group="Texture"><ptype>GLuint</ptype> <name>texture</name></param>
             <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param group="TextureInternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>fixedsamplelocations</name></param>
@@ -25723,7 +27950,7 @@
             <proto>void <name>glTextureStorage3D</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25733,7 +27960,7 @@
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>levels</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25742,7 +27969,7 @@
             <proto>void <name>glTextureStorage3DMultisample</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
@@ -25753,22 +27980,75 @@
             <param><ptype>GLuint</ptype> <name>texture</name></param>
             <param><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLsizei</ptype> <name>samples</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>fixedsamplelocations</name></param>
         </command>
         <command>
-            <proto>void <name>glTextureStorageSparseAMD</name></proto>
+            <proto>void <name>glTextureStorageMem1DEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTextureStorageMem2DEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTextureStorageMem2DMultisampleEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLsizei</ptype> <name>samples</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLboolean</ptype> <name>fixedSampleLocations</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTextureStorageMem3DEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLsizei</ptype> <name>levels</name></param>
             <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTextureStorageMem3DMultisampleEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLsizei</ptype> <name>samples</name></param>
+            <param><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
+            <param><ptype>GLboolean</ptype> <name>fixedSampleLocations</name></param>
+            <param><ptype>GLuint</ptype> <name>memory</name></param>
+            <param><ptype>GLuint64</ptype> <name>offset</name></param>
+        </command>
+        <command>
+            <proto>void <name>glTextureStorageSparseAMD</name></proto>
+            <param><ptype>GLuint</ptype> <name>texture</name></param>
+            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalFormat</name></param>
+            <param><ptype>GLsizei</ptype> <name>width</name></param>
+            <param><ptype>GLsizei</ptype> <name>height</name></param>
+            <param><ptype>GLsizei</ptype> <name>depth</name></param>
             <param><ptype>GLsizei</ptype> <name>layers</name></param>
-            <param><ptype>GLbitfield</ptype> <name>flags</name></param>
+            <param group="TextureStorageMaskAMD"><ptype>GLbitfield</ptype> <name>flags</name></param>
         </command>
         <command>
             <proto>void <name>glTextureSubImage1D</name></proto>
@@ -25776,8 +28056,8 @@
             <param><ptype>GLint</ptype> <name>level</name></param>
             <param><ptype>GLint</ptype> <name>xoffset</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>pixels</name></param>
         </command>
         <command>
@@ -25799,8 +28079,8 @@
             <param><ptype>GLint</ptype> <name>yoffset</name></param>
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>pixels</name></param>
         </command>
         <command>
@@ -25826,8 +28106,8 @@
             <param><ptype>GLsizei</ptype> <name>width</name></param>
             <param><ptype>GLsizei</ptype> <name>height</name></param>
             <param><ptype>GLsizei</ptype> <name>depth</name></param>
-            <param><ptype>GLenum</ptype> <name>format</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="PixelFormat"><ptype>GLenum</ptype> <name>format</name></param>
+            <param group="PixelType"><ptype>GLenum</ptype> <name>type</name></param>
             <param>const void *<name>pixels</name></param>
         </command>
         <command>
@@ -25848,9 +28128,9 @@
         <command>
             <proto>void <name>glTextureView</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>origtexture</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>minlevel</name></param>
             <param><ptype>GLuint</ptype> <name>numlevels</name></param>
             <param><ptype>GLuint</ptype> <name>minlayer</name></param>
@@ -25859,9 +28139,9 @@
         <command>
             <proto>void <name>glTextureViewEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>origtexture</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>minlevel</name></param>
             <param><ptype>GLuint</ptype> <name>numlevels</name></param>
             <param><ptype>GLuint</ptype> <name>minlayer</name></param>
@@ -25871,9 +28151,9 @@
         <command>
             <proto>void <name>glTextureViewOES</name></proto>
             <param><ptype>GLuint</ptype> <name>texture</name></param>
-            <param><ptype>GLenum</ptype> <name>target</name></param>
+            <param group="TextureTarget"><ptype>GLenum</ptype> <name>target</name></param>
             <param><ptype>GLuint</ptype> <name>origtexture</name></param>
-            <param><ptype>GLenum</ptype> <name>internalformat</name></param>
+            <param group="InternalFormat"><ptype>GLenum</ptype> <name>internalformat</name></param>
             <param><ptype>GLuint</ptype> <name>minlevel</name></param>
             <param><ptype>GLuint</ptype> <name>numlevels</name></param>
             <param><ptype>GLuint</ptype> <name>minlayer</name></param>
@@ -25922,6 +28202,7 @@
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLchar</ptype> *const*<name>varyings</name></param>
             <param><ptype>GLenum</ptype> <name>bufferMode</name></param>
+            <glx type="render" opcode="359"/>
         </command>
         <command>
             <proto>void <name>glTransformFeedbackVaryingsEXT</name></proto>
@@ -26550,6 +28831,7 @@
             <param><ptype>GLuint</ptype> <name>program</name></param>
             <param><ptype>GLuint</ptype> <name>uniformBlockIndex</name></param>
             <param><ptype>GLuint</ptype> <name>uniformBlockBinding</name></param>
+            <glx type="render" opcode="366"/>
         </command>
         <command>
             <proto>void <name>glUniformBufferEXT</name></proto>
@@ -26563,6 +28845,12 @@
             <param><ptype>GLuint64</ptype> <name>value</name></param>
         </command>
         <command>
+            <proto>void <name>glUniformHandleui64IMG</name></proto>
+            <param><ptype>GLint</ptype> <name>location</name></param>
+            <param><ptype>GLuint64</ptype> <name>value</name></param>
+            <alias name="glUniformHandleui64ARB"/>
+        </command>
+        <command>
             <proto>void <name>glUniformHandleui64NV</name></proto>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLuint64</ptype> <name>value</name></param>
@@ -26574,6 +28862,13 @@
             <param len="count">const <ptype>GLuint64</ptype> *<name>value</name></param>
         </command>
         <command>
+            <proto>void <name>glUniformHandleui64vIMG</name></proto>
+            <param><ptype>GLint</ptype> <name>location</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param len="count">const <ptype>GLuint64</ptype> *<name>value</name></param>
+            <alias name="glUniformHandleui64vARB"/>
+        </command>
+        <command>
             <proto>void <name>glUniformHandleui64vNV</name></proto>
             <param><ptype>GLint</ptype> <name>location</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
@@ -26785,7 +29080,7 @@
         </command>
         <command>
             <proto>void <name>glUniformSubroutinesuiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>shadertype</name></param>
+            <param group="ShaderType"><ptype>GLenum</ptype> <name>shadertype</name></param>
             <param><ptype>GLsizei</ptype> <name>count</name></param>
             <param len="count">const <ptype>GLuint</ptype> *<name>indices</name></param>
         </command>
@@ -26854,13 +29149,13 @@
         <command>
             <proto>void <name>glUseProgramStages</name></proto>
             <param><ptype>GLuint</ptype> <name>pipeline</name></param>
-            <param><ptype>GLbitfield</ptype> <name>stages</name></param>
+            <param group="UseProgramStageMask"><ptype>GLbitfield</ptype> <name>stages</name></param>
             <param><ptype>GLuint</ptype> <name>program</name></param>
         </command>
         <command>
             <proto>void <name>glUseProgramStagesEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>pipeline</name></param>
-            <param><ptype>GLbitfield</ptype> <name>stages</name></param>
+            <param group="UseProgramStageMask"><ptype>GLbitfield</ptype> <name>stages</name></param>
             <param><ptype>GLuint</ptype> <name>program</name></param>
         </command>
         <command>
@@ -27241,7 +29536,7 @@
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>attribindex</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param><ptype>GLuint</ptype> <name>relativeoffset</name></param>
         </command>
@@ -27250,7 +29545,7 @@
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>attribindex</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>relativeoffset</name></param>
         </command>
         <command>
@@ -27258,7 +29553,7 @@
             <param><ptype>GLuint</ptype> <name>vaobj</name></param>
             <param><ptype>GLuint</ptype> <name>attribindex</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>relativeoffset</name></param>
         </command>
         <command>
@@ -28546,7 +30841,7 @@
             <proto>void <name>glVertexAttribIPointer</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param len="COMPSIZE(size,type,stride)">const void *<name>pointer</name></param>
         </command>
@@ -28554,7 +30849,7 @@
             <proto>void <name>glVertexAttribIPointerEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param group="VertexAttribEnum"><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param len="COMPSIZE(size,type,stride)">const void *<name>pointer</name></param>
             <alias name="glVertexAttribIPointer"/>
@@ -28765,21 +31060,21 @@
             <proto>void <name>glVertexAttribLFormat</name></proto>
             <param><ptype>GLuint</ptype> <name>attribindex</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>relativeoffset</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribLFormatNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribLPointer</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param len="size">const void *<name>pointer</name></param>
         </command>
@@ -28787,7 +31082,7 @@
             <proto>void <name>glVertexAttribLPointerEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
             <param len="size">const void *<name>pointer</name></param>
             <alias name="glVertexAttribLPointer"/>
@@ -28795,56 +31090,56 @@
         <command>
             <proto>void <name>glVertexAttribP1ui</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP1uiv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP2ui</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP2uiv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP3ui</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP3uiv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP4ui</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexAttribP4uiv</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexAttribPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param group="Boolean"><ptype>GLboolean</ptype> <name>normalized</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
@@ -29023,37 +31318,37 @@
         <command>
             <proto>void <name>glVertexFormatNV</name></proto>
             <param><ptype>GLint</ptype> <name>size</name></param>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLsizei</ptype> <name>stride</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP2ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP2uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP3ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP3uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP4ui</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param><ptype>GLuint</ptype> <name>value</name></param>
         </command>
         <command>
             <proto>void <name>glVertexP4uiv</name></proto>
-            <param><ptype>GLenum</ptype> <name>type</name></param>
+            <param group="VertexPointerType"><ptype>GLenum</ptype> <name>type</name></param>
             <param len="1">const <ptype>GLuint</ptype> *<name>value</name></param>
         </command>
         <command>
@@ -29345,6 +31640,13 @@
             <alias name="glViewportArrayv"/>
         </command>
         <command>
+            <proto>void <name>glViewportArrayvOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>first</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param len="COMPSIZE(count)">const <ptype>GLfloat</ptype> *<name>v</name></param>
+            <alias name="glViewportArrayv"/>
+        </command>
+        <command>
             <proto>void <name>glViewportIndexedf</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLfloat</ptype> <name>x</name></param>
@@ -29353,6 +31655,15 @@
             <param><ptype>GLfloat</ptype> <name>h</name></param>
         </command>
         <command>
+            <proto>void <name>glViewportIndexedfOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param><ptype>GLfloat</ptype> <name>x</name></param>
+            <param><ptype>GLfloat</ptype> <name>y</name></param>
+            <param><ptype>GLfloat</ptype> <name>w</name></param>
+            <param><ptype>GLfloat</ptype> <name>h</name></param>
+            <alias name="glViewportIndexedf"/>
+        </command>
+        <command>
             <proto>void <name>glViewportIndexedfNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param><ptype>GLfloat</ptype> <name>x</name></param>
@@ -29367,12 +31678,41 @@
             <param len="4">const <ptype>GLfloat</ptype> *<name>v</name></param>
         </command>
         <command>
+            <proto>void <name>glViewportIndexedfvOES</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param len="4">const <ptype>GLfloat</ptype> *<name>v</name></param>
+            <alias name="glViewportIndexedfv"/>
+        </command>
+        <command>
             <proto>void <name>glViewportIndexedfvNV</name></proto>
             <param><ptype>GLuint</ptype> <name>index</name></param>
             <param len="4">const <ptype>GLfloat</ptype> *<name>v</name></param>
             <alias name="glViewportIndexedfv"/>
         </command>
         <command>
+            <proto>void <name>glViewportPositionWScaleNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param><ptype>GLfloat</ptype> <name>xcoeff</name></param>
+            <param><ptype>GLfloat</ptype> <name>ycoeff</name></param>
+        </command>
+        <command>
+            <proto>void <name>glViewportSwizzleNV</name></proto>
+            <param><ptype>GLuint</ptype> <name>index</name></param>
+            <param><ptype>GLenum</ptype> <name>swizzlex</name></param>
+            <param><ptype>GLenum</ptype> <name>swizzley</name></param>
+            <param><ptype>GLenum</ptype> <name>swizzlez</name></param>
+            <param><ptype>GLenum</ptype> <name>swizzlew</name></param>
+        </command>
+        <command>
+            <proto>void <name>glWaitSemaphoreEXT</name></proto>
+            <param><ptype>GLuint</ptype> <name>semaphore</name></param>
+            <param><ptype>GLuint</ptype> <name>numBufferBarriers</name></param>
+            <param len="COMPSIZE(numBufferBarriers)">const <ptype>GLuint</ptype> *<name>buffers</name></param>
+            <param><ptype>GLuint</ptype> <name>numTextureBarriers</name></param>
+            <param len="COMPSIZE(numTextureBarriers)">const <ptype>GLuint</ptype> *<name>textures</name></param>
+            <param group="TextureLayout" len="COMPSIZE(numTextureBarriers)">const <ptype>GLenum</ptype> *<name>srcLayouts</name></param>
+        </command>
+        <command>
             <proto>void <name>glWaitSync</name></proto>
             <param group="sync"><ptype>GLsync</ptype> <name>sync</name></param>
             <param><ptype>GLbitfield</ptype> <name>flags</name></param>
@@ -29803,6 +32143,12 @@
             <param group="CoordS" len="4">const <ptype>GLshort</ptype> *<name>v</name></param>
         </command>
         <command>
+            <proto>void <name>glWindowRectanglesEXT</name></proto>
+            <param><ptype>GLenum</ptype> <name>mode</name></param>
+            <param><ptype>GLsizei</ptype> <name>count</name></param>
+            <param len="COMPSIZE(count)">const <ptype>GLint</ptype> *<name>box</name></param>
+        </command>
+        <command>
             <proto>void <name>glWriteMaskEXT</name></proto>
             <param><ptype>GLuint</ptype> <name>res</name></param>
             <param><ptype>GLuint</ptype> <name>in</name></param>
@@ -29811,6 +32157,36 @@
             <param group="VertexShaderWriteMaskEXT"><ptype>GLenum</ptype> <name>outZ</name></param>
             <param group="VertexShaderWriteMaskEXT"><ptype>GLenum</ptype> <name>outW</name></param>
         </command>
+        <command>
+            <proto>void <name>glDrawVkImageNV</name></proto>
+            <param><ptype>GLuint64</ptype> <name>vkImage</name></param>
+            <param><ptype>GLuint</ptype> <name>sampler</name></param>
+            <param><ptype>GLfloat</ptype> <name>x0</name></param>
+            <param><ptype>GLfloat</ptype> <name>y0</name></param>
+            <param><ptype>GLfloat</ptype> <name>x1</name></param>
+            <param><ptype>GLfloat</ptype> <name>y1</name></param>
+            <param><ptype>GLfloat</ptype> <name>z</name></param>
+            <param><ptype>GLfloat</ptype> <name>s0</name></param>
+            <param><ptype>GLfloat</ptype> <name>t0</name></param>
+            <param><ptype>GLfloat</ptype> <name>s1</name></param>
+            <param><ptype>GLfloat</ptype> <name>t1</name></param>
+        </command>
+        <command>
+            <proto><ptype>GLVULKANPROCNV</ptype> <name>glGetVkProcAddrNV</name></proto>
+            <param len="COMPSIZE(name)">const <ptype>GLchar</ptype> *<name>name</name></param>
+        </command>
+        <command>
+            <proto>void <name>glWaitVkSemaphoreNV</name></proto>
+            <param><ptype>GLuint64</ptype> <name>vkSemaphore</name></param>
+        </command>
+        <command>
+            <proto>void <name>glSignalVkSemaphoreNV</name></proto>
+            <param><ptype>GLuint64</ptype> <name>vkSemaphore</name></param>
+        </command>
+        <command>
+            <proto>void <name>glSignalVkFenceNV</name></proto>
+            <param><ptype>GLuint64</ptype> <name>vkFence</name></param>
+        </command>
 
     </commands>
 
@@ -29818,6 +32194,430 @@
     <feature api="gl" name="GL_VERSION_1_0" number="1.0">
         <require>
             <type name="GLvoid" comment="No longer used in headers"/>
+            <enum name="GL_DEPTH_BUFFER_BIT"/>
+            <enum name="GL_STENCIL_BUFFER_BIT"/>
+            <enum name="GL_COLOR_BUFFER_BIT"/>
+            <enum name="GL_FALSE"/>
+            <enum name="GL_TRUE"/>
+            <enum name="GL_POINTS"/>
+            <enum name="GL_LINES"/>
+            <enum name="GL_LINE_LOOP"/>
+            <enum name="GL_LINE_STRIP"/>
+            <enum name="GL_TRIANGLES"/>
+            <enum name="GL_TRIANGLE_STRIP"/>
+            <enum name="GL_TRIANGLE_FAN"/>
+            <enum name="GL_QUADS"/>
+            <enum name="GL_NEVER"/>
+            <enum name="GL_LESS"/>
+            <enum name="GL_EQUAL"/>
+            <enum name="GL_LEQUAL"/>
+            <enum name="GL_GREATER"/>
+            <enum name="GL_NOTEQUAL"/>
+            <enum name="GL_GEQUAL"/>
+            <enum name="GL_ALWAYS"/>
+            <enum name="GL_ZERO"/>
+            <enum name="GL_ONE"/>
+            <enum name="GL_SRC_COLOR"/>
+            <enum name="GL_ONE_MINUS_SRC_COLOR"/>
+            <enum name="GL_SRC_ALPHA"/>
+            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
+            <enum name="GL_DST_ALPHA"/>
+            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
+            <enum name="GL_DST_COLOR"/>
+            <enum name="GL_ONE_MINUS_DST_COLOR"/>
+            <enum name="GL_SRC_ALPHA_SATURATE"/>
+            <enum name="GL_NONE"/>
+            <enum name="GL_FRONT_LEFT"/>
+            <enum name="GL_FRONT_RIGHT"/>
+            <enum name="GL_BACK_LEFT"/>
+            <enum name="GL_BACK_RIGHT"/>
+            <enum name="GL_FRONT"/>
+            <enum name="GL_BACK"/>
+            <enum name="GL_LEFT"/>
+            <enum name="GL_RIGHT"/>
+            <enum name="GL_FRONT_AND_BACK"/>
+            <enum name="GL_NO_ERROR"/>
+            <enum name="GL_INVALID_ENUM"/>
+            <enum name="GL_INVALID_VALUE"/>
+            <enum name="GL_INVALID_OPERATION"/>
+            <enum name="GL_OUT_OF_MEMORY"/>
+            <enum name="GL_CW"/>
+            <enum name="GL_CCW"/>
+            <enum name="GL_POINT_SIZE"/>
+            <enum name="GL_POINT_SIZE_RANGE"/>
+            <enum name="GL_POINT_SIZE_GRANULARITY"/>
+            <enum name="GL_LINE_SMOOTH"/>
+            <enum name="GL_LINE_WIDTH"/>
+            <enum name="GL_LINE_WIDTH_RANGE"/>
+            <enum name="GL_LINE_WIDTH_GRANULARITY"/>
+            <enum name="GL_POLYGON_MODE"/>
+            <enum name="GL_POLYGON_SMOOTH"/>
+            <enum name="GL_CULL_FACE"/>
+            <enum name="GL_CULL_FACE_MODE"/>
+            <enum name="GL_FRONT_FACE"/>
+            <enum name="GL_DEPTH_RANGE"/>
+            <enum name="GL_DEPTH_TEST"/>
+            <enum name="GL_DEPTH_WRITEMASK"/>
+            <enum name="GL_DEPTH_CLEAR_VALUE"/>
+            <enum name="GL_DEPTH_FUNC"/>
+            <enum name="GL_STENCIL_TEST"/>
+            <enum name="GL_STENCIL_CLEAR_VALUE"/>
+            <enum name="GL_STENCIL_FUNC"/>
+            <enum name="GL_STENCIL_VALUE_MASK"/>
+            <enum name="GL_STENCIL_FAIL"/>
+            <enum name="GL_STENCIL_PASS_DEPTH_FAIL"/>
+            <enum name="GL_STENCIL_PASS_DEPTH_PASS"/>
+            <enum name="GL_STENCIL_REF"/>
+            <enum name="GL_STENCIL_WRITEMASK"/>
+            <enum name="GL_VIEWPORT"/>
+            <enum name="GL_DITHER"/>
+            <enum name="GL_BLEND_DST"/>
+            <enum name="GL_BLEND_SRC"/>
+            <enum name="GL_BLEND"/>
+            <enum name="GL_LOGIC_OP_MODE"/>
+            <enum name="GL_DRAW_BUFFER"/>
+            <enum name="GL_READ_BUFFER"/>
+            <enum name="GL_SCISSOR_BOX"/>
+            <enum name="GL_SCISSOR_TEST"/>
+            <enum name="GL_COLOR_CLEAR_VALUE"/>
+            <enum name="GL_COLOR_WRITEMASK"/>
+            <enum name="GL_DOUBLEBUFFER"/>
+            <enum name="GL_STEREO"/>
+            <enum name="GL_LINE_SMOOTH_HINT"/>
+            <enum name="GL_POLYGON_SMOOTH_HINT"/>
+            <enum name="GL_UNPACK_SWAP_BYTES"/>
+            <enum name="GL_UNPACK_LSB_FIRST"/>
+            <enum name="GL_UNPACK_ROW_LENGTH"/>
+            <enum name="GL_UNPACK_SKIP_ROWS"/>
+            <enum name="GL_UNPACK_SKIP_PIXELS"/>
+            <enum name="GL_UNPACK_ALIGNMENT"/>
+            <enum name="GL_PACK_SWAP_BYTES"/>
+            <enum name="GL_PACK_LSB_FIRST"/>
+            <enum name="GL_PACK_ROW_LENGTH"/>
+            <enum name="GL_PACK_SKIP_ROWS"/>
+            <enum name="GL_PACK_SKIP_PIXELS"/>
+            <enum name="GL_PACK_ALIGNMENT"/>
+            <enum name="GL_MAX_TEXTURE_SIZE"/>
+            <enum name="GL_MAX_VIEWPORT_DIMS"/>
+            <enum name="GL_SUBPIXEL_BITS"/>
+            <enum name="GL_TEXTURE_1D"/>
+            <enum name="GL_TEXTURE_2D"/>
+            <enum name="GL_TEXTURE_WIDTH"/>
+            <enum name="GL_TEXTURE_HEIGHT"/>
+            <enum name="GL_TEXTURE_BORDER_COLOR"/>
+            <enum name="GL_DONT_CARE"/>
+            <enum name="GL_FASTEST"/>
+            <enum name="GL_NICEST"/>
+            <enum name="GL_BYTE"/>
+            <enum name="GL_UNSIGNED_BYTE"/>
+            <enum name="GL_SHORT"/>
+            <enum name="GL_UNSIGNED_SHORT"/>
+            <enum name="GL_INT"/>
+            <enum name="GL_UNSIGNED_INT"/>
+            <enum name="GL_FLOAT"/>
+            <enum name="GL_STACK_OVERFLOW"/>
+            <enum name="GL_STACK_UNDERFLOW"/>
+            <enum name="GL_CLEAR"/>
+            <enum name="GL_AND"/>
+            <enum name="GL_AND_REVERSE"/>
+            <enum name="GL_COPY"/>
+            <enum name="GL_AND_INVERTED"/>
+            <enum name="GL_NOOP"/>
+            <enum name="GL_XOR"/>
+            <enum name="GL_OR"/>
+            <enum name="GL_NOR"/>
+            <enum name="GL_EQUIV"/>
+            <enum name="GL_INVERT"/>
+            <enum name="GL_OR_REVERSE"/>
+            <enum name="GL_COPY_INVERTED"/>
+            <enum name="GL_OR_INVERTED"/>
+            <enum name="GL_NAND"/>
+            <enum name="GL_SET"/>
+            <enum name="GL_TEXTURE"/>
+            <enum name="GL_COLOR"/>
+            <enum name="GL_DEPTH"/>
+            <enum name="GL_STENCIL"/>
+            <enum name="GL_STENCIL_INDEX"/>
+            <enum name="GL_DEPTH_COMPONENT"/>
+            <enum name="GL_RED"/>
+            <enum name="GL_GREEN"/>
+            <enum name="GL_BLUE"/>
+            <enum name="GL_ALPHA"/>
+            <enum name="GL_RGB"/>
+            <enum name="GL_RGBA"/>
+            <enum name="GL_POINT"/>
+            <enum name="GL_LINE"/>
+            <enum name="GL_FILL"/>
+            <enum name="GL_KEEP"/>
+            <enum name="GL_REPLACE"/>
+            <enum name="GL_INCR"/>
+            <enum name="GL_DECR"/>
+            <enum name="GL_VENDOR"/>
+            <enum name="GL_RENDERER"/>
+            <enum name="GL_VERSION"/>
+            <enum name="GL_EXTENSIONS"/>
+            <enum name="GL_NEAREST"/>
+            <enum name="GL_LINEAR"/>
+            <enum name="GL_NEAREST_MIPMAP_NEAREST"/>
+            <enum name="GL_LINEAR_MIPMAP_NEAREST"/>
+            <enum name="GL_NEAREST_MIPMAP_LINEAR"/>
+            <enum name="GL_LINEAR_MIPMAP_LINEAR"/>
+            <enum name="GL_TEXTURE_MAG_FILTER"/>
+            <enum name="GL_TEXTURE_MIN_FILTER"/>
+            <enum name="GL_TEXTURE_WRAP_S"/>
+            <enum name="GL_TEXTURE_WRAP_T"/>
+            <enum name="GL_REPEAT"/>
+            <enum name="GL_CURRENT_BIT"/>
+            <enum name="GL_POINT_BIT"/>
+            <enum name="GL_LINE_BIT"/>
+            <enum name="GL_POLYGON_BIT"/>
+            <enum name="GL_POLYGON_STIPPLE_BIT"/>
+            <enum name="GL_PIXEL_MODE_BIT"/>
+            <enum name="GL_LIGHTING_BIT"/>
+            <enum name="GL_FOG_BIT"/>
+            <enum name="GL_ACCUM_BUFFER_BIT"/>
+            <enum name="GL_VIEWPORT_BIT"/>
+            <enum name="GL_TRANSFORM_BIT"/>
+            <enum name="GL_ENABLE_BIT"/>
+            <enum name="GL_HINT_BIT"/>
+            <enum name="GL_EVAL_BIT"/>
+            <enum name="GL_LIST_BIT"/>
+            <enum name="GL_TEXTURE_BIT"/>
+            <enum name="GL_SCISSOR_BIT"/>
+            <enum name="GL_ALL_ATTRIB_BITS"/>
+            <enum name="GL_QUAD_STRIP"/>
+            <enum name="GL_POLYGON"/>
+            <enum name="GL_ACCUM"/>
+            <enum name="GL_LOAD"/>
+            <enum name="GL_RETURN"/>
+            <enum name="GL_MULT"/>
+            <enum name="GL_ADD"/>
+            <enum name="GL_AUX0"/>
+            <enum name="GL_AUX1"/>
+            <enum name="GL_AUX2"/>
+            <enum name="GL_AUX3"/>
+            <enum name="GL_2D"/>
+            <enum name="GL_3D"/>
+            <enum name="GL_3D_COLOR"/>
+            <enum name="GL_3D_COLOR_TEXTURE"/>
+            <enum name="GL_4D_COLOR_TEXTURE"/>
+            <enum name="GL_PASS_THROUGH_TOKEN"/>
+            <enum name="GL_POINT_TOKEN"/>
+            <enum name="GL_LINE_TOKEN"/>
+            <enum name="GL_POLYGON_TOKEN"/>
+            <enum name="GL_BITMAP_TOKEN"/>
+            <enum name="GL_DRAW_PIXEL_TOKEN"/>
+            <enum name="GL_COPY_PIXEL_TOKEN"/>
+            <enum name="GL_LINE_RESET_TOKEN"/>
+            <enum name="GL_EXP"/>
+            <enum name="GL_EXP2"/>
+            <enum name="GL_COEFF"/>
+            <enum name="GL_ORDER"/>
+            <enum name="GL_DOMAIN"/>
+            <enum name="GL_PIXEL_MAP_I_TO_I"/>
+            <enum name="GL_PIXEL_MAP_S_TO_S"/>
+            <enum name="GL_PIXEL_MAP_I_TO_R"/>
+            <enum name="GL_PIXEL_MAP_I_TO_G"/>
+            <enum name="GL_PIXEL_MAP_I_TO_B"/>
+            <enum name="GL_PIXEL_MAP_I_TO_A"/>
+            <enum name="GL_PIXEL_MAP_R_TO_R"/>
+            <enum name="GL_PIXEL_MAP_G_TO_G"/>
+            <enum name="GL_PIXEL_MAP_B_TO_B"/>
+            <enum name="GL_PIXEL_MAP_A_TO_A"/>
+            <enum name="GL_CURRENT_COLOR"/>
+            <enum name="GL_CURRENT_INDEX"/>
+            <enum name="GL_CURRENT_NORMAL"/>
+            <enum name="GL_CURRENT_TEXTURE_COORDS"/>
+            <enum name="GL_CURRENT_RASTER_COLOR"/>
+            <enum name="GL_CURRENT_RASTER_INDEX"/>
+            <enum name="GL_CURRENT_RASTER_TEXTURE_COORDS"/>
+            <enum name="GL_CURRENT_RASTER_POSITION"/>
+            <enum name="GL_CURRENT_RASTER_POSITION_VALID"/>
+            <enum name="GL_CURRENT_RASTER_DISTANCE"/>
+            <enum name="GL_POINT_SMOOTH"/>
+            <enum name="GL_LINE_STIPPLE"/>
+            <enum name="GL_LINE_STIPPLE_PATTERN"/>
+            <enum name="GL_LINE_STIPPLE_REPEAT"/>
+            <enum name="GL_LIST_MODE"/>
+            <enum name="GL_MAX_LIST_NESTING"/>
+            <enum name="GL_LIST_BASE"/>
+            <enum name="GL_LIST_INDEX"/>
+            <enum name="GL_POLYGON_STIPPLE"/>
+            <enum name="GL_EDGE_FLAG"/>
+            <enum name="GL_LIGHTING"/>
+            <enum name="GL_LIGHT_MODEL_LOCAL_VIEWER"/>
+            <enum name="GL_LIGHT_MODEL_TWO_SIDE"/>
+            <enum name="GL_LIGHT_MODEL_AMBIENT"/>
+            <enum name="GL_SHADE_MODEL"/>
+            <enum name="GL_COLOR_MATERIAL_FACE"/>
+            <enum name="GL_COLOR_MATERIAL_PARAMETER"/>
+            <enum name="GL_COLOR_MATERIAL"/>
+            <enum name="GL_FOG"/>
+            <enum name="GL_FOG_INDEX"/>
+            <enum name="GL_FOG_DENSITY"/>
+            <enum name="GL_FOG_START"/>
+            <enum name="GL_FOG_END"/>
+            <enum name="GL_FOG_MODE"/>
+            <enum name="GL_FOG_COLOR"/>
+            <enum name="GL_ACCUM_CLEAR_VALUE"/>
+            <enum name="GL_MATRIX_MODE"/>
+            <enum name="GL_NORMALIZE"/>
+            <enum name="GL_MODELVIEW_STACK_DEPTH"/>
+            <enum name="GL_PROJECTION_STACK_DEPTH"/>
+            <enum name="GL_TEXTURE_STACK_DEPTH"/>
+            <enum name="GL_MODELVIEW_MATRIX"/>
+            <enum name="GL_PROJECTION_MATRIX"/>
+            <enum name="GL_TEXTURE_MATRIX"/>
+            <enum name="GL_ATTRIB_STACK_DEPTH"/>
+            <enum name="GL_ALPHA_TEST"/>
+            <enum name="GL_ALPHA_TEST_FUNC"/>
+            <enum name="GL_ALPHA_TEST_REF"/>
+            <enum name="GL_LOGIC_OP"/>
+            <enum name="GL_AUX_BUFFERS"/>
+            <enum name="GL_INDEX_CLEAR_VALUE"/>
+            <enum name="GL_INDEX_WRITEMASK"/>
+            <enum name="GL_INDEX_MODE"/>
+            <enum name="GL_RGBA_MODE"/>
+            <enum name="GL_RENDER_MODE"/>
+            <enum name="GL_PERSPECTIVE_CORRECTION_HINT"/>
+            <enum name="GL_POINT_SMOOTH_HINT"/>
+            <enum name="GL_FOG_HINT"/>
+            <enum name="GL_TEXTURE_GEN_S"/>
+            <enum name="GL_TEXTURE_GEN_T"/>
+            <enum name="GL_TEXTURE_GEN_R"/>
+            <enum name="GL_TEXTURE_GEN_Q"/>
+            <enum name="GL_PIXEL_MAP_I_TO_I_SIZE"/>
+            <enum name="GL_PIXEL_MAP_S_TO_S_SIZE"/>
+            <enum name="GL_PIXEL_MAP_I_TO_R_SIZE"/>
+            <enum name="GL_PIXEL_MAP_I_TO_G_SIZE"/>
+            <enum name="GL_PIXEL_MAP_I_TO_B_SIZE"/>
+            <enum name="GL_PIXEL_MAP_I_TO_A_SIZE"/>
+            <enum name="GL_PIXEL_MAP_R_TO_R_SIZE"/>
+            <enum name="GL_PIXEL_MAP_G_TO_G_SIZE"/>
+            <enum name="GL_PIXEL_MAP_B_TO_B_SIZE"/>
+            <enum name="GL_PIXEL_MAP_A_TO_A_SIZE"/>
+            <enum name="GL_MAP_COLOR"/>
+            <enum name="GL_MAP_STENCIL"/>
+            <enum name="GL_INDEX_SHIFT"/>
+            <enum name="GL_INDEX_OFFSET"/>
+            <enum name="GL_RED_SCALE"/>
+            <enum name="GL_RED_BIAS"/>
+            <enum name="GL_ZOOM_X"/>
+            <enum name="GL_ZOOM_Y"/>
+            <enum name="GL_GREEN_SCALE"/>
+            <enum name="GL_GREEN_BIAS"/>
+            <enum name="GL_BLUE_SCALE"/>
+            <enum name="GL_BLUE_BIAS"/>
+            <enum name="GL_ALPHA_SCALE"/>
+            <enum name="GL_ALPHA_BIAS"/>
+            <enum name="GL_DEPTH_SCALE"/>
+            <enum name="GL_DEPTH_BIAS"/>
+            <enum name="GL_MAX_EVAL_ORDER"/>
+            <enum name="GL_MAX_LIGHTS"/>
+            <enum name="GL_MAX_CLIP_PLANES"/>
+            <enum name="GL_MAX_PIXEL_MAP_TABLE"/>
+            <enum name="GL_MAX_ATTRIB_STACK_DEPTH"/>
+            <enum name="GL_MAX_MODELVIEW_STACK_DEPTH"/>
+            <enum name="GL_MAX_NAME_STACK_DEPTH"/>
+            <enum name="GL_MAX_PROJECTION_STACK_DEPTH"/>
+            <enum name="GL_MAX_TEXTURE_STACK_DEPTH"/>
+            <enum name="GL_INDEX_BITS"/>
+            <enum name="GL_RED_BITS"/>
+            <enum name="GL_GREEN_BITS"/>
+            <enum name="GL_BLUE_BITS"/>
+            <enum name="GL_ALPHA_BITS"/>
+            <enum name="GL_DEPTH_BITS"/>
+            <enum name="GL_STENCIL_BITS"/>
+            <enum name="GL_ACCUM_RED_BITS"/>
+            <enum name="GL_ACCUM_GREEN_BITS"/>
+            <enum name="GL_ACCUM_BLUE_BITS"/>
+            <enum name="GL_ACCUM_ALPHA_BITS"/>
+            <enum name="GL_NAME_STACK_DEPTH"/>
+            <enum name="GL_AUTO_NORMAL"/>
+            <enum name="GL_MAP1_COLOR_4"/>
+            <enum name="GL_MAP1_INDEX"/>
+            <enum name="GL_MAP1_NORMAL"/>
+            <enum name="GL_MAP1_TEXTURE_COORD_1"/>
+            <enum name="GL_MAP1_TEXTURE_COORD_2"/>
+            <enum name="GL_MAP1_TEXTURE_COORD_3"/>
+            <enum name="GL_MAP1_TEXTURE_COORD_4"/>
+            <enum name="GL_MAP1_VERTEX_3"/>
+            <enum name="GL_MAP1_VERTEX_4"/>
+            <enum name="GL_MAP2_COLOR_4"/>
+            <enum name="GL_MAP2_INDEX"/>
+            <enum name="GL_MAP2_NORMAL"/>
+            <enum name="GL_MAP2_TEXTURE_COORD_1"/>
+            <enum name="GL_MAP2_TEXTURE_COORD_2"/>
+            <enum name="GL_MAP2_TEXTURE_COORD_3"/>
+            <enum name="GL_MAP2_TEXTURE_COORD_4"/>
+            <enum name="GL_MAP2_VERTEX_3"/>
+            <enum name="GL_MAP2_VERTEX_4"/>
+            <enum name="GL_MAP1_GRID_DOMAIN"/>
+            <enum name="GL_MAP1_GRID_SEGMENTS"/>
+            <enum name="GL_MAP2_GRID_DOMAIN"/>
+            <enum name="GL_MAP2_GRID_SEGMENTS"/>
+            <enum name="GL_TEXTURE_COMPONENTS"/>
+            <enum name="GL_TEXTURE_BORDER"/>
+            <enum name="GL_AMBIENT"/>
+            <enum name="GL_DIFFUSE"/>
+            <enum name="GL_SPECULAR"/>
+            <enum name="GL_POSITION"/>
+            <enum name="GL_SPOT_DIRECTION"/>
+            <enum name="GL_SPOT_EXPONENT"/>
+            <enum name="GL_SPOT_CUTOFF"/>
+            <enum name="GL_CONSTANT_ATTENUATION"/>
+            <enum name="GL_LINEAR_ATTENUATION"/>
+            <enum name="GL_QUADRATIC_ATTENUATION"/>
+            <enum name="GL_COMPILE"/>
+            <enum name="GL_COMPILE_AND_EXECUTE"/>
+            <enum name="GL_2_BYTES"/>
+            <enum name="GL_3_BYTES"/>
+            <enum name="GL_4_BYTES"/>
+            <enum name="GL_EMISSION"/>
+            <enum name="GL_SHININESS"/>
+            <enum name="GL_AMBIENT_AND_DIFFUSE"/>
+            <enum name="GL_COLOR_INDEXES"/>
+            <enum name="GL_MODELVIEW"/>
+            <enum name="GL_PROJECTION"/>
+            <enum name="GL_COLOR_INDEX"/>
+            <enum name="GL_LUMINANCE"/>
+            <enum name="GL_LUMINANCE_ALPHA"/>
+            <enum name="GL_BITMAP"/>
+            <enum name="GL_RENDER"/>
+            <enum name="GL_FEEDBACK"/>
+            <enum name="GL_SELECT"/>
+            <enum name="GL_FLAT"/>
+            <enum name="GL_SMOOTH"/>
+            <enum name="GL_S"/>
+            <enum name="GL_T"/>
+            <enum name="GL_R"/>
+            <enum name="GL_Q"/>
+            <enum name="GL_MODULATE"/>
+            <enum name="GL_DECAL"/>
+            <enum name="GL_TEXTURE_ENV_MODE"/>
+            <enum name="GL_TEXTURE_ENV_COLOR"/>
+            <enum name="GL_TEXTURE_ENV"/>
+            <enum name="GL_EYE_LINEAR"/>
+            <enum name="GL_OBJECT_LINEAR"/>
+            <enum name="GL_SPHERE_MAP"/>
+            <enum name="GL_TEXTURE_GEN_MODE"/>
+            <enum name="GL_OBJECT_PLANE"/>
+            <enum name="GL_EYE_PLANE"/>
+            <enum name="GL_CLAMP"/>
+            <enum name="GL_CLIP_PLANE0"/>
+            <enum name="GL_CLIP_PLANE1"/>
+            <enum name="GL_CLIP_PLANE2"/>
+            <enum name="GL_CLIP_PLANE3"/>
+            <enum name="GL_CLIP_PLANE4"/>
+            <enum name="GL_CLIP_PLANE5"/>
+            <enum name="GL_LIGHT0"/>
+            <enum name="GL_LIGHT1"/>
+            <enum name="GL_LIGHT2"/>
+            <enum name="GL_LIGHT3"/>
+            <enum name="GL_LIGHT4"/>
+            <enum name="GL_LIGHT5"/>
+            <enum name="GL_LIGHT6"/>
+            <enum name="GL_LIGHT7"/>
             <command name="glCullFace"/>
             <command name="glFrontFace"/>
             <command name="glHint"/>
@@ -30130,116 +32930,7 @@
         <require>
             <type name="GLclampf" comment="No longer used in GL 1.1, but still defined in Mesa gl.h"/>
             <type name="GLclampd" comment="No longer used in GL 1.1, but still defined in Mesa gl.h"/>
-            <!-- Many of these are really VERSION_1_0 enums -->
-            <enum name="GL_DEPTH_BUFFER_BIT"/>
-            <enum name="GL_STENCIL_BUFFER_BIT"/>
-            <enum name="GL_COLOR_BUFFER_BIT"/>
-            <enum name="GL_FALSE"/>
-            <enum name="GL_TRUE"/>
-            <enum name="GL_POINTS"/>
-            <enum name="GL_LINES"/>
-            <enum name="GL_LINE_LOOP"/>
-            <enum name="GL_LINE_STRIP"/>
-            <enum name="GL_TRIANGLES"/>
-            <enum name="GL_TRIANGLE_STRIP"/>
-            <enum name="GL_TRIANGLE_FAN"/>
-            <enum name="GL_QUADS"/>
-            <enum name="GL_NEVER"/>
-            <enum name="GL_LESS"/>
-            <enum name="GL_EQUAL"/>
-            <enum name="GL_LEQUAL"/>
-            <enum name="GL_GREATER"/>
-            <enum name="GL_NOTEQUAL"/>
-            <enum name="GL_GEQUAL"/>
-            <enum name="GL_ALWAYS"/>
-            <enum name="GL_ZERO"/>
-            <enum name="GL_ONE"/>
-            <enum name="GL_SRC_COLOR"/>
-            <enum name="GL_ONE_MINUS_SRC_COLOR"/>
-            <enum name="GL_SRC_ALPHA"/>
-            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
-            <enum name="GL_DST_ALPHA"/>
-            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
-            <enum name="GL_DST_COLOR"/>
-            <enum name="GL_ONE_MINUS_DST_COLOR"/>
-            <enum name="GL_SRC_ALPHA_SATURATE"/>
-            <enum name="GL_NONE"/>
-            <enum name="GL_FRONT_LEFT"/>
-            <enum name="GL_FRONT_RIGHT"/>
-            <enum name="GL_BACK_LEFT"/>
-            <enum name="GL_BACK_RIGHT"/>
-            <enum name="GL_FRONT"/>
-            <enum name="GL_BACK"/>
-            <enum name="GL_LEFT"/>
-            <enum name="GL_RIGHT"/>
-            <enum name="GL_FRONT_AND_BACK"/>
-            <enum name="GL_NO_ERROR"/>
-            <enum name="GL_INVALID_ENUM"/>
-            <enum name="GL_INVALID_VALUE"/>
-            <enum name="GL_INVALID_OPERATION"/>
-            <enum name="GL_OUT_OF_MEMORY"/>
-            <enum name="GL_CW"/>
-            <enum name="GL_CCW"/>
-            <enum name="GL_POINT_SIZE"/>
-            <enum name="GL_POINT_SIZE_RANGE"/>
-            <enum name="GL_POINT_SIZE_GRANULARITY"/>
-            <enum name="GL_LINE_SMOOTH"/>
-            <enum name="GL_LINE_WIDTH"/>
-            <enum name="GL_LINE_WIDTH_RANGE"/>
-            <enum name="GL_LINE_WIDTH_GRANULARITY"/>
-            <enum name="GL_POLYGON_MODE"/>
-            <enum name="GL_POLYGON_SMOOTH"/>
-            <enum name="GL_CULL_FACE"/>
-            <enum name="GL_CULL_FACE_MODE"/>
-            <enum name="GL_FRONT_FACE"/>
-            <enum name="GL_DEPTH_RANGE"/>
-            <enum name="GL_DEPTH_TEST"/>
-            <enum name="GL_DEPTH_WRITEMASK"/>
-            <enum name="GL_DEPTH_CLEAR_VALUE"/>
-            <enum name="GL_DEPTH_FUNC"/>
-            <enum name="GL_STENCIL_TEST"/>
-            <enum name="GL_STENCIL_CLEAR_VALUE"/>
-            <enum name="GL_STENCIL_FUNC"/>
-            <enum name="GL_STENCIL_VALUE_MASK"/>
-            <enum name="GL_STENCIL_FAIL"/>
-            <enum name="GL_STENCIL_PASS_DEPTH_FAIL"/>
-            <enum name="GL_STENCIL_PASS_DEPTH_PASS"/>
-            <enum name="GL_STENCIL_REF"/>
-            <enum name="GL_STENCIL_WRITEMASK"/>
-            <enum name="GL_VIEWPORT"/>
-            <enum name="GL_DITHER"/>
-            <enum name="GL_BLEND_DST"/>
-            <enum name="GL_BLEND_SRC"/>
-            <enum name="GL_BLEND"/>
-            <enum name="GL_LOGIC_OP_MODE"/>
             <enum name="GL_COLOR_LOGIC_OP"/>
-            <enum name="GL_DRAW_BUFFER"/>
-            <enum name="GL_READ_BUFFER"/>
-            <enum name="GL_SCISSOR_BOX"/>
-            <enum name="GL_SCISSOR_TEST"/>
-            <enum name="GL_COLOR_CLEAR_VALUE"/>
-            <enum name="GL_COLOR_WRITEMASK"/>
-            <enum name="GL_DOUBLEBUFFER"/>
-            <enum name="GL_STEREO"/>
-            <enum name="GL_LINE_SMOOTH_HINT"/>
-            <enum name="GL_POLYGON_SMOOTH_HINT"/>
-            <enum name="GL_UNPACK_SWAP_BYTES"/>
-            <enum name="GL_UNPACK_LSB_FIRST"/>
-            <enum name="GL_UNPACK_ROW_LENGTH"/>
-            <enum name="GL_UNPACK_SKIP_ROWS"/>
-            <enum name="GL_UNPACK_SKIP_PIXELS"/>
-            <enum name="GL_UNPACK_ALIGNMENT"/>
-            <enum name="GL_PACK_SWAP_BYTES"/>
-            <enum name="GL_PACK_LSB_FIRST"/>
-            <enum name="GL_PACK_ROW_LENGTH"/>
-            <enum name="GL_PACK_SKIP_ROWS"/>
-            <enum name="GL_PACK_SKIP_PIXELS"/>
-            <enum name="GL_PACK_ALIGNMENT"/>
-            <enum name="GL_MAX_TEXTURE_SIZE"/>
-            <enum name="GL_MAX_VIEWPORT_DIMS"/>
-            <enum name="GL_SUBPIXEL_BITS"/>
-            <enum name="GL_TEXTURE_1D"/>
-            <enum name="GL_TEXTURE_2D"/>
             <enum name="GL_POLYGON_OFFSET_UNITS"/>
             <enum name="GL_POLYGON_OFFSET_POINT"/>
             <enum name="GL_POLYGON_OFFSET_LINE"/>
@@ -30247,79 +32938,14 @@
             <enum name="GL_POLYGON_OFFSET_FACTOR"/>
             <enum name="GL_TEXTURE_BINDING_1D"/>
             <enum name="GL_TEXTURE_BINDING_2D"/>
-            <enum name="GL_TEXTURE_WIDTH"/>
-            <enum name="GL_TEXTURE_HEIGHT"/>
             <enum name="GL_TEXTURE_INTERNAL_FORMAT"/>
-            <enum name="GL_TEXTURE_BORDER_COLOR"/>
             <enum name="GL_TEXTURE_RED_SIZE"/>
             <enum name="GL_TEXTURE_GREEN_SIZE"/>
             <enum name="GL_TEXTURE_BLUE_SIZE"/>
             <enum name="GL_TEXTURE_ALPHA_SIZE"/>
-            <enum name="GL_DONT_CARE"/>
-            <enum name="GL_FASTEST"/>
-            <enum name="GL_NICEST"/>
-            <enum name="GL_BYTE"/>
-            <enum name="GL_UNSIGNED_BYTE"/>
-            <enum name="GL_SHORT"/>
-            <enum name="GL_UNSIGNED_SHORT"/>
-            <enum name="GL_INT"/>
-            <enum name="GL_UNSIGNED_INT"/>
-            <enum name="GL_FLOAT"/>
             <enum name="GL_DOUBLE"/>
-            <enum name="GL_STACK_OVERFLOW"/>
-            <enum name="GL_STACK_UNDERFLOW"/>
-            <enum name="GL_CLEAR"/>
-            <enum name="GL_AND"/>
-            <enum name="GL_AND_REVERSE"/>
-            <enum name="GL_COPY"/>
-            <enum name="GL_AND_INVERTED"/>
-            <enum name="GL_NOOP"/>
-            <enum name="GL_XOR"/>
-            <enum name="GL_OR"/>
-            <enum name="GL_NOR"/>
-            <enum name="GL_EQUIV"/>
-            <enum name="GL_INVERT"/>
-            <enum name="GL_OR_REVERSE"/>
-            <enum name="GL_COPY_INVERTED"/>
-            <enum name="GL_OR_INVERTED"/>
-            <enum name="GL_NAND"/>
-            <enum name="GL_SET"/>
-            <enum name="GL_TEXTURE"/>
-            <enum name="GL_COLOR"/>
-            <enum name="GL_DEPTH"/>
-            <enum name="GL_STENCIL"/>
-            <enum name="GL_STENCIL_INDEX"/>
-            <enum name="GL_DEPTH_COMPONENT"/>
-            <enum name="GL_RED"/>
-            <enum name="GL_GREEN"/>
-            <enum name="GL_BLUE"/>
-            <enum name="GL_ALPHA"/>
-            <enum name="GL_RGB"/>
-            <enum name="GL_RGBA"/>
-            <enum name="GL_POINT"/>
-            <enum name="GL_LINE"/>
-            <enum name="GL_FILL"/>
-            <enum name="GL_KEEP"/>
-            <enum name="GL_REPLACE"/>
-            <enum name="GL_INCR"/>
-            <enum name="GL_DECR"/>
-            <enum name="GL_VENDOR"/>
-            <enum name="GL_RENDERER"/>
-            <enum name="GL_VERSION"/>
-            <enum name="GL_EXTENSIONS"/>
-            <enum name="GL_NEAREST"/>
-            <enum name="GL_LINEAR"/>
-            <enum name="GL_NEAREST_MIPMAP_NEAREST"/>
-            <enum name="GL_LINEAR_MIPMAP_NEAREST"/>
-            <enum name="GL_NEAREST_MIPMAP_LINEAR"/>
-            <enum name="GL_LINEAR_MIPMAP_LINEAR"/>
-            <enum name="GL_TEXTURE_MAG_FILTER"/>
-            <enum name="GL_TEXTURE_MIN_FILTER"/>
-            <enum name="GL_TEXTURE_WRAP_S"/>
-            <enum name="GL_TEXTURE_WRAP_T"/>
             <enum name="GL_PROXY_TEXTURE_1D"/>
             <enum name="GL_PROXY_TEXTURE_2D"/>
-            <enum name="GL_REPEAT"/>
             <enum name="GL_R3_G3_B2"/>
             <enum name="GL_RGB4"/>
             <enum name="GL_RGB5"/>
@@ -30334,66 +32960,9 @@
             <enum name="GL_RGB10_A2"/>
             <enum name="GL_RGBA12"/>
             <enum name="GL_RGBA16"/>
-            <enum name="GL_CURRENT_BIT"/>
-            <enum name="GL_POINT_BIT"/>
-            <enum name="GL_LINE_BIT"/>
-            <enum name="GL_POLYGON_BIT"/>
-            <enum name="GL_POLYGON_STIPPLE_BIT"/>
-            <enum name="GL_PIXEL_MODE_BIT"/>
-            <enum name="GL_LIGHTING_BIT"/>
-            <enum name="GL_FOG_BIT"/>
-            <enum name="GL_ACCUM_BUFFER_BIT"/>
-            <enum name="GL_VIEWPORT_BIT"/>
-            <enum name="GL_TRANSFORM_BIT"/>
-            <enum name="GL_ENABLE_BIT"/>
-            <enum name="GL_HINT_BIT"/>
-            <enum name="GL_EVAL_BIT"/>
-            <enum name="GL_LIST_BIT"/>
-            <enum name="GL_TEXTURE_BIT"/>
-            <enum name="GL_SCISSOR_BIT"/>
-            <enum name="GL_ALL_ATTRIB_BITS"/>
             <enum name="GL_CLIENT_PIXEL_STORE_BIT"/>
             <enum name="GL_CLIENT_VERTEX_ARRAY_BIT"/>
             <enum name="GL_CLIENT_ALL_ATTRIB_BITS"/>
-            <enum name="GL_QUAD_STRIP"/>
-            <enum name="GL_POLYGON"/>
-            <enum name="GL_ACCUM"/>
-            <enum name="GL_LOAD"/>
-            <enum name="GL_RETURN"/>
-            <enum name="GL_MULT"/>
-            <enum name="GL_ADD"/>
-            <enum name="GL_AUX0"/>
-            <enum name="GL_AUX1"/>
-            <enum name="GL_AUX2"/>
-            <enum name="GL_AUX3"/>
-            <enum name="GL_2D"/>
-            <enum name="GL_3D"/>
-            <enum name="GL_3D_COLOR"/>
-            <enum name="GL_3D_COLOR_TEXTURE"/>
-            <enum name="GL_4D_COLOR_TEXTURE"/>
-            <enum name="GL_PASS_THROUGH_TOKEN"/>
-            <enum name="GL_POINT_TOKEN"/>
-            <enum name="GL_LINE_TOKEN"/>
-            <enum name="GL_POLYGON_TOKEN"/>
-            <enum name="GL_BITMAP_TOKEN"/>
-            <enum name="GL_DRAW_PIXEL_TOKEN"/>
-            <enum name="GL_COPY_PIXEL_TOKEN"/>
-            <enum name="GL_LINE_RESET_TOKEN"/>
-            <enum name="GL_EXP"/>
-            <enum name="GL_EXP2"/>
-            <enum name="GL_COEFF"/>
-            <enum name="GL_ORDER"/>
-            <enum name="GL_DOMAIN"/>
-            <enum name="GL_PIXEL_MAP_I_TO_I"/>
-            <enum name="GL_PIXEL_MAP_S_TO_S"/>
-            <enum name="GL_PIXEL_MAP_I_TO_R"/>
-            <enum name="GL_PIXEL_MAP_I_TO_G"/>
-            <enum name="GL_PIXEL_MAP_I_TO_B"/>
-            <enum name="GL_PIXEL_MAP_I_TO_A"/>
-            <enum name="GL_PIXEL_MAP_R_TO_R"/>
-            <enum name="GL_PIXEL_MAP_G_TO_G"/>
-            <enum name="GL_PIXEL_MAP_B_TO_B"/>
-            <enum name="GL_PIXEL_MAP_A_TO_A"/>
             <enum name="GL_VERTEX_ARRAY_POINTER"/>
             <enum name="GL_NORMAL_ARRAY_POINTER"/>
             <enum name="GL_COLOR_ARRAY_POINTER"/>
@@ -30402,141 +32971,9 @@
             <enum name="GL_EDGE_FLAG_ARRAY_POINTER"/>
             <enum name="GL_FEEDBACK_BUFFER_POINTER"/>
             <enum name="GL_SELECTION_BUFFER_POINTER"/>
-            <enum name="GL_CURRENT_COLOR"/>
-            <enum name="GL_CURRENT_INDEX"/>
-            <enum name="GL_CURRENT_NORMAL"/>
-            <enum name="GL_CURRENT_TEXTURE_COORDS"/>
-            <enum name="GL_CURRENT_RASTER_COLOR"/>
-            <enum name="GL_CURRENT_RASTER_INDEX"/>
-            <enum name="GL_CURRENT_RASTER_TEXTURE_COORDS"/>
-            <enum name="GL_CURRENT_RASTER_POSITION"/>
-            <enum name="GL_CURRENT_RASTER_POSITION_VALID"/>
-            <enum name="GL_CURRENT_RASTER_DISTANCE"/>
-            <enum name="GL_POINT_SMOOTH"/>
-            <enum name="GL_LINE_STIPPLE"/>
-            <enum name="GL_LINE_STIPPLE_PATTERN"/>
-            <enum name="GL_LINE_STIPPLE_REPEAT"/>
-            <enum name="GL_LIST_MODE"/>
-            <enum name="GL_MAX_LIST_NESTING"/>
-            <enum name="GL_LIST_BASE"/>
-            <enum name="GL_LIST_INDEX"/>
-            <enum name="GL_POLYGON_STIPPLE"/>
-            <enum name="GL_EDGE_FLAG"/>
-            <enum name="GL_LIGHTING"/>
-            <enum name="GL_LIGHT_MODEL_LOCAL_VIEWER"/>
-            <enum name="GL_LIGHT_MODEL_TWO_SIDE"/>
-            <enum name="GL_LIGHT_MODEL_AMBIENT"/>
-            <enum name="GL_SHADE_MODEL"/>
-            <enum name="GL_COLOR_MATERIAL_FACE"/>
-            <enum name="GL_COLOR_MATERIAL_PARAMETER"/>
-            <enum name="GL_COLOR_MATERIAL"/>
-            <enum name="GL_FOG"/>
-            <enum name="GL_FOG_INDEX"/>
-            <enum name="GL_FOG_DENSITY"/>
-            <enum name="GL_FOG_START"/>
-            <enum name="GL_FOG_END"/>
-            <enum name="GL_FOG_MODE"/>
-            <enum name="GL_FOG_COLOR"/>
-            <enum name="GL_ACCUM_CLEAR_VALUE"/>
-            <enum name="GL_MATRIX_MODE"/>
-            <enum name="GL_NORMALIZE"/>
-            <enum name="GL_MODELVIEW_STACK_DEPTH"/>
-            <enum name="GL_PROJECTION_STACK_DEPTH"/>
-            <enum name="GL_TEXTURE_STACK_DEPTH"/>
-            <enum name="GL_MODELVIEW_MATRIX"/>
-            <enum name="GL_PROJECTION_MATRIX"/>
-            <enum name="GL_TEXTURE_MATRIX"/>
-            <enum name="GL_ATTRIB_STACK_DEPTH"/>
             <enum name="GL_CLIENT_ATTRIB_STACK_DEPTH"/>
-            <enum name="GL_ALPHA_TEST"/>
-            <enum name="GL_ALPHA_TEST_FUNC"/>
-            <enum name="GL_ALPHA_TEST_REF"/>
             <enum name="GL_INDEX_LOGIC_OP"/>
-            <enum name="GL_LOGIC_OP"/>
-            <enum name="GL_AUX_BUFFERS"/>
-            <enum name="GL_INDEX_CLEAR_VALUE"/>
-            <enum name="GL_INDEX_WRITEMASK"/>
-            <enum name="GL_INDEX_MODE"/>
-            <enum name="GL_RGBA_MODE"/>
-            <enum name="GL_RENDER_MODE"/>
-            <enum name="GL_PERSPECTIVE_CORRECTION_HINT"/>
-            <enum name="GL_POINT_SMOOTH_HINT"/>
-            <enum name="GL_FOG_HINT"/>
-            <enum name="GL_TEXTURE_GEN_S"/>
-            <enum name="GL_TEXTURE_GEN_T"/>
-            <enum name="GL_TEXTURE_GEN_R"/>
-            <enum name="GL_TEXTURE_GEN_Q"/>
-            <enum name="GL_PIXEL_MAP_I_TO_I_SIZE"/>
-            <enum name="GL_PIXEL_MAP_S_TO_S_SIZE"/>
-            <enum name="GL_PIXEL_MAP_I_TO_R_SIZE"/>
-            <enum name="GL_PIXEL_MAP_I_TO_G_SIZE"/>
-            <enum name="GL_PIXEL_MAP_I_TO_B_SIZE"/>
-            <enum name="GL_PIXEL_MAP_I_TO_A_SIZE"/>
-            <enum name="GL_PIXEL_MAP_R_TO_R_SIZE"/>
-            <enum name="GL_PIXEL_MAP_G_TO_G_SIZE"/>
-            <enum name="GL_PIXEL_MAP_B_TO_B_SIZE"/>
-            <enum name="GL_PIXEL_MAP_A_TO_A_SIZE"/>
-            <enum name="GL_MAP_COLOR"/>
-            <enum name="GL_MAP_STENCIL"/>
-            <enum name="GL_INDEX_SHIFT"/>
-            <enum name="GL_INDEX_OFFSET"/>
-            <enum name="GL_RED_SCALE"/>
-            <enum name="GL_RED_BIAS"/>
-            <enum name="GL_ZOOM_X"/>
-            <enum name="GL_ZOOM_Y"/>
-            <enum name="GL_GREEN_SCALE"/>
-            <enum name="GL_GREEN_BIAS"/>
-            <enum name="GL_BLUE_SCALE"/>
-            <enum name="GL_BLUE_BIAS"/>
-            <enum name="GL_ALPHA_SCALE"/>
-            <enum name="GL_ALPHA_BIAS"/>
-            <enum name="GL_DEPTH_SCALE"/>
-            <enum name="GL_DEPTH_BIAS"/>
-            <enum name="GL_MAX_EVAL_ORDER"/>
-            <enum name="GL_MAX_LIGHTS"/>
-            <enum name="GL_MAX_CLIP_PLANES"/>
-            <enum name="GL_MAX_PIXEL_MAP_TABLE"/>
-            <enum name="GL_MAX_ATTRIB_STACK_DEPTH"/>
-            <enum name="GL_MAX_MODELVIEW_STACK_DEPTH"/>
-            <enum name="GL_MAX_NAME_STACK_DEPTH"/>
-            <enum name="GL_MAX_PROJECTION_STACK_DEPTH"/>
-            <enum name="GL_MAX_TEXTURE_STACK_DEPTH"/>
             <enum name="GL_MAX_CLIENT_ATTRIB_STACK_DEPTH"/>
-            <enum name="GL_INDEX_BITS"/>
-            <enum name="GL_RED_BITS"/>
-            <enum name="GL_GREEN_BITS"/>
-            <enum name="GL_BLUE_BITS"/>
-            <enum name="GL_ALPHA_BITS"/>
-            <enum name="GL_DEPTH_BITS"/>
-            <enum name="GL_STENCIL_BITS"/>
-            <enum name="GL_ACCUM_RED_BITS"/>
-            <enum name="GL_ACCUM_GREEN_BITS"/>
-            <enum name="GL_ACCUM_BLUE_BITS"/>
-            <enum name="GL_ACCUM_ALPHA_BITS"/>
-            <enum name="GL_NAME_STACK_DEPTH"/>
-            <enum name="GL_AUTO_NORMAL"/>
-            <enum name="GL_MAP1_COLOR_4"/>
-            <enum name="GL_MAP1_INDEX"/>
-            <enum name="GL_MAP1_NORMAL"/>
-            <enum name="GL_MAP1_TEXTURE_COORD_1"/>
-            <enum name="GL_MAP1_TEXTURE_COORD_2"/>
-            <enum name="GL_MAP1_TEXTURE_COORD_3"/>
-            <enum name="GL_MAP1_TEXTURE_COORD_4"/>
-            <enum name="GL_MAP1_VERTEX_3"/>
-            <enum name="GL_MAP1_VERTEX_4"/>
-            <enum name="GL_MAP2_COLOR_4"/>
-            <enum name="GL_MAP2_INDEX"/>
-            <enum name="GL_MAP2_NORMAL"/>
-            <enum name="GL_MAP2_TEXTURE_COORD_1"/>
-            <enum name="GL_MAP2_TEXTURE_COORD_2"/>
-            <enum name="GL_MAP2_TEXTURE_COORD_3"/>
-            <enum name="GL_MAP2_TEXTURE_COORD_4"/>
-            <enum name="GL_MAP2_VERTEX_3"/>
-            <enum name="GL_MAP2_VERTEX_4"/>
-            <enum name="GL_MAP1_GRID_DOMAIN"/>
-            <enum name="GL_MAP1_GRID_SEGMENTS"/>
-            <enum name="GL_MAP2_GRID_DOMAIN"/>
-            <enum name="GL_MAP2_GRID_SEGMENTS"/>
             <enum name="GL_FEEDBACK_BUFFER_SIZE"/>
             <enum name="GL_FEEDBACK_BUFFER_TYPE"/>
             <enum name="GL_SELECTION_BUFFER_SIZE"/>
@@ -30560,58 +32997,10 @@
             <enum name="GL_TEXTURE_COORD_ARRAY_TYPE"/>
             <enum name="GL_TEXTURE_COORD_ARRAY_STRIDE"/>
             <enum name="GL_EDGE_FLAG_ARRAY_STRIDE"/>
-            <enum name="GL_TEXTURE_COMPONENTS"/>
-            <enum name="GL_TEXTURE_BORDER"/>
             <enum name="GL_TEXTURE_LUMINANCE_SIZE"/>
             <enum name="GL_TEXTURE_INTENSITY_SIZE"/>
             <enum name="GL_TEXTURE_PRIORITY"/>
             <enum name="GL_TEXTURE_RESIDENT"/>
-            <enum name="GL_AMBIENT"/>
-            <enum name="GL_DIFFUSE"/>
-            <enum name="GL_SPECULAR"/>
-            <enum name="GL_POSITION"/>
-            <enum name="GL_SPOT_DIRECTION"/>
-            <enum name="GL_SPOT_EXPONENT"/>
-            <enum name="GL_SPOT_CUTOFF"/>
-            <enum name="GL_CONSTANT_ATTENUATION"/>
-            <enum name="GL_LINEAR_ATTENUATION"/>
-            <enum name="GL_QUADRATIC_ATTENUATION"/>
-            <enum name="GL_COMPILE"/>
-            <enum name="GL_COMPILE_AND_EXECUTE"/>
-            <enum name="GL_2_BYTES"/>
-            <enum name="GL_3_BYTES"/>
-            <enum name="GL_4_BYTES"/>
-            <enum name="GL_EMISSION"/>
-            <enum name="GL_SHININESS"/>
-            <enum name="GL_AMBIENT_AND_DIFFUSE"/>
-            <enum name="GL_COLOR_INDEXES"/>
-            <enum name="GL_MODELVIEW"/>
-            <enum name="GL_PROJECTION"/>
-            <enum name="GL_COLOR_INDEX"/>
-            <enum name="GL_LUMINANCE"/>
-            <enum name="GL_LUMINANCE_ALPHA"/>
-            <enum name="GL_BITMAP"/>
-            <enum name="GL_RENDER"/>
-            <enum name="GL_FEEDBACK"/>
-            <enum name="GL_SELECT"/>
-            <enum name="GL_FLAT"/>
-            <enum name="GL_SMOOTH"/>
-            <enum name="GL_S"/>
-            <enum name="GL_T"/>
-            <enum name="GL_R"/>
-            <enum name="GL_Q"/>
-            <enum name="GL_MODULATE"/>
-            <enum name="GL_DECAL"/>
-            <enum name="GL_TEXTURE_ENV_MODE"/>
-            <enum name="GL_TEXTURE_ENV_COLOR"/>
-            <enum name="GL_TEXTURE_ENV"/>
-            <enum name="GL_EYE_LINEAR"/>
-            <enum name="GL_OBJECT_LINEAR"/>
-            <enum name="GL_SPHERE_MAP"/>
-            <enum name="GL_TEXTURE_GEN_MODE"/>
-            <enum name="GL_OBJECT_PLANE"/>
-            <enum name="GL_EYE_PLANE"/>
-            <enum name="GL_CLAMP"/>
             <enum name="GL_ALPHA4"/>
             <enum name="GL_ALPHA8"/>
             <enum name="GL_ALPHA12"/>
@@ -30645,20 +33034,6 @@
             <enum name="GL_T2F_N3F_V3F"/>
             <enum name="GL_T2F_C4F_N3F_V3F"/>
             <enum name="GL_T4F_C4F_N3F_V4F"/>
-            <enum name="GL_CLIP_PLANE0"/>
-            <enum name="GL_CLIP_PLANE1"/>
-            <enum name="GL_CLIP_PLANE2"/>
-            <enum name="GL_CLIP_PLANE3"/>
-            <enum name="GL_CLIP_PLANE4"/>
-            <enum name="GL_CLIP_PLANE5"/>
-            <enum name="GL_LIGHT0"/>
-            <enum name="GL_LIGHT1"/>
-            <enum name="GL_LIGHT2"/>
-            <enum name="GL_LIGHT3"/>
-            <enum name="GL_LIGHT4"/>
-            <enum name="GL_LIGHT5"/>
-            <enum name="GL_LIGHT6"/>
-            <enum name="GL_LIGHT7"/>
             <command name="glDrawArrays"/>
             <command name="glDrawElements"/>
             <command name="glGetPointerv"/>
@@ -30738,7 +33113,7 @@
             <command name="glTexImage3D"/>
             <command name="glTexSubImage3D"/>
             <command name="glCopyTexSubImage3D"/>
-          </require>
+        </require>
     </feature>
     <feature api="gl" name="GL_VERSION_1_3" number="1.3">
         <require>
@@ -30974,15 +33349,17 @@
             <command name="glWindowPos3sv"/>
         </require>
         <require comment="Promoted from ARB_imaging subset to core">
-            <enum name="GL_FUNC_ADD"/>
-            <enum name="GL_FUNC_SUBTRACT"/>
-            <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
-            <enum name="GL_MIN"/>
-            <enum name="GL_MAX"/>
+            <enum name="GL_BLEND_COLOR"/>
+            <enum name="GL_BLEND_EQUATION"/>
             <enum name="GL_CONSTANT_COLOR"/>
             <enum name="GL_ONE_MINUS_CONSTANT_COLOR"/>
             <enum name="GL_CONSTANT_ALPHA"/>
             <enum name="GL_ONE_MINUS_CONSTANT_ALPHA"/>
+            <enum name="GL_FUNC_ADD"/>
+            <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
+            <enum name="GL_FUNC_SUBTRACT"/>
+            <enum name="GL_MIN"/>
+            <enum name="GL_MAX"/>
             <command name="glBlendColor"/>
             <command name="glBlendEquation"/>
         </require>
@@ -32935,6 +35312,7 @@
             <command name="glGenProgramPipelines"/>
             <command name="glIsProgramPipeline"/>
             <command name="glGetProgramPipelineiv"/>
+            <command name="glProgramParameteri"/>
             <command name="glProgramUniform1i"/>
             <command name="glProgramUniform1iv"/>
             <command name="glProgramUniform1f"/>
@@ -33596,7 +35974,6 @@
         <require profile="core" comment="Restore functionality removed in GL 3.2 core to GL 4.3. Needed for debug interface.">
             <enum name="GL_STACK_UNDERFLOW"/>
             <enum name="GL_STACK_OVERFLOW"/>
-            <command name="glGetPointerv"/>
         </require>
         <!-- Deprecated in OpenGL 4.3 core;
              deprecate tag not defined/supported yet
@@ -33845,9 +36222,69 @@
             <enum name="GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH"/>
         </require>
     </feature>
+    <feature api="gl" name="GL_VERSION_4_6" number="4.6">
+        <require comment="Reuse GL_KHR_context_flush_control">
+            <enum name="GL_CONTEXT_RELEASE_BEHAVIOR"/>
+            <enum name="GL_NONE"/>
+            <enum name="GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH"/>
+        </require>
+        <require comment="Reuse GL_ARB_gl_spirv">
+            <enum name="GL_SHADER_BINARY_FORMAT_SPIR_V"/>
+            <enum name="GL_SPIR_V_BINARY"/>
+            <command name="glSpecializeShader"/>
+        </require>
+        <require comment="Reuse GL_ARB_indirect_parameters">
+            <enum name="GL_PARAMETER_BUFFER"/>
+            <enum name="GL_PARAMETER_BUFFER_BINDING"/>
+            <command name="glMultiDrawArraysIndirectCount"/>
+            <command name="glMultiDrawElementsIndirectCount"/>
+        </require>
+        <require comment="Reuse GL_KHR_no_error">
+            <enum name="GL_CONTEXT_FLAG_NO_ERROR_BIT"/>
+        </require>
+        <require comment="Reuse GL_ARB_pipeline_statistics_query">
+            <enum name="GL_VERTICES_SUBMITTED"/>
+            <enum name="GL_PRIMITIVES_SUBMITTED"/>
+            <enum name="GL_VERTEX_SHADER_INVOCATIONS"/>
+            <enum name="GL_TESS_CONTROL_SHADER_PATCHES"/>
+            <enum name="GL_TESS_EVALUATION_SHADER_INVOCATIONS"/>
+            <enum name="GL_GEOMETRY_SHADER_INVOCATIONS"/>
+            <enum name="GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED"/>
+            <enum name="GL_FRAGMENT_SHADER_INVOCATIONS"/>
+            <enum name="GL_COMPUTE_SHADER_INVOCATIONS"/>
+            <enum name="GL_CLIPPING_INPUT_PRIMITIVES"/>
+            <enum name="GL_CLIPPING_OUTPUT_PRIMITIVES"/>
+        </require>
+        <require comment="Reuse GL_ARB_polygon_offset_clamp">
+            <enum name="GL_POLYGON_OFFSET_CLAMP"/>
+            <command name="glPolygonOffsetClamp"/>
+        </require>
+        <require comment="Reuse GL_ARB_shader_atomic_counter_ops (none)"/>
+        <require comment="Reuse GL_ARB_shader_draw_parameters (none)"/>
+        <require comment="Reuse GL_ARB_shader_group_vote (none)"/>
+        <require comment="Reuse GL_ARB_spirv_extensions">
+            <enum name="GL_SPIR_V_EXTENSIONS"/>
+            <enum name="GL_NUM_SPIR_V_EXTENSIONS"/>
+        </require>
+        <require comment="Reuse GL_ARB_texture_filter_anisotropic">
+            <enum name="GL_TEXTURE_MAX_ANISOTROPY"/>
+            <enum name="GL_MAX_TEXTURE_MAX_ANISOTROPY"/>
+        </require>
+        <require comment="Reuse GL_ARB_transform_feedback_overflow_query">
+            <enum name="GL_TRANSFORM_FEEDBACK_OVERFLOW"/>
+            <enum name="GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW"/>
+        </require>
+    </feature>
+
 
     <!-- SECTION: OpenGL ES 1.0/1.1 API interface definitions. -->
     <feature api="gles1" name="GL_VERSION_ES_CM_1_0" number="1.0">
+        <require comment="Not used by the API, for compatibility with old gl.h">
+            <type name="GLbyte"/>
+            <type name="GLclampf"/>
+            <type name="GLshort"/>
+            <type name="GLushort"/>
+        </require>
         <require>
             <!-- Additional API definition macros - ES 1.0/1.1, common/common-lite all in one header -->
             <enum name="GL_VERSION_ES_CL_1_0"/>
@@ -35844,6 +38281,400 @@
             <command name="glTexStorage3DMultisample"/>
         </require>
     </feature>
+    <feature api="glsc2" name="GL_SC_VERSION_2_0" number="2.0">
+        <require comment="Not used by the API, but could be used by applications">
+            <type name="GLbyte" comment="Used to define GL_BYTE data"/>
+            <type name="GLshort" comment="Used to define GL_SHORT data"/>
+            <type name="GLushort" comment="Used to define GL_UNSIGNED_SHORT data"/>
+        </require>
+        <require>
+            <enum name="GL_DEPTH_BUFFER_BIT"/>
+            <enum name="GL_STENCIL_BUFFER_BIT"/>
+            <enum name="GL_COLOR_BUFFER_BIT"/>
+            <enum name="GL_FALSE"/>
+            <enum name="GL_TRUE"/>
+            <enum name="GL_POINTS"/>
+            <enum name="GL_LINES"/>
+            <enum name="GL_LINE_LOOP"/>
+            <enum name="GL_LINE_STRIP"/>
+            <enum name="GL_TRIANGLES"/>
+            <enum name="GL_TRIANGLE_STRIP"/>
+            <enum name="GL_TRIANGLE_FAN"/>
+            <enum name="GL_ZERO"/>
+            <enum name="GL_ONE"/>
+            <enum name="GL_SRC_COLOR"/>
+            <enum name="GL_ONE_MINUS_SRC_COLOR"/>
+            <enum name="GL_SRC_ALPHA"/>
+            <enum name="GL_ONE_MINUS_SRC_ALPHA"/>
+            <enum name="GL_DST_ALPHA"/>
+            <enum name="GL_ONE_MINUS_DST_ALPHA"/>
+            <enum name="GL_DST_COLOR"/>
+            <enum name="GL_ONE_MINUS_DST_COLOR"/>
+            <enum name="GL_SRC_ALPHA_SATURATE"/>
+            <enum name="GL_FUNC_ADD"/>
+            <enum name="GL_BLEND_EQUATION"/>
+            <enum name="GL_BLEND_EQUATION_RGB"/>
+            <enum name="GL_BLEND_EQUATION_ALPHA"/>
+            <enum name="GL_FUNC_SUBTRACT"/>
+            <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
+            <enum name="GL_BLEND_DST_RGB"/>
+            <enum name="GL_BLEND_SRC_RGB"/>
+            <enum name="GL_BLEND_DST_ALPHA"/>
+            <enum name="GL_BLEND_SRC_ALPHA"/>
+            <enum name="GL_CONSTANT_COLOR"/>
+            <enum name="GL_ONE_MINUS_CONSTANT_COLOR"/>
+            <enum name="GL_CONSTANT_ALPHA"/>
+            <enum name="GL_ONE_MINUS_CONSTANT_ALPHA"/>
+            <enum name="GL_BLEND_COLOR"/>
+            <enum name="GL_ARRAY_BUFFER"/>
+            <enum name="GL_ELEMENT_ARRAY_BUFFER"/>
+            <enum name="GL_ARRAY_BUFFER_BINDING"/>
+            <enum name="GL_ELEMENT_ARRAY_BUFFER_BINDING"/>
+            <enum name="GL_STREAM_DRAW"/>
+            <enum name="GL_STATIC_DRAW"/>
+            <enum name="GL_DYNAMIC_DRAW"/>
+            <enum name="GL_BUFFER_SIZE"/>
+            <enum name="GL_BUFFER_USAGE"/>
+            <enum name="GL_CURRENT_VERTEX_ATTRIB"/>
+            <enum name="GL_FRONT"/>
+            <enum name="GL_BACK"/>
+            <enum name="GL_FRONT_AND_BACK"/>
+            <enum name="GL_TEXTURE_2D"/>
+            <enum name="GL_CULL_FACE"/>
+            <enum name="GL_BLEND"/>
+            <enum name="GL_DITHER"/>
+            <enum name="GL_STENCIL_TEST"/>
+            <enum name="GL_DEPTH_TEST"/>
+            <enum name="GL_SCISSOR_TEST"/>
+            <enum name="GL_POLYGON_OFFSET_FILL"/>
+            <enum name="GL_SAMPLE_ALPHA_TO_COVERAGE"/>
+            <enum name="GL_SAMPLE_COVERAGE"/>
+            <enum name="GL_NO_ERROR"/>
+            <enum name="GL_INVALID_ENUM"/>
+            <enum name="GL_INVALID_VALUE"/>
+            <enum name="GL_INVALID_OPERATION"/>
+            <enum name="GL_OUT_OF_MEMORY"/>
+            <enum name="GL_INVALID_FRAMEBUFFER_OPERATION"/>
+            <enum name="GL_CONTEXT_LOST"/>
+            <enum name="GL_CW"/>
+            <enum name="GL_CCW"/>
+            <enum name="GL_LINE_WIDTH"/>
+            <enum name="GL_ALIASED_POINT_SIZE_RANGE"/>
+            <enum name="GL_ALIASED_LINE_WIDTH_RANGE"/>
+            <enum name="GL_CULL_FACE_MODE"/>
+            <enum name="GL_FRONT_FACE"/>
+            <enum name="GL_DEPTH_RANGE"/>
+            <enum name="GL_DEPTH_WRITEMASK"/>
+            <enum name="GL_DEPTH_CLEAR_VALUE"/>
+            <enum name="GL_DEPTH_FUNC"/>
+            <enum name="GL_STENCIL_CLEAR_VALUE"/>
+            <enum name="GL_STENCIL_FUNC"/>
+            <enum name="GL_STENCIL_FAIL"/>
+            <enum name="GL_STENCIL_PASS_DEPTH_FAIL"/>
+            <enum name="GL_STENCIL_PASS_DEPTH_PASS"/>
+            <enum name="GL_STENCIL_REF"/>
+            <enum name="GL_STENCIL_VALUE_MASK"/>
+            <enum name="GL_STENCIL_WRITEMASK"/>
+            <enum name="GL_STENCIL_BACK_FUNC"/>
+            <enum name="GL_STENCIL_BACK_FAIL"/>
+            <enum name="GL_STENCIL_BACK_PASS_DEPTH_FAIL"/>
+            <enum name="GL_STENCIL_BACK_PASS_DEPTH_PASS"/>
+            <enum name="GL_STENCIL_BACK_REF"/>
+            <enum name="GL_STENCIL_BACK_VALUE_MASK"/>
+            <enum name="GL_STENCIL_BACK_WRITEMASK"/>
+            <enum name="GL_VIEWPORT"/>
+            <enum name="GL_SCISSOR_BOX"/>
+            <enum name="GL_COLOR_CLEAR_VALUE"/>
+            <enum name="GL_COLOR_WRITEMASK"/>
+            <enum name="GL_UNPACK_ALIGNMENT"/>
+            <enum name="GL_PACK_ALIGNMENT"/>
+            <enum name="GL_MAX_TEXTURE_SIZE"/>
+            <enum name="GL_MAX_VIEWPORT_DIMS"/>
+            <enum name="GL_SUBPIXEL_BITS"/>
+            <enum name="GL_RED_BITS"/>
+            <enum name="GL_GREEN_BITS"/>
+            <enum name="GL_BLUE_BITS"/>
+            <enum name="GL_ALPHA_BITS"/>
+            <enum name="GL_DEPTH_BITS"/>
+            <enum name="GL_STENCIL_BITS"/>
+            <enum name="GL_POLYGON_OFFSET_UNITS"/>
+            <enum name="GL_POLYGON_OFFSET_FACTOR"/>
+            <enum name="GL_TEXTURE_BINDING_2D"/>
+            <enum name="GL_SAMPLE_BUFFERS"/>
+            <enum name="GL_SAMPLES"/>
+            <enum name="GL_SAMPLE_COVERAGE_VALUE"/>
+            <enum name="GL_SAMPLE_COVERAGE_INVERT"/>
+            <enum name="GL_NUM_COMPRESSED_TEXTURE_FORMATS"/>
+            <enum name="GL_COMPRESSED_TEXTURE_FORMATS"/>
+            <enum name="GL_DONT_CARE"/>
+            <enum name="GL_FASTEST"/>
+            <enum name="GL_NICEST"/>
+            <enum name="GL_GENERATE_MIPMAP_HINT"/>
+            <enum name="GL_BYTE"/>
+            <enum name="GL_UNSIGNED_BYTE"/>
+            <enum name="GL_SHORT"/>
+            <enum name="GL_UNSIGNED_SHORT"/>
+            <enum name="GL_INT"/>
+            <enum name="GL_UNSIGNED_INT"/>
+            <enum name="GL_FLOAT"/>
+            <enum name="GL_RED"/>
+            <enum name="GL_RG"/>
+            <enum name="GL_RGB"/>
+            <enum name="GL_RGBA"/>
+            <enum name="GL_UNSIGNED_SHORT_4_4_4_4"/>
+            <enum name="GL_UNSIGNED_SHORT_5_5_5_1"/>
+            <enum name="GL_UNSIGNED_SHORT_5_6_5"/>
+            <enum name="GL_MAX_VERTEX_ATTRIBS"/>
+            <enum name="GL_MAX_VERTEX_UNIFORM_VECTORS"/>
+            <enum name="GL_MAX_VARYING_VECTORS"/>
+            <enum name="GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS"/>
+            <enum name="GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS"/>
+            <enum name="GL_MAX_TEXTURE_IMAGE_UNITS"/>
+            <enum name="GL_MAX_FRAGMENT_UNIFORM_VECTORS"/>
+            <enum name="GL_LINK_STATUS"/>
+            <enum name="GL_SHADING_LANGUAGE_VERSION"/>
+            <enum name="GL_CURRENT_PROGRAM"/>
+            <enum name="GL_NEVER"/>
+            <enum name="GL_LESS"/>
+            <enum name="GL_EQUAL"/>
+            <enum name="GL_LEQUAL"/>
+            <enum name="GL_GREATER"/>
+            <enum name="GL_NOTEQUAL"/>
+            <enum name="GL_GEQUAL"/>
+            <enum name="GL_ALWAYS"/>
+            <enum name="GL_KEEP"/>
+            <enum name="GL_REPLACE"/>
+            <enum name="GL_INCR"/>
+            <enum name="GL_DECR"/>
+            <enum name="GL_INVERT"/>
+            <enum name="GL_INCR_WRAP"/>
+            <enum name="GL_DECR_WRAP"/>
+            <enum name="GL_VENDOR"/>
+            <enum name="GL_RENDERER"/>
+            <enum name="GL_VERSION"/>
+            <enum name="GL_EXTENSIONS"/>
+            <enum name="GL_NEAREST"/>
+            <enum name="GL_LINEAR"/>
+            <enum name="GL_NEAREST_MIPMAP_NEAREST"/>
+            <enum name="GL_LINEAR_MIPMAP_NEAREST"/>
+            <enum name="GL_NEAREST_MIPMAP_LINEAR"/>
+            <enum name="GL_LINEAR_MIPMAP_LINEAR"/>
+            <enum name="GL_TEXTURE_MAG_FILTER"/>
+            <enum name="GL_TEXTURE_MIN_FILTER"/>
+            <enum name="GL_TEXTURE_WRAP_S"/>
+            <enum name="GL_TEXTURE_WRAP_T"/>
+            <enum name="GL_TEXTURE_IMMUTABLE_FORMAT"/>
+            <enum name="GL_TEXTURE"/>
+            <enum name="GL_TEXTURE0"/>
+            <enum name="GL_TEXTURE1"/>
+            <enum name="GL_TEXTURE2"/>
+            <enum name="GL_TEXTURE3"/>
+            <enum name="GL_TEXTURE4"/>
+            <enum name="GL_TEXTURE5"/>
+            <enum name="GL_TEXTURE6"/>
+            <enum name="GL_TEXTURE7"/>
+            <enum name="GL_TEXTURE8"/>
+            <enum name="GL_TEXTURE9"/>
+            <enum name="GL_TEXTURE10"/>
+            <enum name="GL_TEXTURE11"/>
+            <enum name="GL_TEXTURE12"/>
+            <enum name="GL_TEXTURE13"/>
+            <enum name="GL_TEXTURE14"/>
+            <enum name="GL_TEXTURE15"/>
+            <enum name="GL_TEXTURE16"/>
+            <enum name="GL_TEXTURE17"/>
+            <enum name="GL_TEXTURE18"/>
+            <enum name="GL_TEXTURE19"/>
+            <enum name="GL_TEXTURE20"/>
+            <enum name="GL_TEXTURE21"/>
+            <enum name="GL_TEXTURE22"/>
+            <enum name="GL_TEXTURE23"/>
+            <enum name="GL_TEXTURE24"/>
+            <enum name="GL_TEXTURE25"/>
+            <enum name="GL_TEXTURE26"/>
+            <enum name="GL_TEXTURE27"/>
+            <enum name="GL_TEXTURE28"/>
+            <enum name="GL_TEXTURE29"/>
+            <enum name="GL_TEXTURE30"/>
+            <enum name="GL_TEXTURE31"/>
+            <enum name="GL_ACTIVE_TEXTURE"/>
+            <enum name="GL_REPEAT"/>
+            <enum name="GL_CLAMP_TO_EDGE"/>
+            <enum name="GL_MIRRORED_REPEAT"/>
+            <enum name="GL_SAMPLER_2D"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_ENABLED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_SIZE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_STRIDE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_TYPE"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_POINTER"/>
+            <enum name="GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"/>
+            <enum name="GL_IMPLEMENTATION_COLOR_READ_TYPE"/>
+            <enum name="GL_IMPLEMENTATION_COLOR_READ_FORMAT"/>
+            <enum name="GL_NUM_PROGRAM_BINARY_FORMATS"/>
+            <enum name="GL_PROGRAM_BINARY_FORMATS"/>
+            <enum name="GL_LOW_FLOAT"/>
+            <enum name="GL_MEDIUM_FLOAT"/>
+            <enum name="GL_HIGH_FLOAT"/>
+            <enum name="GL_LOW_INT"/>
+            <enum name="GL_MEDIUM_INT"/>
+            <enum name="GL_HIGH_INT"/>
+            <enum name="GL_FRAMEBUFFER"/>
+            <enum name="GL_RENDERBUFFER"/>
+            <enum name="GL_R8"/>
+            <enum name="GL_RG8"/>
+            <enum name="GL_RGB8"/>
+            <enum name="GL_RGBA8"/>
+            <enum name="GL_RGBA4"/>
+            <enum name="GL_RGB5_A1"/>
+            <enum name="GL_RGB565"/>
+            <enum name="GL_DEPTH_COMPONENT16"/>
+            <enum name="GL_STENCIL_INDEX8"/>
+            <enum name="GL_RENDERBUFFER_WIDTH"/>
+            <enum name="GL_RENDERBUFFER_HEIGHT"/>
+            <enum name="GL_RENDERBUFFER_INTERNAL_FORMAT"/>
+            <enum name="GL_RENDERBUFFER_RED_SIZE"/>
+            <enum name="GL_RENDERBUFFER_GREEN_SIZE"/>
+            <enum name="GL_RENDERBUFFER_BLUE_SIZE"/>
+            <enum name="GL_RENDERBUFFER_ALPHA_SIZE"/>
+            <enum name="GL_RENDERBUFFER_DEPTH_SIZE"/>
+            <enum name="GL_RENDERBUFFER_STENCIL_SIZE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME"/>
+            <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL"/>
+            <enum name="GL_COLOR_ATTACHMENT0"/>
+            <enum name="GL_DEPTH_ATTACHMENT"/>
+            <enum name="GL_STENCIL_ATTACHMENT"/>
+            <enum name="GL_NONE"/>
+            <enum name="GL_FRAMEBUFFER_COMPLETE"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"/>
+            <enum name="GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"/>
+            <enum name="GL_FRAMEBUFFER_UNSUPPORTED"/>
+            <enum name="GL_FRAMEBUFFER_UNDEFINED"/>
+            <enum name="GL_FRAMEBUFFER_BINDING"/>
+            <enum name="GL_RENDERBUFFER_BINDING"/>
+            <enum name="GL_MAX_RENDERBUFFER_SIZE"/>
+            <enum name="GL_NO_ERROR"/>
+            <enum name="GL_GUILTY_CONTEXT_RESET"/>
+            <enum name="GL_INNOCENT_CONTEXT_RESET"/>
+            <enum name="GL_UNKNOWN_CONTEXT_RESET"/>
+            <enum name="GL_CONTEXT_ROBUST_ACCESS"/>
+            <enum name="GL_RESET_NOTIFICATION_STRATEGY"/>
+            <enum name="GL_LOSE_CONTEXT_ON_RESET"/>
+            <command name="glActiveTexture"/>
+            <command name="glBindBuffer"/>
+            <command name="glBindFramebuffer"/>
+            <command name="glBindRenderbuffer"/>
+            <command name="glBindTexture"/>
+            <command name="glBlendColor"/>
+            <command name="glBlendEquation"/>
+            <command name="glBlendEquationSeparate"/>
+            <command name="glBlendFunc"/>
+            <command name="glBlendFuncSeparate"/>
+            <command name="glBufferData"/>
+            <command name="glBufferSubData"/>
+            <command name="glCheckFramebufferStatus"/>
+            <command name="glClear"/>
+            <command name="glClearColor"/>
+            <command name="glClearDepthf"/>
+            <command name="glClearStencil"/>
+            <command name="glColorMask"/>
+            <command name="glCompressedTexSubImage2D"/>
+            <command name="glCreateProgram"/>
+            <command name="glCullFace"/>
+            <command name="glDepthFunc"/>
+            <command name="glDepthMask"/>
+            <command name="glDepthRangef"/>
+            <command name="glDisable"/>
+            <command name="glDisableVertexAttribArray"/>
+            <command name="glDrawArrays"/>
+            <command name="glDrawRangeElements"/>
+            <command name="glEnable"/>
+            <command name="glEnableVertexAttribArray"/>
+            <command name="glFinish"/>
+            <command name="glFlush"/>
+            <command name="glFramebufferRenderbuffer"/>
+            <command name="glFramebufferTexture2D"/>
+            <command name="glFrontFace"/>
+            <command name="glGenBuffers"/>
+            <command name="glGenerateMipmap"/>
+            <command name="glGenFramebuffers"/>
+            <command name="glGenRenderbuffers"/>
+            <command name="glGenTextures"/>
+            <command name="glGetAttribLocation"/>
+            <command name="glGetBooleanv"/>
+            <command name="glGetBufferParameteriv"/>
+            <command name="glGetError"/>
+            <command name="glGetFloatv"/>
+            <command name="glGetFramebufferAttachmentParameteriv"/>
+            <command name="glGetGraphicsResetStatus"/>
+            <command name="glGetIntegerv"/>
+            <command name="glGetProgramiv"/>
+            <command name="glGetRenderbufferParameteriv"/>
+            <command name="glGetString"/>
+            <command name="glGetTexParameterfv"/>
+            <command name="glGetTexParameteriv"/>
+            <command name="glGetnUniformfv"/>
+            <command name="glGetnUniformiv"/>
+            <command name="glGetUniformLocation"/>
+            <command name="glGetVertexAttribfv"/>
+            <command name="glGetVertexAttribiv"/>
+            <command name="glGetVertexAttribPointerv"/>
+            <command name="glHint"/>
+            <command name="glIsEnabled"/>
+            <command name="glLineWidth"/>
+            <command name="glPixelStorei"/>
+            <command name="glPolygonOffset"/>
+            <command name="glProgramBinary"/>
+            <command name="glReadnPixels"/>
+            <command name="glRenderbufferStorage"/>
+            <command name="glSampleCoverage"/>
+            <command name="glScissor"/>
+            <command name="glStencilFunc"/>
+            <command name="glStencilFuncSeparate"/>
+            <command name="glStencilMask"/>
+            <command name="glStencilMaskSeparate"/>
+            <command name="glStencilOp"/>
+            <command name="glStencilOpSeparate"/>
+            <command name="glTexStorage2D"/>
+            <command name="glTexParameterf"/>
+            <command name="glTexParameterfv"/>
+            <command name="glTexParameteri"/>
+            <command name="glTexParameteriv"/>
+            <command name="glTexSubImage2D"/>
+            <command name="glUniform1f"/>
+            <command name="glUniform1fv"/>
+            <command name="glUniform1i"/>
+            <command name="glUniform1iv"/>
+            <command name="glUniform2f"/>
+            <command name="glUniform2fv"/>
+            <command name="glUniform2i"/>
+            <command name="glUniform2iv"/>
+            <command name="glUniform3f"/>
+            <command name="glUniform3fv"/>
+            <command name="glUniform3i"/>
+            <command name="glUniform3iv"/>
+            <command name="glUniform4f"/>
+            <command name="glUniform4fv"/>
+            <command name="glUniform4i"/>
+            <command name="glUniform4iv"/>
+            <command name="glUniformMatrix2fv"/>
+            <command name="glUniformMatrix3fv"/>
+            <command name="glUniformMatrix4fv"/>
+            <command name="glUseProgram"/>
+            <command name="glVertexAttrib1f"/>
+            <command name="glVertexAttrib1fv"/>
+            <command name="glVertexAttrib2f"/>
+            <command name="glVertexAttrib2fv"/>
+            <command name="glVertexAttrib3f"/>
+            <command name="glVertexAttrib3fv"/>
+            <command name="glVertexAttrib4f"/>
+            <command name="glVertexAttrib4fv"/>
+            <command name="glVertexAttribPointer"/>
+            <command name="glViewport"/>
+        </require>
+    </feature>
 
     <!-- SECTION: OpenGL / OpenGL ES extension interface definitions -->
     <extensions>
@@ -35922,7 +38753,37 @@
                 <command name="glBlendEquationSeparateIndexedAMD"/>
             </require>
         </extension>
+        <extension name="GL_AMD_framebuffer_sample_positions" supported="gl">
+            <require>
+                <enum name="GL_SUBSAMPLE_DISTANCE_AMD"/>
+                <enum name="GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD"/>
+                <enum name="GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD"/>
+                <enum name="GL_ALL_PIXELS_AMD"/>
+                <command name="glFramebufferSamplePositionsfvAMD"/>
+                <command name="glNamedFramebufferSamplePositionsfvAMD"/>
+                <command name="glGetFramebufferParameterfvAMD"/>
+                <command name="glGetNamedFramebufferParameterfvAMD"/>
+            </require>
+        </extension>
         <extension name="GL_AMD_gcn_shader" supported="gl"/>
+        <extension name="GL_AMD_gpu_shader_half_float" supported="gl">
+            <require>
+                <enum name="GL_FLOAT16_NV"/>
+                <enum name="GL_FLOAT16_VEC2_NV"/>
+                <enum name="GL_FLOAT16_VEC3_NV"/>
+                <enum name="GL_FLOAT16_VEC4_NV"/>
+                <enum name="GL_FLOAT16_MAT2_AMD"/>
+                <enum name="GL_FLOAT16_MAT3_AMD"/>
+                <enum name="GL_FLOAT16_MAT4_AMD"/>
+                <enum name="GL_FLOAT16_MAT2x3_AMD"/>
+                <enum name="GL_FLOAT16_MAT2x4_AMD"/>
+                <enum name="GL_FLOAT16_MAT3x2_AMD"/>
+                <enum name="GL_FLOAT16_MAT3x4_AMD"/>
+                <enum name="GL_FLOAT16_MAT4x2_AMD"/>
+                <enum name="GL_FLOAT16_MAT4x3_AMD"/>
+            </require>
+        </extension>
+        <extension name="GL_AMD_gpu_shader_int16" supported="gl"/>
         <extension name="GL_AMD_gpu_shader_int64" supported="gl">
             <require>
                 <enum name="GL_INT64_NV"/>
@@ -36034,7 +38895,7 @@
                 <command name="glQueryObjectParameteruiAMD"/>
             </require>
         </extension>
-        <extension name="GL_AMD_performance_monitor" supported="gl|gles2">
+        <extension name="GL_AMD_performance_monitor" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_COUNTER_TYPE_AMD"/>
                 <enum name="GL_COUNTER_RANGE_AMD"/>
@@ -36085,8 +38946,12 @@
             </require>
         </extension>
         <extension name="GL_AMD_shader_atomic_counter_ops" supported="gl"/>
+        <extension name="GL_AMD_shader_ballot" supported="gl"/>
+        <extension name="GL_AMD_shader_gpu_shader_half_float_fetch" supported="gl"/>
+        <extension name="GL_AMD_shader_image_load_store_lod" supported="gl"/>
         <extension name="GL_AMD_shader_stencil_export" supported="gl"/>
         <extension name="GL_AMD_shader_trinary_minmax" supported="gl"/>
+        <extension name="GL_AMD_shader_explicit_vertex_parameter" supported="gl"/>
         <extension name="GL_AMD_sparse_texture" supported="gl">
             <require>
                 <enum name="GL_VIRTUAL_PAGE_SIZE_X_AMD"/>
@@ -36111,6 +38976,7 @@
                 <command name="glStencilOpValueAMD"/>
             </require>
         </extension>
+        <extension name="GL_AMD_texture_gather_bias_lod" supported="gl"/>
         <extension name="GL_AMD_texture_texture4" supported="gl"/>
         <extension name="GL_AMD_transform_feedback3_lines_triangles" supported="gl"/>
         <extension name="GL_AMD_transform_feedback4" supported="gl">
@@ -36335,7 +39201,7 @@
                 <command name="glGetObjectParameterivAPPLE"/>
             </require>
         </extension>
-        <extension name="GL_APPLE_rgb_422" supported="gl|gles2">
+        <extension name="GL_APPLE_rgb_422" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_RGB_422_APPLE"/>
                 <enum name="GL_UNSIGNED_SHORT_8_8_APPLE"/>
@@ -36504,7 +39370,7 @@
                 <command name="glMemoryBarrierByRegion"/>
             </require>
         </extension>
-        <extension name="GL_ARB_ES3_2_compatibility" supported="gl">
+        <extension name="GL_ARB_ES3_2_compatibility" supported="gl|glcore">
             <require>
                 <enum name="GL_PRIMITIVE_BOUNDING_BOX_ARB"/>
                 <enum name="GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB"/>
@@ -36930,7 +39796,7 @@
                 <command name="glDrawElementsIndirect"/>
             </require>
         </extension>
-        <extension name="GL_ARB_draw_instanced" supported="gl">
+        <extension name="GL_ARB_draw_instanced" supported="gl|glcore">
             <require>
                 <command name="glDrawArraysInstancedARB"/>
                 <command name="glDrawElementsInstancedARB"/>
@@ -37063,7 +39929,7 @@
                 <enum name="GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_fragment_shader_interlock" supported="gl"/>
+        <extension name="GL_ARB_fragment_shader_interlock" supported="gl|glcore"/>
         <extension name="GL_ARB_framebuffer_no_attachments" supported="gl|glcore">
             <require>
                 <enum name="GL_FRAMEBUFFER_DEFAULT_WIDTH"/>
@@ -37183,7 +40049,7 @@
                 <enum name="GL_FRAMEBUFFER_SRGB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_geometry_shader4" supported="gl">
+        <extension name="GL_ARB_geometry_shader4" supported="gl|glcore">
             <require>
                 <enum name="GL_LINES_ADJACENCY_ARB"/>
                 <enum name="GL_LINE_STRIP_ADJACENCY_ARB"/>
@@ -37228,6 +40094,13 @@
                 <command name="glGetCompressedTextureSubImage"/>
             </require>
         </extension>
+        <extension name="GL_ARB_gl_spirv" supported="gl|glcore">
+            <require>
+                <enum name="GL_SHADER_BINARY_FORMAT_SPIR_V_ARB"/>
+                <enum name="GL_SPIR_V_BINARY_ARB"/>
+                <command name="glSpecializeShaderARB"/>
+            </require>
+        </extension>
         <extension name="GL_ARB_gpu_shader5" supported="gl|glcore">
             <require>
                 <enum name="GL_GEOMETRY_SHADER_INVOCATIONS"/>
@@ -37273,7 +40146,7 @@
                 <command name="glGetUniformdv"/>
             </require>
         </extension>
-        <extension name="GL_ARB_gpu_shader_int64" supported="gl">
+        <extension name="GL_ARB_gpu_shader_int64" supported="gl|glcore">
             <require>
                 <enum name="GL_INT64_ARB"/>
                 <enum name="GL_UNSIGNED_INT64_ARB"/>
@@ -37335,17 +40208,17 @@
         </extension>
         <extension name="GL_ARB_imaging" supported="gl|glcore" comment="Now treating ARB_imaging as an extension, not a GL API version">
             <require>
+                <enum name="GL_BLEND_COLOR"/>
+                <enum name="GL_BLEND_EQUATION"/>
                 <enum name="GL_CONSTANT_COLOR"/>
                 <enum name="GL_ONE_MINUS_CONSTANT_COLOR"/>
                 <enum name="GL_CONSTANT_ALPHA"/>
                 <enum name="GL_ONE_MINUS_CONSTANT_ALPHA"/>
-                <enum name="GL_BLEND_COLOR"/>
                 <enum name="GL_FUNC_ADD"/>
+                <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
+                <enum name="GL_FUNC_SUBTRACT"/>
                 <enum name="GL_MIN"/>
                 <enum name="GL_MAX"/>
-                <enum name="GL_BLEND_EQUATION"/>
-                <enum name="GL_FUNC_SUBTRACT"/>
-                <enum name="GL_FUNC_REVERSE_SUBTRACT"/>
                 <command name="glBlendColor"/>
                 <command name="glBlendEquation"/>
             </require>
@@ -37456,7 +40329,7 @@
                 <command name="glMultiDrawElementsIndirectCountARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_instanced_arrays" supported="gl">
+        <extension name="GL_ARB_instanced_arrays" supported="gl|glcore">
             <require>
                 <enum name="GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB"/>
                 <command name="glVertexAttribDivisorARB"/>
@@ -37759,7 +40632,7 @@
                 <enum name="GL_ANY_SAMPLES_PASSED"/>
             </require>
         </extension>
-        <extension name="GL_ARB_parallel_shader_compile" supported="gl">
+        <extension name="GL_ARB_parallel_shader_compile" supported="gl|glcore">
             <require>
                 <enum name="GL_MAX_SHADER_COMPILER_THREADS_ARB"/>
                 <enum name="GL_COMPLETION_STATUS_ARB"/>
@@ -37781,7 +40654,7 @@
                 <enum name="GL_CLIPPING_OUTPUT_PRIMITIVES_ARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_pixel_buffer_object" supported="gl">
+        <extension name="GL_ARB_pixel_buffer_object" supported="gl|glcore">
             <require>
                 <enum name="GL_PIXEL_PACK_BUFFER_ARB"/>
                 <enum name="GL_PIXEL_UNPACK_BUFFER_ARB"/>
@@ -37805,7 +40678,13 @@
                 <enum name="GL_COORD_REPLACE_ARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_post_depth_coverage" supported="gl"/>
+        <extension name="GL_ARB_polygon_offset_clamp" supported="gl|glcore">
+            <require>
+                <enum name="GL_POLYGON_OFFSET_CLAMP"/>
+                <command name="glPolygonOffsetClamp"/>
+            </require>
+        </extension>
+        <extension name="GL_ARB_post_depth_coverage" supported="gl|glcore"/>
         <extension name="GL_ARB_program_interface_query" supported="gl|glcore">
             <require>
                 <enum name="GL_UNIFORM"/>
@@ -37919,7 +40798,7 @@
             </require>
         </extension>
         <extension name="GL_ARB_robustness_isolation" supported="gl|glcore"/>
-        <extension name="GL_ARB_sample_locations" supported="gl">
+        <extension name="GL_ARB_sample_locations" supported="gl|glcore">
             <require>
                 <enum name="GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB"/>
                 <enum name="GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB"/>
@@ -37989,6 +40868,7 @@
                 <command name="glGenProgramPipelines"/>
                 <command name="glIsProgramPipeline"/>
                 <command name="glGetProgramPipelineiv"/>
+                <command name="glProgramParameteri"/>
                 <command name="glProgramUniform1i"/>
                 <command name="glProgramUniform1iv"/>
                 <command name="glProgramUniform1f"/>
@@ -38043,7 +40923,7 @@
                 <command name="glGetProgramPipelineInfoLog"/>
             </require>
         </extension>
-        <extension name="GL_ARB_shader_atomic_counter_ops" supported="gl"/>
+        <extension name="GL_ARB_shader_atomic_counter_ops" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_atomic_counters" supported="gl|glcore">
             <require>
                 <enum name="GL_ATOMIC_COUNTER_BUFFER"/>
@@ -38078,9 +40958,9 @@
                 <command name="glGetActiveAtomicCounterBufferiv"/>
             </require>
         </extension>
-        <extension name="GL_ARB_shader_ballot" supported="gl"/>
+        <extension name="GL_ARB_shader_ballot" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_bit_encoding" supported="gl|glcore"/>
-        <extension name="GL_ARB_shader_clock" supported="gl"/>
+        <extension name="GL_ARB_shader_clock" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_draw_parameters" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_group_vote" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_image_load_store" supported="gl|glcore">
@@ -38280,7 +41160,7 @@
         </extension>
         <extension name="GL_ARB_shader_texture_image_samples" supported="gl|glcore"/>
         <extension name="GL_ARB_shader_texture_lod" supported="gl"/>
-        <extension name="GL_ARB_shader_viewport_layer_array" supported="gl"/>
+        <extension name="GL_ARB_shader_viewport_layer_array" supported="gl|glcore"/>
         <extension name="GL_ARB_shading_language_100" supported="gl">
             <require>
                 <enum name="GL_SHADING_LANGUAGE_VERSION_ARB"/>
@@ -38342,8 +41222,14 @@
                 <command name="glTexPageCommitmentARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_sparse_texture2" supported="gl"/>
-        <extension name="GL_ARB_sparse_texture_clamp" supported="gl"/>
+        <extension name="GL_ARB_sparse_texture2" supported="gl|glcore"/>
+        <extension name="GL_ARB_sparse_texture_clamp" supported="gl|glcore"/>
+        <extension name="GL_ARB_spirv_extensions" supported="gl|glcore">
+            <require>
+                <enum name="GL_SPIR_V_EXTENSIONS"/>
+                <enum name="GL_NUM_SPIR_V_EXTENSIONS"/>
+            </require>
+        </extension>
         <extension name="GL_ARB_stencil_texturing" supported="gl|glcore">
             <require>
                 <enum name="GL_DEPTH_STENCIL_TEXTURE_MODE"/>
@@ -38423,12 +41309,12 @@
                 <command name="glTextureBarrier"/>
             </require>
         </extension>
-        <extension name="GL_ARB_texture_border_clamp" supported="gl">
+        <extension name="GL_ARB_texture_border_clamp" supported="gl|glcore">
             <require>
                 <enum name="GL_CLAMP_TO_BORDER_ARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_texture_buffer_object" supported="gl">
+        <extension name="GL_ARB_texture_buffer_object" supported="gl|glcore">
             <require>
                 <enum name="GL_TEXTURE_BUFFER_ARB"/>
                 <enum name="GL_MAX_TEXTURE_BUFFER_SIZE_ARB"/>
@@ -38552,7 +41438,13 @@
                 <enum name="GL_DOT3_RGBA_ARB"/>
             </require>
         </extension>
-        <extension name="GL_ARB_texture_filter_minmax" supported="gl">
+        <extension name="GL_ARB_texture_filter_anisotropic" supported="gl|glcore">
+            <require>
+                <enum name="GL_TEXTURE_MAX_ANISOTROPY"/>
+                <enum name="GL_MAX_TEXTURE_MAX_ANISOTROPY"/>
+            </require>
+        </extension>
+        <extension name="GL_ARB_texture_filter_minmax" supported="gl|glcore">
             <require>
                 <enum name="GL_TEXTURE_REDUCTION_MODE_ARB"/>
                 <enum name="GL_WEIGHTED_AVERAGE_ARB"/>
@@ -38594,7 +41486,7 @@
                 <enum name="GL_MIRROR_CLAMP_TO_EDGE"/>
             </require>
         </extension>
-        <extension name="GL_ARB_texture_mirrored_repeat" supported="gl">
+        <extension name="GL_ARB_texture_mirrored_repeat" supported="gl|glcore">
             <require>
                 <enum name="GL_MIRRORED_REPEAT_ARB"/>
             </require>
@@ -38628,7 +41520,7 @@
                 <command name="glSampleMaski"/>
             </require>
         </extension>
-        <extension name="GL_ARB_texture_non_power_of_two" supported="gl"/>
+        <extension name="GL_ARB_texture_non_power_of_two" supported="gl|glcore"/>
         <extension name="GL_ARB_texture_query_levels" supported="gl|glcore"/>
         <extension name="GL_ARB_texture_query_lod" supported="gl|glcore"/>
         <extension name="GL_ARB_texture_rectangle" supported="gl">
@@ -39669,6 +42561,17 @@
                 <enum name="GL_422_REV_AVERAGE_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_EGL_image_array" supported="gles2">
+        </extension>
+        <extension name="GL_EXT_EGL_image_storage" supported="gl|glcore|gles2">
+            <require>
+                <type name="GLeglImageOES"/>
+                <command name="glEGLImageTargetTexStorageEXT"/>
+            </require>
+            <require comment="Supported only if GL_EXT_direct_state_access, ARB_direct_state_access, or OpenGL 4.5 are supported">
+                <command name="glEGLImageTargetTextureStorageEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_YUV_target" supported="gles2">
             <require>
                 <enum name="GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT"/>
@@ -39782,6 +42685,38 @@
                 <!-- <command name="glNamedBufferStorageEXT"/> -->
             </require>
         </extension>
+        <extension name="GL_EXT_clear_texture" supported="gles2">
+            <require>
+                <command name="glClearTexImageEXT"/>
+                <command name="glClearTexSubImageEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_clip_control" supported="gles2">
+            <require comment="Port of GL_ARB_clip_control">
+                <command name="glClipControlEXT"/>
+                <enum name="GL_LOWER_LEFT_EXT"/>
+                <enum name="GL_UPPER_LEFT_EXT"/>
+                <enum name="GL_NEGATIVE_ONE_TO_ONE_EXT"/>
+                <enum name="GL_ZERO_TO_ONE_EXT"/>
+                <enum name="GL_CLIP_ORIGIN_EXT"/>
+                <enum name="GL_CLIP_DEPTH_MODE_EXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_clip_cull_distance" supported="gles2">
+            <require>
+                <enum name="GL_MAX_CLIP_DISTANCES_EXT"/>
+                <enum name="GL_MAX_CULL_DISTANCES_EXT"/>
+                <enum name="GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT"/>
+                <enum name="GL_CLIP_DISTANCE0_EXT"/>
+                <enum name="GL_CLIP_DISTANCE1_EXT"/>
+                <enum name="GL_CLIP_DISTANCE2_EXT"/>
+                <enum name="GL_CLIP_DISTANCE3_EXT"/>
+                <enum name="GL_CLIP_DISTANCE4_EXT"/>
+                <enum name="GL_CLIP_DISTANCE5_EXT"/>
+                <enum name="GL_CLIP_DISTANCE6_EXT"/>
+                <enum name="GL_CLIP_DISTANCE7_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_clip_volume_hint" supported="gl">
             <require>
                 <enum name="GL_CLIP_VOLUME_CLIPPING_HINT_EXT"/>
@@ -39820,6 +42755,7 @@
                 <command name="glUnlockArraysEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_conservative_depth" supported="gles2"/>
         <extension name="GL_EXT_convolution" supported="gl">
             <require>
                 <enum name="GL_CONVOLUTION_1D_EXT"/>
@@ -39920,7 +42856,7 @@
                 <command name="glCullParameterfvEXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_debug_label" supported="gl|gles2">
+        <extension name="GL_EXT_debug_label" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_PROGRAM_PIPELINE_OBJECT_EXT"/>
                 <enum name="GL_PROGRAM_OBJECT_EXT"/>
@@ -39936,7 +42872,7 @@
                 <enum name="GL_TRANSFORM_FEEDBACK"/>
             </require>
         </extension>
-        <extension name="GL_EXT_debug_marker" supported="gl|gles2">
+        <extension name="GL_EXT_debug_marker" supported="gl|glcore|gles1|gles2">
             <require>
                 <command name="glInsertEventMarkerEXT"/>
                 <command name="glPushGroupMarkerEXT"/>
@@ -39950,7 +42886,7 @@
                 <command name="glDepthBoundsEXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_direct_state_access" supported="gl" comment="DSA extension doesn't identify which interfaces are core profile and keeps getting expanded. This is in sync with revision 34, 2010/09/07">
+        <extension name="GL_EXT_direct_state_access" supported="gl|glcore" comment="DSA extension doesn't identify which interfaces are core profile and keeps getting expanded. This is in sync with revision 34, 2010/09/07">
             <require>
                 <enum name="GL_PROGRAM_MATRIX_EXT"/>
                 <enum name="GL_TRANSPOSE_PROGRAM_MATRIX_EXT"/>
@@ -40431,7 +43367,7 @@
                 <command name="glMultiDrawElementsBaseVertexEXT" comment="Supported only if GL_EXT_multi_draw_arrays is supported"/>
             </require>
         </extension>
-        <extension name="GL_EXT_draw_instanced" supported="gl|gles2">
+        <extension name="GL_EXT_draw_instanced" supported="gl|glcore|gles2">
             <require>
                 <command name="glDrawArraysInstancedEXT"/>
                 <command name="glDrawElementsInstancedEXT"/>
@@ -40444,6 +43380,18 @@
                 <command name="glDrawRangeElementsEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_draw_transform_feedback" supported="gles2">
+            <require>
+                <command name="glDrawTransformFeedbackEXT"/>
+                <command name="glDrawTransformFeedbackInstancedEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_external_buffer" supported="gl|gles2">
+            <require>
+                <command name="glBufferStorageExternalEXT"/>
+                <command name="glNamedBufferStorageExternalEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_float_blend" supported="gles2"/>
         <extension name="GL_EXT_fog_coord" supported="gl">
             <require>
@@ -40771,6 +43719,67 @@
                 <command name="glFlushMappedBufferRangeEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_memory_object" supported="gl|gles2">
+            <require>
+                <enum name="GL_TEXTURE_TILING_EXT"/>
+                <enum name="GL_DEDICATED_MEMORY_OBJECT_EXT"/>
+                <enum name="GL_PROTECTED_MEMORY_OBJECT_EXT"/>
+                <enum name="GL_NUM_TILING_TYPES_EXT"/>
+                <enum name="GL_TILING_TYPES_EXT"/>
+                <enum name="GL_OPTIMAL_TILING_EXT"/>
+                <enum name="GL_LINEAR_TILING_EXT"/>
+                <enum name="GL_NUM_DEVICE_UUIDS_EXT"/>
+                <enum name="GL_DEVICE_UUID_EXT"/>
+                <enum name="GL_DRIVER_UUID_EXT"/>
+                <enum name="GL_UUID_SIZE_EXT"/>
+                <command name="glGetUnsignedBytevEXT"/>
+                <command name="glGetUnsignedBytei_vEXT"/>
+                <command name="glDeleteMemoryObjectsEXT"/>
+                <command name="glIsMemoryObjectEXT"/>
+                <command name="glCreateMemoryObjectsEXT"/>
+                <command name="glMemoryObjectParameterivEXT"/>
+                <command name="glGetMemoryObjectParameterivEXT"/>
+                <command name="glTexStorageMem2DEXT"/>
+                <command name="glTexStorageMem2DMultisampleEXT"/>
+                <command name="glTexStorageMem3DEXT"/>
+                <command name="glTexStorageMem3DMultisampleEXT"/>
+                <command name="glBufferStorageMemEXT"/>
+            </require>
+            <require comment="Supported only if GL_EXT_direct_state_access is supported">
+                <command name="glTextureStorageMem2DEXT"/>
+                <command name="glTextureStorageMem2DMultisampleEXT"/>
+                <command name="glTextureStorageMem3DEXT"/>
+                <command name="glTextureStorageMem3DMultisampleEXT"/>
+                <command name="glNamedBufferStorageMemEXT"/>
+            </require>
+            <require api="gl">
+                <command name="glTexStorageMem1DEXT"/>
+            </require>
+            <require api="gl" comment="Supported only if GL_EXT_direct_state_access is supported">
+                <command name="glTextureStorageMem1DEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_memory_object_fd" supported="gl|gles2">
+            <require>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_FD_EXT"/>
+                <command name="glImportMemoryFdEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_memory_object_win32" supported="gl|gles2">
+            <require>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_EXT"/>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT"/>
+                <enum name="GL_DEVICE_LUID_EXT"/>
+                <enum name="GL_DEVICE_NODE_MASK_EXT"/>
+                <enum name="GL_LUID_SIZE_EXT"/>
+                <enum name="GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT"/>
+                <enum name="GL_HANDLE_TYPE_D3D12_RESOURCE_EXT"/>
+                <enum name="GL_HANDLE_TYPE_D3D11_IMAGE_EXT"/>
+                <enum name="GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT"/>
+                <command name="glImportMemoryWin32HandleEXT"/>
+                <command name="glImportMemoryWin32NameEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_misc_attribute" supported="gl"/>
         <extension name="GL_EXT_multi_draw_arrays" supported="gl|gles1|gles2">
             <require>
@@ -40936,19 +43945,25 @@
                 <command name="glPolygonOffsetEXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_polygon_offset_clamp" supported="gl">
+        <extension name="GL_EXT_polygon_offset_clamp" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_POLYGON_OFFSET_CLAMP_EXT"/>
                 <command name="glPolygonOffsetClampEXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_post_depth_coverage" supported="gl|gles2"/>
+        <extension name="GL_EXT_post_depth_coverage" supported="gl|glcore|gles2"/>
         <extension name="GL_EXT_primitive_bounding_box" supported="gles2">
             <require>
                 <enum name="GL_PRIMITIVE_BOUNDING_BOX_EXT"/>
                 <command name="glPrimitiveBoundingBoxEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_protected_textures" supported="gles2">
+            <require>
+                <enum name="GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT"/>
+                <enum name="GL_TEXTURE_PROTECTED_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_provoking_vertex" supported="gl">
             <require>
                 <enum name="GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT"/>
@@ -40968,7 +43983,7 @@
                 <enum name="GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG"/>
             </require>
         </extension>
-        <extension name="GL_EXT_raster_multisample" supported="gl|gles2">
+        <extension name="GL_EXT_raster_multisample" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_RASTER_MULTISAMPLE_EXT"/>
                 <enum name="GL_RASTER_SAMPLES_EXT"/>
@@ -41019,6 +44034,51 @@
                 <command name="glGetnUniformivEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_semaphore" supported="gl|gles2">
+            <require>
+                <enum name="GL_NUM_DEVICE_UUIDS_EXT"/>
+                <enum name="GL_DEVICE_UUID_EXT"/>
+                <enum name="GL_DRIVER_UUID_EXT"/>
+                <enum name="GL_UUID_SIZE_EXT"/>
+                <enum name="GL_LAYOUT_GENERAL_EXT"/>
+                <enum name="GL_LAYOUT_COLOR_ATTACHMENT_EXT"/>
+                <enum name="GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT"/>
+                <enum name="GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT"/>
+                <enum name="GL_LAYOUT_SHADER_READ_ONLY_EXT"/>
+                <enum name="GL_LAYOUT_TRANSFER_SRC_EXT"/>
+                <enum name="GL_LAYOUT_TRANSFER_DST_EXT"/>
+                <enum name="GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT"/>
+                <enum name="GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT"/>
+                <command name="glGetUnsignedBytevEXT"/>
+                <command name="glGetUnsignedBytei_vEXT"/>
+                <command name="glGenSemaphoresEXT"/>
+                <command name="glDeleteSemaphoresEXT"/>
+                <command name="glIsSemaphoreEXT"/>
+                <command name="glSemaphoreParameterui64vEXT"/>
+                <command name="glGetSemaphoreParameterui64vEXT"/>
+                <command name="glWaitSemaphoreEXT"/>
+                <command name="glSignalSemaphoreEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_semaphore_fd" supported="gl|gles2">
+            <require>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_FD_EXT"/>
+                <command name="glImportSemaphoreFdEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_semaphore_win32" supported="gl|gles2">
+            <require>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_EXT"/>
+                <enum name="GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT"/>
+                <enum name="GL_DEVICE_LUID_EXT"/>
+                <enum name="GL_DEVICE_NODE_MASK_EXT"/>
+                <enum name="GL_LUID_SIZE_EXT"/>
+                <enum name="GL_HANDLE_TYPE_D3D12_FENCE_EXT"/>
+                <enum name="GL_D3D12_FENCE_VALUE_EXT"/>
+                <command name="glImportSemaphoreWin32HandleEXT"/>
+                <command name="glImportSemaphoreWin32NameEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_sRGB" supported="gles1|gles2">
             <require>
                 <enum name="GL_SRGB_EXT"/>
@@ -41060,7 +44120,7 @@
                 <command name="glSecondaryColorPointerEXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_separate_shader_objects" supported="gl|gles2">
+        <extension name="GL_EXT_separate_shader_objects" supported="gl|glcore|gles2">
             <require api="gl" comment="The OpenGL version of this extension is completely unrelated to the OpenGL ES version">
                 <enum name="GL_ACTIVE_PROGRAM_EXT"/>
                 <command name="glUseShaderProgramEXT"/>
@@ -41130,11 +44190,18 @@
                 <enum name="GL_SEPARATE_SPECULAR_COLOR_EXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_shader_framebuffer_fetch" supported="gles2">
+        <extension name="GL_EXT_shader_framebuffer_fetch" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_shader_framebuffer_fetch_non_coherent" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT"/>
+                <command name="glFramebufferFetchBarrierEXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_shader_group_vote" supported="gles2"/>
         <extension name="GL_EXT_shader_image_load_formatted" supported="gl"/>
         <extension name="GL_EXT_shader_image_load_store" supported="gl">
             <require>
@@ -41198,8 +44265,9 @@
             </require>
         </extension>
         <extension name="GL_EXT_shader_implicit_conversions" supported="gles2"/>
-        <extension name="GL_EXT_shader_integer_mix" supported="gl|gles2"/>
+        <extension name="GL_EXT_shader_integer_mix" supported="gl|glcore|gles2"/>
         <extension name="GL_EXT_shader_io_blocks" supported="gles2"/>
+        <extension name="GL_EXT_shader_non_constant_global_initializers" supported="gles2"/>
         <extension name="GL_EXT_shader_pixel_local_storage" supported="gles2">
             <require>
                 <enum name="GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT"/>
@@ -41207,6 +44275,16 @@
                 <enum name="GL_SHADER_PIXEL_LOCAL_STORAGE_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_shader_pixel_local_storage2" supported="gles2">
+            <require>
+                <enum name="GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT"/>
+                <enum name="GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT"/>
+                <enum name="GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT"/>
+                <command name="glFramebufferPixelLocalStorageSizeEXT"/>
+                <command name="glGetFramebufferPixelLocalStorageSizeEXT"/>
+                <command name="glClearPixelLocalStorageuiEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_shader_texture_lod" supported="gles2"/>
         <extension name="GL_EXT_shadow_funcs" supported="gl"/>
         <extension name="GL_EXT_shadow_samplers" supported="gles2">
@@ -41244,7 +44322,7 @@
                 <!-- <command name="glTexturePageCommitmentEXT"/> -->
             </require>
         </extension>
-        <extension name="GL_EXT_sparse_texture2" supported="gl"/>
+        <extension name="GL_EXT_sparse_texture2" supported="gl|gles2"/>
         <extension name="GL_EXT_stencil_clear_tag" supported="gl">
             <require>
                 <enum name="GL_STENCIL_TAG_BITS_EXT"/>
@@ -41444,6 +44522,19 @@
                 <command name="glTexBufferEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_texture_compression_astc_decode_mode" supported="gles2">
+            <require>
+                <enum name="GL_TEXTURE_ASTC_DECODE_PRECISION_EXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_texture_compression_bptc" supported="gles2">
+            <require>
+                <enum name="GL_COMPRESSED_RGBA_BPTC_UNORM_EXT"/>
+                <enum name="GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT"/>
+                <enum name="GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT"/>
+                <enum name="GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_texture_compression_dxt1" supported="gles1|gles2">
             <require>
                 <enum name="GL_COMPRESSED_RGB_S3TC_DXT1_EXT"/>
@@ -41458,7 +44549,7 @@
                 <enum name="GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_texture_compression_rgtc" supported="gl">
+        <extension name="GL_EXT_texture_compression_rgtc" supported="gl|gles2">
             <require>
                 <enum name="GL_COMPRESSED_RED_RGTC1_EXT"/>
                 <enum name="GL_COMPRESSED_SIGNED_RED_RGTC1_EXT"/>
@@ -41466,7 +44557,7 @@
                 <enum name="GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_texture_compression_s3tc" supported="gl|gles2">
+        <extension name="GL_EXT_texture_compression_s3tc" supported="gl|glcore|gles2|glsc2">
             <require>
                 <enum name="GL_COMPRESSED_RGB_S3TC_DXT1_EXT"/>
                 <enum name="GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"/>
@@ -41474,6 +44565,14 @@
                 <enum name="GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_texture_compression_s3tc_srgb" supported="gles2">
+            <require>
+                <enum name="GL_COMPRESSED_SRGB_S3TC_DXT1_EXT"/>
+                <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT"/>
+                <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT"/>
+                <enum name="GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_texture_cube_map" supported="gl" comment="Replaced by ARB_texture_cube_map, but was apparently shipped anyway?">
             <require>
                 <enum name="GL_NORMAL_MAP_EXT"/>
@@ -41541,15 +44640,10 @@
                 <enum name="GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_texture_filter_minmax" supported="gl|gles2">
+        <extension name="GL_EXT_texture_filter_minmax" supported="gl|glcore|gles2">
             <require>
-                <enum name="GL_RASTER_MULTISAMPLE_EXT"/>
-                <enum name="GL_RASTER_SAMPLES_EXT"/>
-                <enum name="GL_MAX_RASTER_SAMPLES_EXT"/>
-                <enum name="GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT"/>
-                <enum name="GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT"/>
-                <enum name="GL_EFFECTIVE_RASTER_SAMPLES_EXT"/>
-                <command name="glRasterSamplesEXT"/>
+                <enum name="GL_TEXTURE_REDUCTION_MODE_EXT"/>
+                <enum name="GL_WEIGHTED_AVERAGE_EXT"/>
             </require>
         </extension>
         <extension name="GL_EXT_texture_format_BGRA8888" supported="gles1|gles2">
@@ -41557,6 +44651,11 @@
                 <enum name="GL_BGRA_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_texture_format_sRGB_override" supported="gles2">
+            <require>
+                <enum name="GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_texture_integer" supported="gl">
             <require>
                 <enum name="GL_RGBA32UI_EXT"/>
@@ -41628,6 +44727,11 @@
                 <enum name="GL_MIRROR_CLAMP_TO_BORDER_EXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_texture_mirror_clamp_to_edge" supported="gles2">
+            <require>
+                <enum name="GL_MIRROR_CLAMP_TO_EDGE_EXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_texture_norm16" supported="gles2">
             <require>
                 <enum name="GL_R16_EXT"/>
@@ -41700,7 +44804,7 @@
                 <enum name="GL_SRG8_EXT"/>
             </require>
         </extension>
-        <extension name="GL_EXT_texture_sRGB_decode" supported="gl|gles2">
+        <extension name="GL_EXT_texture_sRGB_decode" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_TEXTURE_SRGB_DECODE_EXT"/>
                 <enum name="GL_DECODE_EXT"/>
@@ -42095,6 +45199,23 @@
                 <command name="glVertexWeightPointerEXT"/>
             </require>
         </extension>
+        <extension name="GL_EXT_win32_keyed_mutex" supported="gl|gles2">
+            <require>
+                <command name="glAcquireKeyedMutexWin32EXT"/>
+                <command name="glReleaseKeyedMutexWin32EXT"/>
+            </require>
+        </extension>
+        <extension name="GL_EXT_window_rectangles" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_INCLUSIVE_EXT"/>
+                <enum name="GL_EXCLUSIVE_EXT"/>
+                <enum name="GL_WINDOW_RECTANGLE_EXT"/>
+                <enum name="GL_WINDOW_RECTANGLE_MODE_EXT"/>
+                <enum name="GL_MAX_WINDOW_RECTANGLES_EXT"/>
+                <enum name="GL_NUM_WINDOW_RECTANGLES_EXT"/>
+                <command name="glWindowRectanglesEXT"/>
+            </require>
+        </extension>
         <extension name="GL_EXT_x11_sync_object" supported="gl">
             <require>
                 <enum name="GL_SYNC_X11_FENCE_EXT"/>
@@ -42218,6 +45339,26 @@
                 <command name="glVertexPointerListIBM"/>
             </require>
         </extension>
+        <extension name="GL_IMG_bindless_texture" supported="gles2">
+            <require>
+                <command name="glGetTextureHandleIMG"/>
+                <command name="glGetTextureSamplerHandleIMG"/>
+                <command name="glUniformHandleui64IMG"/>
+                <command name="glUniformHandleui64vIMG"/>
+                <command name="glProgramUniformHandleui64IMG"/>
+                <command name="glProgramUniformHandleui64vIMG"/>
+            </require>
+        </extension>
+        <extension name="GL_IMG_framebuffer_downsample" supported="gles2">
+            <require>
+                <enum name="GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG"/>
+                <enum name="GL_NUM_DOWNSAMPLE_SCALES_IMG"/>
+                <enum name="GL_DOWNSAMPLE_SCALES_IMG"/>
+                <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG"/>
+                <command name="glFramebufferTexture2DDownsampleIMG"/>
+                <command name="glFramebufferTextureLayerDownsampleIMG"/>
+            </require>
+        </extension>
         <extension name="GL_IMG_multisampled_render_to_texture" supported="gles1|gles2">
             <require>
                 <enum name="GL_RENDERBUFFER_SAMPLES_IMG"/>
@@ -42311,8 +45452,13 @@
                 <enum name="GL_INTERLACE_READ_INGR"/>
             </require>
         </extension>
+        <extension name="GL_INTEL_conservative_rasterization" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_CONSERVATIVE_RASTERIZATION_INTEL"/>
+            </require>
+        </extension>
         <extension name="GL_INTEL_fragment_shader_ordering" supported="gl"/>
-        <extension name="GL_INTEL_framebuffer_CMAA" supported="gl|gles2">
+        <extension name="GL_INTEL_framebuffer_CMAA" supported="gl|glcore|gles2">
             <require>
                 <command name="glApplyFramebufferAttachmentCMAAINTEL"/>
             </require>
@@ -42328,6 +45474,11 @@
                 <command name="glMapTexture2DINTEL"/>
             </require>
         </extension>
+        <extension name="GL_INTEL_blackhole_render" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_BLACKHOLE_RENDER_INTEL"/>
+            </require>
+        </extension>
         <extension name="GL_INTEL_parallel_arrays" supported="gl">
             <require>
                 <enum name="GL_PARALLEL_ARRAYS_INTEL"/>
@@ -42341,7 +45492,7 @@
                 <command name="glTexCoordPointervINTEL"/>
             </require>
         </extension>
-        <extension name="GL_INTEL_performance_query" supported="gl|gles2">
+        <extension name="GL_INTEL_performance_query" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_PERFQUERY_SINGLE_CONTEXT_INTEL"/>
                 <enum name="GL_PERFQUERY_GLOBAL_CONTEXT_INTEL"/>
@@ -42375,7 +45526,7 @@
                 <command name="glGetPerfQueryInfoINTEL"/>
             </require>
         </extension>
-        <extension name="GL_KHR_blend_equation_advanced" supported="gl|gles2">
+        <extension name="GL_KHR_blend_equation_advanced" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_MULTIPLY_KHR"/>
                 <enum name="GL_SCREEN_KHR"/>
@@ -42395,7 +45546,7 @@
                 <command name="glBlendBarrierKHR"/>
             </require>
         </extension>
-        <extension name="GL_KHR_blend_equation_advanced_coherent" supported="gl|gles2">
+        <extension name="GL_KHR_blend_equation_advanced_coherent" supported="gl|glcore|gles2">
             <require comment="Otherwise identical to GL_KHR_blend_equation_advanced, just different semantic behavior">
                 <enum name="GL_BLEND_ADVANCED_COHERENT_KHR"/>
             </require>
@@ -42412,7 +45563,7 @@
                 <enum name="GL_NONE"/>
             </require>
         </extension>
-        <extension name="GL_KHR_debug" supported="gl|glcore|gles2">
+        <extension name="GL_KHR_debug" supported="gl|glcore|gles1|gles2">
             <require api="gl" comment="KHR extensions *mandate* suffixes for ES, unlike for GL">
                 <enum name="GL_DEBUG_OUTPUT_SYNCHRONOUS"/>
                 <enum name="GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH"/>
@@ -42628,6 +45779,13 @@
             </require>
         </extension>
         <extension name="GL_KHR_texture_compression_astc_sliced_3d" supported="gl|glcore|gles2"/>
+        <extension name="GL_KHR_parallel_shader_compile" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_MAX_SHADER_COMPILER_THREADS_KHR"/>
+                <enum name="GL_COMPLETION_STATUS_KHR"/>
+                <command name="glMaxShaderCompilerThreadsKHR"/>
+            </require>
+        </extension>
         <extension name="GL_MESAX_texture_stack" supported="gl">
             <require>
                 <enum name="GL_TEXTURE_1D_STACK_MESAX"/>
@@ -42643,11 +45801,24 @@
                 <enum name="GL_PACK_INVERT_MESA"/>
             </require>
         </extension>
+        <extension name="GL_MESA_program_binary_formats" supported="gl|gles2">
+            <require>
+                <enum name="GL_PROGRAM_BINARY_FORMAT_MESA"/>
+            </require>
+        </extension>
         <extension name="GL_MESA_resize_buffers" supported="gl">
             <require>
                 <command name="glResizeBuffersMESA"/>
             </require>
         </extension>
+        <extension name="GL_MESA_shader_integer_functions" supported="gl|gles2"/>
+        <extension name="GL_MESA_tile_raster_order" supported="gl">
+            <require>
+                <enum name="GL_TILE_RASTER_ORDER_FIXED_MESA"/>
+                <enum name="GL_TILE_RASTER_ORDER_INCREASING_X_MESA"/>
+                <enum name="GL_TILE_RASTER_ORDER_INCREASING_Y_MESA"/>
+            </require>
+        </extension>
         <extension name="GL_MESA_window_pos" supported="gl">
             <require>
                 <command name="glWindowPos2dMESA"/>
@@ -42683,6 +45854,12 @@
                 <enum name="GL_YCBCR_MESA"/>
             </require>
         </extension>
+        <extension name="GL_NVX_blend_equation_advanced_multi_draw_buffers" supported="gl|gles2"/>
+        <extension name="GL_NVX_cross_process_interop" supported="disabled">
+            <require comment="unpublished experimental extension">
+                <enum name="GL_EXTERNAL_STORAGE_BIT_NVX"/>
+            </require>
+        </extension>
         <extension name="GL_NVX_conditional_render" supported="gl">
             <require>
                 <command name="glBeginConditionalRenderNVX"/>
@@ -42698,19 +45875,37 @@
                 <enum name="GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX"/>
             </require>
         </extension>
-        <extension name="GL_NV_bindless_multi_draw_indirect" supported="gl">
+        <extension name="GL_NVX_linked_gpu_multicast" supported="gl">
+            <require>
+                <enum name="GL_LGPU_SEPARATE_STORAGE_BIT_NVX"/>
+                <enum name="GL_MAX_LGPU_GPUS_NVX"/>
+                <command name="glLGPUNamedBufferSubDataNVX"/>
+                <command name="glLGPUCopyImageSubDataNVX"/>
+                <command name="glLGPUInterlockNVX"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_alpha_to_coverage_dither_control" supported="gl">
+            <require>
+                <enum name="GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV"/>
+                <enum name="GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV"/>
+                <enum name="GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV"/>
+                <enum name="GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV"/>
+                <command name="glAlphaToCoverageDitherControlNV"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_bindless_multi_draw_indirect" supported="gl|glcore">
             <require>
                 <command name="glMultiDrawArraysIndirectBindlessNV"/>
                 <command name="glMultiDrawElementsIndirectBindlessNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_bindless_multi_draw_indirect_count" supported="gl">
+        <extension name="GL_NV_bindless_multi_draw_indirect_count" supported="gl|glcore">
             <require>
                 <command name="glMultiDrawArraysIndirectBindlessCountNV"/>
                 <command name="glMultiDrawElementsIndirectBindlessCountNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_bindless_texture" supported="gl|gles2">
+        <extension name="GL_NV_bindless_texture" supported="gl|glcore|gles2">
             <require>
                 <command name="glGetTextureHandleNV"/>
                 <command name="glGetTextureSamplerHandleNV"/>
@@ -42727,7 +45922,7 @@
                 <command name="glIsImageHandleResidentNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_blend_equation_advanced" supported="gl|gles2">
+        <extension name="GL_NV_blend_equation_advanced" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_BLEND_OVERLAP_NV"/>
                 <enum name="GL_BLEND_PREMULTIPLIED_SRC_NV"/>
@@ -42784,13 +45979,27 @@
                 <command name="glBlendBarrierNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_blend_equation_advanced_coherent" supported="gl|gles2">
+        <extension name="GL_NV_blend_equation_advanced_coherent" supported="gl|glcore|gles2">
             <require comment="Otherwise identical to GL_NV_blend_equation_advanced, just different semantic behavior">
                 <enum name="GL_BLEND_ADVANCED_COHERENT_NV"/>
             </require>
         </extension>
+        <extension name="GL_NV_blend_minmax_factor" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_FACTOR_MIN_AMD"/>
+                <enum name="GL_FACTOR_MAX_AMD"/>
+            </require>
+        </extension>
         <extension name="GL_NV_blend_square" supported="gl"/>
-        <extension name="GL_NV_command_list" supported="gl">
+        <extension name="GL_NV_clip_space_w_scaling" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_VIEWPORT_POSITION_W_SCALE_NV"/>
+                <enum name="GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV"/>
+                <enum name="GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV"/>
+                <command name="glViewportPositionWScaleNV"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_command_list" supported="gl|glcore">
             <require>
                 <enum name="GL_TERMINATE_SEQUENCE_COMMAND_NV"/>
                 <enum name="GL_NOP_COMMAND_NV"/>
@@ -42836,7 +46045,7 @@
                 <enum name="GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV"/>
             </require>
         </extension>
-        <extension name="GL_NV_conditional_render" supported="gl|gles2">
+        <extension name="GL_NV_conditional_render" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_QUERY_WAIT_NV"/>
                 <enum name="GL_QUERY_NO_WAIT_NV"/>
@@ -42846,7 +46055,7 @@
                 <command name="glEndConditionalRenderNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_conservative_raster" supported="gl|gles2">
+        <extension name="GL_NV_conservative_raster" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_CONSERVATIVE_RASTERIZATION_NV"/>
                 <enum name="GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV"/>
@@ -42855,7 +46064,7 @@
                 <command name="glSubpixelPrecisionBiasNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_conservative_raster_dilate" supported="gl">
+        <extension name="GL_NV_conservative_raster_dilate" supported="gl|glcore">
             <require>
                 <enum name="GL_CONSERVATIVE_RASTER_DILATE_NV"/>
                 <enum name="GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV"/>
@@ -42863,6 +46072,21 @@
                 <command name="glConservativeRasterParameterfNV"/>
             </require>
         </extension>
+        <extension name="GL_NV_conservative_raster_pre_snap" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_conservative_raster_pre_snap_triangles" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_CONSERVATIVE_RASTER_MODE_NV"/>
+                <enum name="GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV"/>
+                <enum name="GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV"/>
+                <enum name="GL_CONSERVATIVE_RASTER_MODE_NV"/>
+                <command name="glConservativeRasterParameteriNV"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_conservative_raster_underestimation" supported="gl|glcore"/>
         <extension name="GL_NV_copy_buffer" supported="gles2">
             <require>
                 <enum name="GL_COPY_READ_BUFFER_NV"/>
@@ -42972,6 +46196,15 @@
                 <command name="glDrawTextureNV"/>
             </require>
         </extension>
+        <extension name="GL_NV_draw_vulkan_image" supported="gl|glcore|gles2">
+            <require>
+                <command name="glDrawVkImageNV"/>
+                <command name="glGetVkProcAddrNV"/>
+                <command name="glWaitVkSemaphoreNV"/>
+                <command name="glSignalVkSemaphoreNV"/>
+                <command name="glSignalVkFenceNV"/>
+            </require>
+        </extension>
         <extension name="GL_NV_evaluators" supported="gl">
             <require>
                 <enum name="GL_EVAL_2D_NV"/>
@@ -43062,7 +46295,7 @@
                 <command name="glSetFenceNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_fill_rectangle" supported="gl|gles2">
+        <extension name="GL_NV_fill_rectangle" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_FILL_RECTANGLE_NV"/>
             </require>
@@ -43094,7 +46327,7 @@
                 <enum name="GL_EYE_PLANE"/>
             </require>
         </extension>
-        <extension name="GL_NV_fragment_coverage_to_color" supported="gl|gles2">
+        <extension name="GL_NV_fragment_coverage_to_color" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_FRAGMENT_COVERAGE_TO_COLOR_NV"/>
                 <enum name="GL_FRAGMENT_COVERAGE_COLOR_NV"/>
@@ -43130,7 +46363,7 @@
         </extension>
         <extension name="GL_NV_fragment_program4" supported="gl"/>
         <extension name="GL_NV_fragment_program_option" supported="gl"/>
-        <extension name="GL_NV_fragment_shader_interlock" supported="gl|gles2"/>
+        <extension name="GL_NV_fragment_shader_interlock" supported="gl|glcore|gles2"/>
         <extension name="GL_NV_framebuffer_blit" supported="gles2">
             <require>
                 <enum name="GL_READ_FRAMEBUFFER_NV"/>
@@ -43140,7 +46373,7 @@
                 <command name="glBlitFramebufferNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_framebuffer_mixed_samples" supported="gl|gles2">
+        <extension name="GL_NV_framebuffer_mixed_samples" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_RASTER_MULTISAMPLE_EXT"/>
                 <enum name="GL_COVERAGE_MODULATION_TABLE_NV"/>
@@ -43170,7 +46403,7 @@
                 <command name="glRenderbufferStorageMultisampleNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_framebuffer_multisample_coverage" supported="gl">
+        <extension name="GL_NV_framebuffer_multisample_coverage" supported="gl|glcore">
             <require>
                 <enum name="GL_RENDERBUFFER_COVERAGE_SAMPLES_NV"/>
                 <enum name="GL_RENDERBUFFER_COLOR_SAMPLES_NV"/>
@@ -43205,7 +46438,7 @@
             </require>
         </extension>
         <extension name="GL_NV_geometry_shader4" supported="gl"/>
-        <extension name="GL_NV_geometry_shader_passthrough" supported="gl|gles2"/>
+        <extension name="GL_NV_geometry_shader_passthrough" supported="gl|glcore|gles2"/>
         <extension name="GL_NV_gpu_program4" supported="gl">
             <require>
                 <enum name="GL_MIN_PROGRAM_TEXEL_OFFSET_NV"/>
@@ -43249,7 +46482,7 @@
             </require>
         </extension>
         <extension name="GL_NV_gpu_program5_mem_extended" supported="gl"/>
-        <extension name="GL_NV_gpu_shader5" supported="gl">
+        <extension name="GL_NV_gpu_shader5" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_INT64_NV"/>
                 <enum name="GL_UNSIGNED_INT64_NV"/>
@@ -43375,7 +46608,7 @@
                 <command name="glVertexAttribDivisorNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_internalformat_sample_query" supported="gl|gles2">
+        <extension name="GL_NV_internalformat_sample_query" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_RENDERBUFFER"/>
                 <enum name="GL_TEXTURE_2D_MULTISAMPLE"/>
@@ -43393,6 +46626,27 @@
                 <enum name="GL_MAX_SPOT_EXPONENT_NV"/>
             </require>
         </extension>
+        <extension name="GL_NV_gpu_multicast" supported="gl">
+            <require>
+                <enum name="GL_PER_GPU_STORAGE_BIT_NV"/>
+                <enum name="GL_MULTICAST_GPUS_NV"/>
+                <enum name="GL_RENDER_GPU_MASK_NV"/>
+                <enum name="GL_PER_GPU_STORAGE_NV"/>
+                <enum name="GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV"/>
+                <command name="glRenderGpuMaskNV"/>
+                <command name="glMulticastBufferSubDataNV"/>
+                <command name="glMulticastCopyBufferSubDataNV"/>
+                <command name="glMulticastCopyImageSubDataNV"/>
+                <command name="glMulticastBlitFramebufferNV"/>
+                <command name="glMulticastFramebufferSampleLocationsfvNV"/>
+                <command name="glMulticastBarrierNV"/>
+                <command name="glMulticastWaitSyncNV"/>
+                <command name="glMulticastGetQueryObjectivNV"/>
+                <command name="glMulticastGetQueryObjectuivNV"/>
+                <command name="glMulticastGetQueryObjecti64vNV"/>
+                <command name="glMulticastGetQueryObjectui64vNV"/>
+            </require>
+        </extension>
         <extension name="GL_NV_multisample_coverage" supported="gl">
             <require>
                 <enum name="GL_SAMPLES_ARB"/>
@@ -43454,7 +46708,7 @@
             </require>
         </extension>
         <extension name="GL_NV_parameter_buffer_object2" supported="gl"/>
-        <extension name="GL_NV_path_rendering" supported="gl|gles2">
+        <extension name="GL_NV_path_rendering" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_PATH_FORMAT_SVG_NV"/>
                 <enum name="GL_PATH_FORMAT_PS_NV"/>
@@ -43692,9 +46946,28 @@
                 <enum name="GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV"/>
                 <enum name="GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV"/>
                 <enum name="GL_FRAGMENT_INPUT_NV"/>
+                <command name="glMatrixFrustumEXT"/>
+                <command name="glMatrixLoadIdentityEXT"/>
+                <command name="glMatrixLoadTransposefEXT"/>
+                <command name="glMatrixLoadTransposedEXT"/>
+                <command name="glMatrixLoadfEXT"/>
+                <command name="glMatrixLoaddEXT"/>
+                <command name="glMatrixMultTransposefEXT"/>
+                <command name="glMatrixMultTransposedEXT"/>
+                <command name="glMatrixMultfEXT"/>
+                <command name="glMatrixMultdEXT"/>
+                <command name="glMatrixOrthoEXT"/>
+                <command name="glMatrixPopEXT"/>
+                <command name="glMatrixPushEXT"/>
+                <command name="glMatrixRotatefEXT"/>
+                <command name="glMatrixRotatedEXT"/>
+                <command name="glMatrixScalefEXT"/>
+                <command name="glMatrixScaledEXT"/>
+                <command name="glMatrixTranslatefEXT"/>
+                <command name="glMatrixTranslatedEXT"/>
             </require>
         </extension>
-        <extension name="GL_NV_path_rendering_shared_edge" supported="gl|gles2">
+        <extension name="GL_NV_path_rendering_shared_edge" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_SHARED_EDGE_NV"/>
             </require>
@@ -43711,6 +46984,14 @@
                 <command name="glFlushPixelDataRangeNV"/>
             </require>
         </extension>
+        <extension name="GL_NV_pixel_buffer_object" supported="gles2">
+            <require>
+                <enum name="GL_PIXEL_PACK_BUFFER_NV"/>
+                <enum name="GL_PIXEL_UNPACK_BUFFER_NV"/>
+                <enum name="GL_PIXEL_PACK_BUFFER_BINDING_NV"/>
+                <enum name="GL_PIXEL_UNPACK_BUFFER_BINDING_NV"/>
+            </require>
+        </extension>
         <extension name="GL_NV_point_sprite" supported="gl">
             <require>
                 <enum name="GL_POINT_SPRITE_NV"/>
@@ -43755,6 +47036,24 @@
                 <command name="glPrimitiveRestartIndexNV"/>
             </require>
         </extension>
+        <extension name="GL_NV_query_resource" supported="gl">
+            <require>
+                <enum name="GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV"/>
+                <enum name="GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV"/>
+                <enum name="GL_QUERY_RESOURCE_SYS_RESERVED_NV"/>
+                <enum name="GL_QUERY_RESOURCE_TEXTURE_NV"/>
+                <enum name="GL_QUERY_RESOURCE_RENDERBUFFER_NV"/>
+                <enum name="GL_QUERY_RESOURCE_BUFFEROBJECT_NV"/>
+                <command name="glQueryResourceNV"/>
+            </require>
+        </extension>
+        <extension name="GL_NV_query_resource_tag" supported="gl">
+            <require>
+                <command name="glGenQueryResourceTagNV"/>
+                <command name="glDeleteQueryResourceTagNV"/>
+                <command name="glQueryResourceTagNV"/>
+            </require>
+        </extension>
         <extension name="GL_NV_read_buffer" supported="gles2">
             <require>
                 <enum name="GL_READ_BUFFER_NV"/>
@@ -43845,6 +47144,11 @@
                 <command name="glGetCombinerStageParameterfvNV"/>
             </require>
         </extension>
+        <extension name="GL_NV_robustness_video_memory_purge" supported="gl">
+            <require>
+                <enum name="GL_PURGED_CONTEXT_RESET_NV"/>
+            </require>
+        </extension>
         <extension name="GL_NV_sRGB_formats" supported="gles2">
             <require>
                 <enum name="GL_SLUMINANCE_NV"/>
@@ -43859,7 +47163,7 @@
                 <enum name="GL_ETC1_SRGB8_NV"/>
             </require>
         </extension>
-        <extension name="GL_NV_sample_locations" supported="gl|gles2">
+        <extension name="GL_NV_sample_locations" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV"/>
                 <enum name="GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV"/>
@@ -43874,12 +47178,13 @@
                 <command name="glResolveDepthValuesNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_sample_mask_override_coverage" supported="gl|gles2"/>
-        <extension name="GL_NV_shader_atomic_counters" supported="gl"/>
-        <extension name="GL_NV_shader_atomic_float" supported="gl"/>
-        <extension name="GL_NV_shader_atomic_fp16_vector" supported="gl"/>
-        <extension name="GL_NV_shader_atomic_int64" supported="gl"/>
-        <extension name="GL_NV_shader_buffer_load" supported="gl">
+        <extension name="GL_NV_sample_mask_override_coverage" supported="gl|glcore|gles2"/>
+        <extension name="GL_NV_shader_atomic_counters" supported="gl|glcore"/>
+        <extension name="GL_NV_shader_atomic_float" supported="gl|glcore"/>
+        <extension name="GL_NV_shader_atomic_float64" supported="gl|glcore"/>
+        <extension name="GL_NV_shader_atomic_fp16_vector" supported="gl|glcore|gles2"/>
+        <extension name="GL_NV_shader_atomic_int64" supported="gl|glcore"/>
+        <extension name="GL_NV_shader_buffer_load" supported="gl|glcore">
             <require>
                 <enum name="GL_BUFFER_GPU_ADDRESS_NV"/>
                 <enum name="GL_GPU_ADDRESS_NV"/>
@@ -43900,7 +47205,7 @@
                 <command name="glProgramUniformui64vNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_shader_buffer_store" supported="gl">
+        <extension name="GL_NV_shader_buffer_store" supported="gl|glcore">
             <require>
                 <enum name="GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV"/>
                 <enum name="GL_READ_WRITE"/>
@@ -43909,14 +47214,14 @@
         </extension>
         <extension name="GL_NV_shader_noperspective_interpolation" supported="gles2"/>
         <extension name="GL_NV_shader_storage_buffer_object" supported="gl"/>
-        <extension name="GL_NV_shader_thread_group" supported="gl">
+        <extension name="GL_NV_shader_thread_group" supported="gl|glcore">
             <require>
                 <enum name="GL_WARP_SIZE_NV"/>
                 <enum name="GL_WARPS_PER_SM_NV"/>
                 <enum name="GL_SM_COUNT_NV"/>
             </require>
         </extension>
-        <extension name="GL_NV_shader_thread_shuffle" supported="gl"/>
+        <extension name="GL_NV_shader_thread_shuffle" supported="gl|glcore"/>
         <extension name="GL_NV_shadow_samplers_array" supported="gles2">
             <require>
                 <enum name="GL_SAMPLER_2D_ARRAY_SHADOW_NV"/>
@@ -43927,6 +47232,7 @@
                 <enum name="GL_SAMPLER_CUBE_SHADOW_NV"/>
             </require>
         </extension>
+        <extension name="GL_NV_stereo_view_rendering" supported="gl|glcore|gles2"/>
         <extension name="GL_NV_tessellation_program5" supported="gl">
             <require>
                 <enum name="GL_MAX_PROGRAM_PATCH_ATTRIBS_NV"/>
@@ -43949,7 +47255,7 @@
                 <enum name="GL_REFLECTION_MAP_NV"/>
             </require>
         </extension>
-        <extension name="GL_NV_texture_barrier" supported="gl">
+        <extension name="GL_NV_texture_barrier" supported="gl|glcore">
             <require>
                 <command name="glTextureBarrierNV"/>
             </require>
@@ -43999,6 +47305,7 @@
                 <enum name="GL_MAX_RECTANGLE_TEXTURE_SIZE_NV"/>
             </require>
         </extension>
+        <extension name="GL_NV_texture_rectangle_compressed" supported="gl|glcore"/>
         <extension name="GL_NV_texture_shader" supported="gl">
             <require>
                 <enum name="GL_OFFSET_TEXTURE_RECTANGLE_NV"/>
@@ -44166,7 +47473,7 @@
                 <command name="glDrawTransformFeedbackNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_uniform_buffer_unified_memory" supported="gl">
+        <extension name="GL_NV_uniform_buffer_unified_memory" supported="gl|glcore">
             <require>
                 <enum name="GL_UNIFORM_BUFFER_UNIFIED_NV"/>
                 <enum name="GL_UNIFORM_BUFFER_ADDRESS_NV"/>
@@ -44207,7 +47514,7 @@
                 <enum name="GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV"/>
             </require>
         </extension>
-        <extension name="GL_NV_vertex_attrib_integer_64bit" supported="gl">
+        <extension name="GL_NV_vertex_attrib_integer_64bit" supported="gl|glcore">
             <require>
                 <enum name="GL_INT64_NV"/>
                 <enum name="GL_UNSIGNED_INT64_NV"/>
@@ -44232,7 +47539,7 @@
                 <command name="glVertexAttribLFormatNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_vertex_buffer_unified_memory" supported="gl">
+        <extension name="GL_NV_vertex_buffer_unified_memory" supported="gl|glcore">
             <require>
                 <enum name="GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV"/>
                 <enum name="GL_ELEMENT_ARRAY_UNIFIED_NV"/>
@@ -44534,7 +47841,24 @@
                 <command name="glIsEnablediNV"/>
             </require>
         </extension>
-        <extension name="GL_NV_viewport_array2" supported="gl|gles2"/>
+        <extension name="GL_NV_viewport_array2" supported="gl|glcore|gles2"/>
+        <extension name="GL_NV_viewport_swizzle" supported="gl|glcore|gles2">
+            <require>
+                <enum name="GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_X_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_Y_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_Z_NV"/>
+                <enum name="GL_VIEWPORT_SWIZZLE_W_NV"/>
+                <command name="glViewportSwizzleNV"/>
+            </require>
+        </extension>
         <extension name="GL_OES_EGL_image" supported="gles1|gles2">
             <require>
                 <type name="GLeglImageOES"/>
@@ -44634,12 +47958,12 @@
                 <command name="glCopyImageSubDataOES"/>
             </require>
         </extension>
-        <extension name="GL_OES_depth24" supported="gles1|gles2">
+        <extension name="GL_OES_depth24" supported="gles1|gles2|glsc2">
             <require>
                 <enum name="GL_DEPTH_COMPONENT24_OES"/>
             </require>
         </extension>
-        <extension name="GL_OES_depth32" supported="gles1|gles2">
+        <extension name="GL_OES_depth32" supported="gles1|gles2|glsc2">
             <require>
                 <enum name="GL_DEPTH_COMPONENT32_OES"/>
             </require>
@@ -44696,7 +48020,7 @@
                 <command name="glDrawElementsBaseVertexOES"/>
                 <command name="glDrawRangeElementsBaseVertexOES" comment="Supported only if OpenGL ES 3.0 is supported"/>
                 <command name="glDrawElementsInstancedBaseVertexOES" comment="Supported only if OpenGL ES 3.0 is supported"/>
-                <command name="glMultiDrawElementsBaseVertexOES" comment="Supported only if GL_EXT_multi_draw_arrays is supported"/>
+                <command name="glMultiDrawElementsBaseVertexEXT" comment="Supported only if GL_EXT_multi_draw_arrays is supported"/>
             </require>
         </extension>
         <extension name="GL_OES_draw_texture" supported="gles1">
@@ -45041,7 +48365,7 @@
                 <enum name="GL_RGB10_A2_EXT"/>
             </require>
         </extension>
-        <extension name="GL_OES_rgb8_rgba8" supported="gles1|gles2">
+        <extension name="GL_OES_rgb8_rgba8" supported="gles1|gles2|glsc2">
             <require>
                 <enum name="GL_RGB8_OES"/>
                 <enum name="GL_RGBA8_OES"/>
@@ -45074,7 +48398,7 @@
                 <command name="glOrthofOES"/>
             </require>
         </extension>
-        <extension name="GL_OES_standard_derivatives" supported="gles2">
+        <extension name="GL_OES_standard_derivatives" supported="gles2|glsc2">
             <require>
                 <enum name="GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES"/>
             </require>
@@ -45100,7 +48424,7 @@
                 <enum name="GL_DECR_WRAP_OES"/>
             </require>
         </extension>
-        <extension name="GL_OES_surfaceless_context" supported="gles2">
+        <extension name="GL_OES_surfaceless_context" supported="gles1|gles2">
             <require>
                 <enum name="GL_FRAMEBUFFER_UNDEFINED_OES"/>
             </require>
@@ -45317,7 +48641,7 @@
                 <enum name="GL_MIRRORED_REPEAT_OES"/>
             </require>
         </extension>
-        <extension name="GL_OES_texture_npot" supported="gles2"/>
+        <extension name="GL_OES_texture_npot" supported="gles1|gles2"/>
         <extension name="GL_OES_texture_stencil8" supported="gles2">
             <require>
                 <enum name="GL_STENCIL_INDEX_OES"/>
@@ -45364,6 +48688,30 @@
                 <enum name="GL_INT_10_10_10_2_OES"/>
             </require>
         </extension>
+        <extension name="GL_OES_viewport_array" supported="gles2">
+            <require>
+                <enum name="GL_SCISSOR_BOX"/>
+                <enum name="GL_VIEWPORT"/>
+                <enum name="GL_DEPTH_RANGE"/>
+                <enum name="GL_SCISSOR_TEST"/>
+                <enum name="GL_MAX_VIEWPORTS_OES"/>
+                <enum name="GL_VIEWPORT_SUBPIXEL_BITS_OES"/>
+                <enum name="GL_VIEWPORT_BOUNDS_RANGE_OES"/>
+                <enum name="GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES"/>
+                <command name="glViewportArrayvOES"/>
+                <command name="glViewportIndexedfOES"/>
+                <command name="glViewportIndexedfvOES"/>
+                <command name="glScissorArrayvOES"/>
+                <command name="glScissorIndexedOES"/>
+                <command name="glScissorIndexedvOES"/>
+                <command name="glDepthRangeArrayfvOES"/>
+                <command name="glDepthRangeIndexedfOES"/>
+                <command name="glGetFloati_vOES"/>
+                <command name="glEnableiOES"/>
+                <command name="glDisableiOES"/>
+                <command name="glIsEnablediOES"/>
+            </require>
+        </extension>
         <extension name="GL_OML_interlace" supported="gl">
             <require>
                 <enum name="GL_INTERLACE_OML"/>
@@ -45386,15 +48734,16 @@
                 <enum name="GL_FORMAT_SUBSAMPLE_244_244_OML"/>
             </require>
         </extension>
-        <extension name="GL_OVR_multiview" supported="gl|gles2">
+        <extension name="GL_OVR_multiview" supported="gl|glcore|gles2">
             <require>
                 <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR"/>
                 <enum name="GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR"/>
                 <enum name="GL_MAX_VIEWS_OVR"/>
+                <enum name="GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR"/>
                 <command name="glFramebufferTextureMultiviewOVR"/>
             </require>
         </extension>
-        <extension name="GL_OVR_multiview2" supported="gl|gles2"/>
+        <extension name="GL_OVR_multiview2" supported="gl|glcore|gles2"/>
         <extension name="GL_OVR_multiview_multisampled_render_to_texture" supported="gles2">
             <require>
                 <command name="glFramebufferTextureMultisampleMultiviewOVR"/>
@@ -45506,11 +48855,37 @@
                 <command name="glExtGetProgramBinarySourceQCOM"/>
             </require>
         </extension>
+        <extension name="GL_QCOM_framebuffer_foveated" supported="gles2">
+            <require>
+                <enum name="GL_FOVEATION_ENABLE_BIT_QCOM"/>
+                <enum name="GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM"/>
+                <command name="glFramebufferFoveationConfigQCOM"/>
+                <command name="glFramebufferFoveationParametersQCOM"/>
+            </require>
+        </extension>
+        <extension name="GL_QCOM_texture_foveated" supported="gles2">
+            <require>
+                <enum name="GL_FOVEATION_ENABLE_BIT_QCOM"/>
+                <enum name="GL_FOVEATION_SCALED_BIN_METHOD_BIT_QCOM"/>
+                <enum name="GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM"/>
+                <enum name="GL_TEXTURE_FOVEATED_MIN_PIXEL_DENSITY_QCOM"/>
+                <enum name="GL_TEXTURE_FOVEATED_FEATURE_QUERY_QCOM"/>
+                <enum name="GL_TEXTURE_FOVEATED_NUM_FOCAL_POINTS_QUERY_QCOM"/>
+                <enum name="GL_FRAMEBUFFER_INCOMPLETE_FOVEATION_QCOM"/>
+                <command name="glTextureFoveationParametersQCOM"/>
+            </require>
+        </extension>
         <extension name="GL_QCOM_perfmon_global_mode" supported="gles1|gles2">
             <require>
                 <enum name="GL_PERFMON_GLOBAL_MODE_QCOM"/>
             </require>
         </extension>
+        <extension name="GL_QCOM_shader_framebuffer_fetch_noncoherent" supported="gles2">
+            <require>
+                <enum name="GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM"/>
+                <command name="glFramebufferFetchBarrierQCOM"/>
+            </require>
+        </extension>
         <extension name="GL_QCOM_tiled_rendering" supported="gles1|gles2">
             <require>
                 <enum name="GL_COLOR_BUFFER_BIT0_QCOM"/>
diff --git a/services/Android.bp b/services/Android.bp
deleted file mode 100644
index 7a8ee5d..0000000
--- a/services/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = [ "*" ]
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 22b084a..12ad47e 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -3,7 +3,6 @@
 
     srcs: [
         "IAudioManager.cpp",
-        "IPlayer.cpp",
     ],
 
     shared_libs: [
diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp
deleted file mode 100644
index e8a9c34..0000000
--- a/services/audiomanager/IPlayer.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "IPlayer"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <audiomanager/IPlayer.h>
-
-namespace android {
-
-enum {
-    START      = IBinder::FIRST_CALL_TRANSACTION,
-    PAUSE      = IBinder::FIRST_CALL_TRANSACTION + 1,
-    STOP       = IBinder::FIRST_CALL_TRANSACTION + 2,
-    SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
-    SET_PAN    = IBinder::FIRST_CALL_TRANSACTION + 4,
-    SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5,
-    APPLY_VOLUME_SHAPER = IBinder::FIRST_CALL_TRANSACTION + 6,
-};
-
-class BpPlayer : public BpInterface<IPlayer>
-{
-public:
-    explicit BpPlayer(const sp<IBinder>& impl)
-        : BpInterface<IPlayer>(impl)
-    {
-    }
-
-    virtual void start()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(START, data, &reply);
-    }
-
-    virtual void pause()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(PAUSE, data, &reply);
-    }
-
-    virtual void stop()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(STOP, data, &reply);
-    }
-
-    virtual void setVolume(float vol)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeFloat(vol);
-        remote()->transact(SET_VOLUME, data, &reply);
-    }
-
-    virtual void setPan(float pan)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeFloat(pan);
-        remote()->transact(SET_PAN, data, &reply);
-    }
-
-    virtual void setStartDelayMs(int32_t delayMs) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeInt32(delayMs);
-        remote()->transact(SET_START_DELAY_MS, data, &reply);
-    }
-
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-
-        status_t status = configuration.get() == nullptr
-                ? data.writeInt32(0)
-                :  data.writeInt32(1)
-                    ?: configuration->writeToParcel(&data);
-        if (status != NO_ERROR) {
-            ALOGW("applyVolumeShaper failed configuration parceling: %d", status);
-            return; // ignore error
-        }
-
-        status = operation.get() == nullptr
-                ? status = data.writeInt32(0)
-                : data.writeInt32(1)
-                    ?: operation->writeToParcel(&data);
-        if (status != NO_ERROR) {
-            ALOGW("applyVolumeShaper failed operation parceling: %d", status);
-            return; // ignore error
-        }
-
-        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply);
-
-        ALOGW_IF(status != NO_ERROR, "applyVolumeShaper failed transact: %d", status);
-        return; // one way transaction, ignore error
-    }
-};
-
-IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
-
-// ----------------------------------------------------------------------
-
-status_t BnPlayer::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case START: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            start();
-            return NO_ERROR;
-        } break;
-        case PAUSE: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            pause();
-            return NO_ERROR;
-        }
-        case STOP: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            stop();
-            return NO_ERROR;
-        } break;
-        case SET_VOLUME: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setVolume(data.readFloat());
-            return NO_ERROR;
-        } break;
-        case SET_PAN: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setPan(data.readFloat());
-            return NO_ERROR;
-        } break;
-        case SET_START_DELAY_MS: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setStartDelayMs(data.readInt32());
-            return NO_ERROR;
-        } break;
-        case APPLY_VOLUME_SHAPER: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            sp<VolumeShaper::Configuration> configuration;
-            sp<VolumeShaper::Operation> operation;
-
-            int32_t present;
-            status_t status = data.readInt32(&present);
-            if (status == NO_ERROR && present != 0) {
-                configuration = new VolumeShaper::Configuration();
-                status = configuration->readFromParcel(data);
-            }
-            status = status ?: data.readInt32(&present);
-            if (status == NO_ERROR && present != 0) {
-                operation = new VolumeShaper::Operation();
-                status = operation->readFromParcel(data);
-            }
-            if (status == NO_ERROR) {
-                // one way transaction, no error returned
-                applyVolumeShaper(configuration, operation);
-            }
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} // namespace android
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
index 4c7265b..186f399 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -5,29 +5,3 @@
     header_libs: ["libbinder_headers"],
     export_header_lib_headers: ["libbinder_headers"],
 }
-
-cc_library {
-    name: "libbatteryservice",
-
-    srcs: [
-        "BatteryProperties.cpp",
-        "BatteryProperty.cpp",
-        "IBatteryPropertiesListener.cpp",
-        "IBatteryPropertiesRegistrar.cpp",
-    ],
-
-    header_libs: ["libbatteryservice_headers"],
-    export_header_lib_headers: ["libbatteryservice_headers"],
-
-    shared_libs: [
-        "libutils",
-        "libbinder",
-    ],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wunused",
-        "-Wunreachable-code",
-    ],
-}
diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp
deleted file mode 100644
index 8fa111d..0000000
--- a/services/batteryservice/BatteryProperties.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/BatteryService.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-namespace android {
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/BatteryProperties.java
- */
-
-status_t BatteryProperties::readFromParcel(Parcel* p) {
-    chargerAcOnline = p->readInt32() == 1 ? true : false;
-    chargerUsbOnline = p->readInt32() == 1 ? true : false;
-    chargerWirelessOnline = p->readInt32() == 1 ? true : false;
-    maxChargingCurrent = p->readInt32();
-    maxChargingVoltage = p->readInt32();
-    batteryStatus = p->readInt32();
-    batteryHealth = p->readInt32();
-    batteryPresent = p->readInt32() == 1 ? true : false;
-    batteryLevel = p->readInt32();
-    batteryVoltage = p->readInt32();
-    batteryTemperature = p->readInt32();
-    batteryFullCharge = p->readInt32();
-    batteryChargeCounter = p->readInt32();
-    batteryTechnology = String8((p->readString16()).string());
-    return OK;
-}
-
-status_t BatteryProperties::writeToParcel(Parcel* p) const {
-    p->writeInt32(chargerAcOnline ? 1 : 0);
-    p->writeInt32(chargerUsbOnline ? 1 : 0);
-    p->writeInt32(chargerWirelessOnline ? 1 : 0);
-    p->writeInt32(maxChargingCurrent);
-    p->writeInt32(maxChargingVoltage);
-    p->writeInt32(batteryStatus);
-    p->writeInt32(batteryHealth);
-    p->writeInt32(batteryPresent ? 1 : 0);
-    p->writeInt32(batteryLevel);
-    p->writeInt32(batteryVoltage);
-    p->writeInt32(batteryTemperature);
-    p->writeInt32(batteryFullCharge);
-    p->writeInt32(batteryChargeCounter);
-    p->writeString16(String16(batteryTechnology));
-    return OK;
-}
-
-}; // namespace android
diff --git a/services/batteryservice/BatteryProperty.cpp b/services/batteryservice/BatteryProperty.cpp
deleted file mode 100644
index 483d925..0000000
--- a/services/batteryservice/BatteryProperty.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/BatteryService.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/BatteryProperty.java
- */
-
-status_t BatteryProperty::readFromParcel(Parcel* p) {
-    valueInt64 = p->readInt64();
-    return OK;
-}
-
-status_t BatteryProperty::writeToParcel(Parcel* p) const {
-    p->writeInt64(valueInt64);
-    return OK;
-}
-
-}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp
deleted file mode 100644
index 6e5bcfe..0000000
--- a/services/batteryservice/IBatteryPropertiesListener.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener>
-{
-public:
-    explicit BpBatteryPropertiesListener(const sp<IBinder>& impl)
-        : BpInterface<IBatteryPropertiesListener>(impl)
-    {
-    }
-
-    void batteryPropertiesChanged(struct BatteryProperties props)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor());
-        data.writeInt32(1);
-        props.writeToParcel(&data);
-        remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener");
-
-// ----------------------------------------------------------------------------
-
-status_t BnBatteryPropertiesListener::onTransact(uint32_t code, const Parcel& data,
-                                                 Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case TRANSACT_BATTERYPROPERTIESCHANGED: {
-            CHECK_INTERFACE(IBatteryPropertiesListener, data, reply);
-            struct BatteryProperties props = {};
-            if (data.readInt32() != 0) {
-                props.readFromParcel((Parcel*)&data);
-            }
-            batteryPropertiesChanged(props);
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-};
-
-}; // namespace android
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
deleted file mode 100644
index 01a65ae..0000000
--- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "IBatteryPropertiesRegistrar"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <batteryservice/IBatteryPropertiesListener.h>
-#include <batteryservice/IBatteryPropertiesRegistrar.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> {
-public:
-    explicit BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
-        : BpInterface<IBatteryPropertiesRegistrar>(impl) {}
-
-        void registerListener(const sp<IBatteryPropertiesListener>& listener) {
-            Parcel data;
-            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
-            data.writeStrongBinder(IInterface::asBinder(listener));
-            remote()->transact(REGISTER_LISTENER, data, NULL);
-        }
-
-        void unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
-            Parcel data;
-            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
-            data.writeStrongBinder(IInterface::asBinder(listener));
-            remote()->transact(UNREGISTER_LISTENER, data, NULL);
-        }
-
-        status_t getProperty(int id, struct BatteryProperty *val) {
-            Parcel data, reply;
-            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
-            data.writeInt32(id);
-            remote()->transact(GET_PROPERTY, data, &reply);
-            int32_t ret = reply.readExceptionCode();
-            if (ret != 0) {
-                return ret;
-            }
-            ret = reply.readInt32();
-            int parcelpresent = reply.readInt32();
-            if (parcelpresent)
-                val->readFromParcel(&reply);
-            return ret;
-        }
-
-        void scheduleUpdate() {
-            Parcel data;
-            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
-            remote()->transact(SCHEDULE_UPDATE, data, NULL);
-        }
-};
-
-IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
-
-status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code,
-                                                  const Parcel& data,
-                                                  Parcel* reply,
-                                                  uint32_t flags)
-{
-    switch(code) {
-        case REGISTER_LISTENER: {
-            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
-            sp<IBatteryPropertiesListener> listener =
-                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
-            registerListener(listener);
-            return OK;
-        }
-
-        case UNREGISTER_LISTENER: {
-            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
-            sp<IBatteryPropertiesListener> listener =
-                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
-            unregisterListener(listener);
-            return OK;
-        }
-
-        case GET_PROPERTY: {
-            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
-            int id = data.readInt32();
-            struct BatteryProperty val;
-            status_t result = getProperty(id, &val);
-            reply->writeNoException();
-            reply->writeInt32(result);
-            reply->writeInt32(1);
-            val.writeToParcel(reply);
-            return OK;
-        }
-
-        case SCHEDULE_UPDATE: {
-            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
-            scheduleUpdate();
-            return OK;
-        }
-    }
-    return BBinder::onTransact(code, data, reply, flags);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/displayservice/DisplayEventReceiver.cpp b/services/displayservice/DisplayEventReceiver.cpp
index 5993e44..2bb74c2 100644
--- a/services/displayservice/DisplayEventReceiver.cpp
+++ b/services/displayservice/DisplayEventReceiver.cpp
@@ -102,10 +102,20 @@
 
             switch(buf[i].header.type) {
                 case FwkReceiver::DISPLAY_EVENT_VSYNC: {
-                    mCallback->onVsync(timestamp, event.vsync.count);
+                    auto ret = mCallback->onVsync(timestamp, event.vsync.count);
+                    if (!ret.isOk()) {
+                        LOG(ERROR) << "AttachedEvent handleEvent fails on onVsync callback"
+                                   << " because of " << ret.description();
+                        return 0;  // remove the callback
+                    }
                 } break;
                 case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
-                    mCallback->onHotplug(timestamp, event.hotplug.connected);
+                    auto ret = mCallback->onHotplug(timestamp, event.hotplug.connected);
+                    if (!ret.isOk()) {
+                        LOG(ERROR) << "AttachedEvent handleEvent fails on onHotplug callback"
+                                   << " because of " << ret.description();
+                        return 0;  // remove the callback
+                    }
                 } break;
                 default: {
                     LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 4fd98e2..a9e5a43 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -26,6 +26,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libbinder",
         "libcrypto",
         "libcutils",
@@ -37,6 +38,9 @@
     ],
 
     cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 50589b4..4d9a2a0 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -39,6 +39,7 @@
 
 #include <hardware_legacy/power.h>
 
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <openssl/sha.h>
 #include <utils/Log.h>
@@ -64,17 +65,13 @@
 #define INDENT2 "    "
 #define INDENT3 "      "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 static const char *WAKE_LOCK_ID = "KeyEvents";
 static const char *DEVICE_PATH = "/dev/input";
 
-/* return the larger integer */
-static inline int max(int v1, int v2)
-{
-    return (v1 > v2) ? v1 : v2;
-}
-
 static inline const char* toString(bool value) {
     return value ? "true" : "false";
 }
@@ -1739,43 +1736,43 @@
     mNeedToReopenDevices = true;
 }
 
-void EventHub::dump(String8& dump) {
-    dump.append("Event Hub State:\n");
+void EventHub::dump(std::string& dump) {
+    dump += "Event Hub State:\n";
 
     { // acquire lock
         AutoMutex _l(mLock);
 
-        dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
+        dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
 
-        dump.append(INDENT "Devices:\n");
+        dump += INDENT "Devices:\n";
 
         for (size_t i = 0; i < mDevices.size(); i++) {
             const Device* device = mDevices.valueAt(i);
             if (mBuiltInKeyboardId == device->id) {
-                dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
+                dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
                         device->id, device->identifier.name.string());
             } else {
-                dump.appendFormat(INDENT2 "%d: %s\n", device->id,
+                dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
                         device->identifier.name.string());
             }
-            dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
-            dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
-            dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled));
-            dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
-            dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
-            dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
-            dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
-            dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
+            dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes);
+            dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string());
+            dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
+            dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
+            dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string());
+            dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
+            dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+            dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
                     "product=0x%04x, version=0x%04x\n",
                     device->identifier.bus, device->identifier.vendor,
                     device->identifier.product, device->identifier.version);
-            dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
+            dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
                     device->keyMap.keyLayoutFile.string());
-            dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
+            dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
                     device->keyMap.keyCharacterMapFile.string());
-            dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
+            dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
                     device->configurationFile.string());
-            dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
+            dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
                     toString(device->overlayKeyMap != NULL));
         }
     } // release lock
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 727b73a..66bc294 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -24,7 +24,6 @@
 #include <input/KeyLayoutMap.h>
 #include <input/KeyCharacterMap.h>
 #include <input/VirtualKeyMap.h>
-#include <utils/String8.h>
 #include <utils/Mutex.h>
 #include <utils/Log.h>
 #include <utils/List.h>
@@ -262,7 +261,7 @@
     virtual void wake() = 0;
 
     /* Dump EventHub state to a string. */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
@@ -333,7 +332,7 @@
 
     virtual void wake();
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
 protected:
diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h
index 1f5504c..724fc2c 100644
--- a/services/inputflinger/InputApplication.h
+++ b/services/inputflinger/InputApplication.h
@@ -18,10 +18,8 @@
 #define _UI_INPUT_APPLICATION_H
 
 #include <input/Input.h>
-
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <utils/String8.h>
 
 namespace android {
 
@@ -29,7 +27,7 @@
  * Describes the properties of an application that can receive input.
  */
 struct InputApplicationInfo {
-    String8 name;
+    std::string name;
     nsecs_t dispatchingTimeout;
 };
 
@@ -46,8 +44,8 @@
         return mInfo;
     }
 
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
+    inline std::string getName() const {
+        return mInfo ? mInfo->name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 69067d2..9a449fa 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -47,10 +47,13 @@
 
 #include <errno.h>
 #include <limits.h>
+#include <sstream>
 #include <stddef.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <android-base/chrono_utils.h>
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 #include <powermanager/PowerManager.h>
@@ -61,32 +64,38 @@
 #define INDENT3 "      "
 #define INDENT4 "        "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 // Default input dispatching timeout if there is no focused application or paused window
 // from which to determine an appropriate dispatching timeout.
-const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
+constexpr nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
 
 // Amount of time to allow for all pending events to be processed when an app switch
 // key is on the way.  This is used to preempt input dispatch and drop input events
 // when an application takes too long to respond and the user has pressed an app switch key.
-const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
+constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
 // Amount of time to allow for an event to be dispatched (measured since its eventTime)
 // before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
+constexpr nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
 
 // Amount of time to allow touch events to be streamed out to a connection before requiring
 // that the first event be finished.  This value extends the ANR timeout by the specified
 // amount.  For example, if streaming is allowed to get ahead by one second relative to the
 // queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
-const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
+constexpr nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
 // Log a warning when an event takes longer than this to process, even if an ANR does not occur.
-const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
+constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
+
+// Log a warning when an interception call takes longer than this to process.
+constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms;
 
 // Number of recent events to keep for debugging purposes.
-const size_t RECENT_QUEUE_MAX_SIZE = 10;
+constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
+
 
 static inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -96,6 +105,36 @@
     return value ? "true" : "false";
 }
 
+static std::string motionActionToString(int32_t action) {
+    // Convert MotionEvent action to string
+    switch(action & AMOTION_EVENT_ACTION_MASK) {
+        case AMOTION_EVENT_ACTION_DOWN:
+            return "DOWN";
+        case AMOTION_EVENT_ACTION_MOVE:
+            return "MOVE";
+        case AMOTION_EVENT_ACTION_UP:
+            return "UP";
+        case AMOTION_EVENT_ACTION_POINTER_DOWN:
+            return "POINTER_DOWN";
+        case AMOTION_EVENT_ACTION_POINTER_UP:
+            return "POINTER_UP";
+    }
+    return StringPrintf("%" PRId32, action);
+}
+
+static std::string keyActionToString(int32_t action) {
+    // Convert KeyEvent action to string
+    switch(action) {
+        case AKEY_EVENT_ACTION_DOWN:
+            return "DOWN";
+        case AKEY_EVENT_ACTION_UP:
+            return "UP";
+        case AKEY_EVENT_ACTION_MULTIPLE:
+            return "MULTIPLE";
+    }
+    return StringPrintf("%" PRId32, action);
+}
+
 static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
     return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
             >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -176,9 +215,9 @@
     return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE;
 }
 
-static void dumpRegion(String8& dump, const Region& region) {
+static void dumpRegion(std::string& dump, const Region& region) {
     if (region.isEmpty()) {
-        dump.append("<empty>");
+        dump += "<empty>";
         return;
     }
 
@@ -189,9 +228,9 @@
         if (first) {
             first = false;
         } else {
-            dump.append("|");
+            dump += "|";
         }
-        dump.appendFormat("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom);
+        dump += StringPrintf("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom);
         cur++;
     }
 }
@@ -685,7 +724,7 @@
 bool InputDispatcher::dispatchConfigurationChangedLocked(
         nsecs_t currentTime, ConfigurationChangedEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime);
+    ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime);
 #endif
 
     // Reset key repeating in case a keyboard device was added or removed or something.
@@ -701,7 +740,8 @@
 bool InputDispatcher::dispatchDeviceResetLocked(
         nsecs_t currentTime, DeviceResetEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId);
+    ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime,
+            entry->deviceId);
 #endif
 
     CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
@@ -811,9 +851,9 @@
 
 void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
-            "repeatCount=%d, downTime=%lld",
+            "repeatCount=%d, downTime=%" PRId64,
             prefix,
             entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
             entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
@@ -884,10 +924,10 @@
 
 void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, "
             "metaState=0x%x, buttonState=0x%x,"
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
             prefix,
             entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
             entry->action, entry->actionButton, entry->flags,
@@ -936,7 +976,7 @@
 #if DEBUG_FOCUS
             ALOGD("Dropping event delivery to target with channel '%s' because it "
                     "is no longer registered with the input dispatcher.",
-                    inputTarget.inputChannel->getName().string());
+                    inputTarget.inputChannel->getName().c_str());
 #endif
         }
     }
@@ -962,7 +1002,7 @@
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
 #if DEBUG_FOCUS
             ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
-                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
+                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
                     reason);
 #endif
             nsecs_t timeout;
@@ -1069,7 +1109,7 @@
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
-    String8 reason;
+    std::string reason;
 
     // If there is no currently focused window and no focused application
     // then drop the event.
@@ -1097,9 +1137,9 @@
     // Check whether the window is ready for more input.
     reason = checkWindowReadyForMoreInputLocked(currentTime,
             mFocusedWindowHandle, entry, "focused");
-    if (!reason.isEmpty()) {
+    if (!reason.empty()) {
         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
+                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
         goto Unresponsive;
     }
 
@@ -1132,8 +1172,6 @@
         INJECTION_PERMISSION_DENIED
     };
 
-    nsecs_t startTime = now();
-
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
     int32_t displayId = entry->displayId;
@@ -1310,8 +1348,8 @@
                     && newTouchedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Touch is slipping out of window %s into window %s.",
-                        oldTouchedWindowHandle->getName().string(),
-                        newTouchedWindowHandle->getName().string());
+                        oldTouchedWindowHandle->getName().c_str(),
+                        newTouchedWindowHandle->getName().c_str());
 #endif
                 // Make a slippery exit from the old window.
                 mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
@@ -1345,7 +1383,7 @@
         if (mLastHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
             ALOGD("Sending hover exit event to window %s.",
-                    mLastHoverWindowHandle->getName().string());
+                    mLastHoverWindowHandle->getName().c_str());
 #endif
             mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
@@ -1355,7 +1393,7 @@
         if (newHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
             ALOGD("Sending hover enter event to window %s.",
-                    newHoverWindowHandle->getName().string());
+                    newHoverWindowHandle->getName().c_str());
 #endif
             mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
@@ -1413,11 +1451,11 @@
         const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
         if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
             // Check whether the window is ready for more input.
-            String8 reason = checkWindowReadyForMoreInputLocked(currentTime,
+            std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
                     touchedWindow.windowHandle, entry, "touched");
-            if (!reason.isEmpty()) {
+            if (!reason.empty()) {
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string());
+                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
                 goto Unresponsive;
             }
         }
@@ -1605,7 +1643,7 @@
             ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
                     "owned by uid %d",
                     injectionState->injectorPid, injectionState->injectorUid,
-                    windowHandle->getName().string(),
+                    windowHandle->getName().c_str(),
                     windowHandle->getInfo()->ownerUid);
         } else {
             ALOGW("Permission denied: injecting event from pid %d uid %d",
@@ -1657,18 +1695,18 @@
     return false;
 }
 
-String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
+std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
         const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
         const char* targetType) {
     // If the window is paused then keep waiting.
     if (windowHandle->getInfo()->paused) {
-        return String8::format("Waiting because the %s window is paused.", targetType);
+        return StringPrintf("Waiting because the %s window is paused.", targetType);
     }
 
     // If the window's connection is not registered then keep waiting.
     ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
     if (connectionIndex < 0) {
-        return String8::format("Waiting because the %s window's input channel is not "
+        return StringPrintf("Waiting because the %s window's input channel is not "
                 "registered with the input dispatcher.  The window may be in the process "
                 "of being removed.", targetType);
     }
@@ -1676,14 +1714,14 @@
     // If the connection is dead then keep waiting.
     sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
     if (connection->status != Connection::STATUS_NORMAL) {
-        return String8::format("Waiting because the %s window's input connection is %s."
+        return StringPrintf("Waiting because the %s window's input connection is %s."
                 "The window may be in the process of being removed.", targetType,
                 connection->getStatusLabel());
     }
 
     // If the connection is backed up then keep waiting.
     if (connection->inputPublisherBlocked) {
-        return String8::format("Waiting because the %s window's input channel is full.  "
+        return StringPrintf("Waiting because the %s window's input channel is full.  "
                 "Outbound queue length: %d.  Wait queue length: %d.",
                 targetType, connection->outboundQueue.count(), connection->waitQueue.count());
     }
@@ -1702,7 +1740,7 @@
         // To obtain this behavior, we must serialize key events with respect to all
         // prior input events.
         if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
-            return String8::format("Waiting to send key event because the %s window has not "
+            return StringPrintf("Waiting to send key event because the %s window has not "
                     "finished processing all of the input events that were previously "
                     "delivered to it.  Outbound queue length: %d.  Wait queue length: %d.",
                     targetType, connection->outboundQueue.count(), connection->waitQueue.count());
@@ -1726,7 +1764,7 @@
         if (!connection->waitQueue.isEmpty()
                 && currentTime >= connection->waitQueue.head->deliveryTime
                         + STREAM_AHEAD_EVENT_TIMEOUT) {
-            return String8::format("Waiting to send non-key event because the %s window has not "
+            return StringPrintf("Waiting to send non-key event because the %s window has not "
                     "finished processing certain input events that were delivered to it over "
                     "%0.1fms ago.  Wait queue length: %d.  Wait queue head age: %0.1fms.",
                     targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
@@ -1734,17 +1772,17 @@
                     (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
         }
     }
-    return String8::empty();
+    return "";
 }
 
-String8 InputDispatcher::getApplicationWindowLabelLocked(
+std::string InputDispatcher::getApplicationWindowLabelLocked(
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle) {
     if (applicationHandle != NULL) {
         if (windowHandle != NULL) {
-            String8 label(applicationHandle->getName());
-            label.append(" - ");
-            label.append(windowHandle->getName());
+            std::string label(applicationHandle->getName());
+            label += " - ";
+            label += windowHandle->getName();
             return label;
         } else {
             return applicationHandle->getName();
@@ -1752,7 +1790,7 @@
     } else if (windowHandle != NULL) {
         return windowHandle->getName();
     } else {
-        return String8("<unknown application or window>");
+        return "<unknown application or window>";
     }
 }
 
@@ -1761,7 +1799,7 @@
         const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
         if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
 #if DEBUG_DISPATCH_CYCLE
-            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string());
+            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
 #endif
             return;
         }
@@ -1802,7 +1840,7 @@
     ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
             "xOffset=%f, yOffset=%f, scaleFactor=%f, "
             "pointerIds=0x%x",
-            connection->getInputChannelName(), inputTarget->flags,
+            connection->getInputChannelName().c_str(), inputTarget->flags,
             inputTarget->xOffset, inputTarget->yOffset,
             inputTarget->scaleFactor, inputTarget->pointerIds.value);
 #endif
@@ -1812,7 +1850,7 @@
     if (connection->status != Connection::STATUS_NORMAL) {
 #if DEBUG_DISPATCH_CYCLE
         ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
-                connection->getInputChannelName(), connection->getStatusLabel());
+                connection->getInputChannelName().c_str(), connection->getStatusLabel());
 #endif
         return;
     }
@@ -1830,7 +1868,7 @@
             }
 #if DEBUG_FOCUS
             ALOGD("channel '%s' ~ Split motion event.",
-                    connection->getInputChannelName());
+                    connection->getInputChannelName().c_str());
             logOutboundMotionDetailsLocked("  ", splitMotionEntry);
 #endif
             enqueueDispatchEntriesLocked(currentTime, connection,
@@ -1894,7 +1932,7 @@
                 dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
 #if DEBUG_DISPATCH_CYCLE
             ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
-                    connection->getInputChannelName());
+                    connection->getInputChannelName().c_str());
 #endif
             delete dispatchEntry;
             return; // skip the inconsistent event
@@ -1922,7 +1960,7 @@
                         motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
 #if DEBUG_DISPATCH_CYCLE
         ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
-                connection->getInputChannelName());
+                connection->getInputChannelName().c_str());
 #endif
             dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
         }
@@ -1939,7 +1977,7 @@
                 dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
 #if DEBUG_DISPATCH_CYCLE
             ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
-                    connection->getInputChannelName());
+                    connection->getInputChannelName().c_str());
 #endif
             delete dispatchEntry;
             return; // skip the inconsistent event
@@ -1962,7 +2000,7 @@
         const sp<Connection>& connection) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ startDispatchCycle",
-            connection->getInputChannelName());
+            connection->getInputChannelName().c_str());
 #endif
 
     while (connection->status == Connection::STATUS_NORMAL
@@ -1994,10 +2032,10 @@
             const PointerCoords* usingCoords = motionEntry->pointerCoords;
 
             // Set the X and Y offset depending on the input source.
-            float xOffset, yOffset, scaleFactor;
+            float xOffset, yOffset;
             if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                     && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
-                scaleFactor = dispatchEntry->scaleFactor;
+                float scaleFactor = dispatchEntry->scaleFactor;
                 xOffset = dispatchEntry->xOffset * scaleFactor;
                 yOffset = dispatchEntry->yOffset * scaleFactor;
                 if (scaleFactor != 1.0f) {
@@ -2010,7 +2048,6 @@
             } else {
                 xOffset = 0.0f;
                 yOffset = 0.0f;
-                scaleFactor = 1.0f;
 
                 // We don't want the dispatch target to know.
                 if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
@@ -2046,7 +2083,8 @@
                     ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
                             "This is unexpected because the wait queue is empty, so the pipe "
                             "should be empty and we shouldn't have any problems writing an "
-                            "event to it, status=%d", connection->getInputChannelName(), status);
+                            "event to it, status=%d", connection->getInputChannelName().c_str(),
+                            status);
                     abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
                 } else {
                     // Pipe is full and we are waiting for the app to finish process some events
@@ -2054,13 +2092,13 @@
 #if DEBUG_DISPATCH_CYCLE
                     ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
                             "waiting for the application to catch up",
-                            connection->getInputChannelName());
+                            connection->getInputChannelName().c_str());
 #endif
                     connection->inputPublisherBlocked = true;
                 }
             } else {
                 ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
-                        "status=%d", connection->getInputChannelName(), status);
+                        "status=%d", connection->getInputChannelName().c_str(), status);
                 abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
             }
             return;
@@ -2078,7 +2116,7 @@
         const sp<Connection>& connection, uint32_t seq, bool handled) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
-            connection->getInputChannelName(), seq, toString(handled));
+            connection->getInputChannelName().c_str(), seq, toString(handled));
 #endif
 
     connection->inputPublisherBlocked = false;
@@ -2096,7 +2134,7 @@
         const sp<Connection>& connection, bool notify) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
-            connection->getInputChannelName(), toString(notify));
+            connection->getInputChannelName().c_str(), toString(notify));
 #endif
 
     // Clear the dispatch queues.
@@ -2149,7 +2187,7 @@
         if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
             if (!(events & ALOOPER_EVENT_INPUT)) {
                 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
-                        "events=0x%x", connection->getInputChannelName(), events);
+                        "events=0x%x", connection->getInputChannelName().c_str(), events);
                 return 1;
             }
 
@@ -2176,7 +2214,7 @@
             notify = status != DEAD_OBJECT || !connection->monitor;
             if (notify) {
                 ALOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
-                        connection->getInputChannelName(), status);
+                        connection->getInputChannelName().c_str(), status);
             }
         } else {
             // Monitor channels are never explicitly unregistered.
@@ -2185,7 +2223,7 @@
             notify = !connection->monitor;
             if (notify) {
                 ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred.  "
-                        "events=0x%x", connection->getInputChannelName(), events);
+                        "events=0x%x", connection->getInputChannelName().c_str(), events);
             }
         }
 
@@ -2233,9 +2271,9 @@
 
     if (!cancelationEvents.isEmpty()) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+        ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
                 "with reality: %s, mode=%d.",
-                connection->getInputChannelName(), cancelationEvents.size(),
+                connection->getInputChannelName().c_str(), cancelationEvents.size(),
                 options.reason, options.mode);
 #endif
         for (size_t i = 0; i < cancelationEvents.size(); i++) {
@@ -2369,7 +2407,7 @@
 
 void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime);
+    ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
 #endif
 
     bool needWake;
@@ -2387,8 +2425,9 @@
 
 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
-            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
+    ALOGD("notifyKey - eventTime=%" PRId64
+            ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
+            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
             args->eventTime, args->deviceId, args->source, args->policyFlags,
             args->action, args->flags, args->keyCode, args->scanCode,
             args->metaState, args->downTime);
@@ -2444,7 +2483,12 @@
             flags, keyCode, args->scanCode, metaState, 0,
             args->downTime, args->eventTime);
 
+    android::base::Timer t;
     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     bool needWake;
     { // acquire lock
@@ -2482,9 +2526,9 @@
 
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
             args->eventTime, args->deviceId, args->source, args->policyFlags,
             args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
             args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
@@ -2513,7 +2557,13 @@
 
     uint32_t policyFlags = args->policyFlags;
     policyFlags |= POLICY_FLAG_TRUSTED;
+
+    android::base::Timer t;
     mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     bool needWake;
     { // acquire lock
@@ -2562,9 +2612,9 @@
 
 void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x",
-            args->eventTime, args->policyFlags,
-            args->switchValues, args->switchMask);
+    ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
+            "switchMask=0x%08x",
+            args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
 #endif
 
     uint32_t policyFlags = args->policyFlags;
@@ -2575,7 +2625,7 @@
 
 void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d",
+    ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d",
             args->eventTime, args->deviceId);
 #endif
 
@@ -2625,7 +2675,12 @@
         }
 
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
+            android::base::Timer t;
             mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+            if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+                ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
+                        std::to_string(t.duration().count()).c_str());
+            }
         }
 
         mLock.lock();
@@ -2650,7 +2705,12 @@
 
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
             nsecs_t eventTime = motionEvent->getEventTime();
+            android::base::Timer t;
             mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags);
+            if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+                ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
+                        std::to_string(t.duration().count()).c_str());
+            }
         }
 
         mLock.lock();
@@ -2883,7 +2943,7 @@
             if (mFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Focus left window: %s",
-                        mFocusedWindowHandle->getName().string());
+                        mFocusedWindowHandle->getName().c_str());
 #endif
                 sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
                 if (focusedInputChannel != NULL) {
@@ -2896,7 +2956,7 @@
             if (newFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Focus entered window: %s",
-                        newFocusedWindowHandle->getName().string());
+                        newFocusedWindowHandle->getName().c_str());
 #endif
             }
             mFocusedWindowHandle = newFocusedWindowHandle;
@@ -2904,12 +2964,12 @@
 
         for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
             TouchState& state = mTouchStatesByDisplay.editValueAt(d);
-            for (size_t i = 0; i < state.windows.size(); i++) {
+            for (size_t i = 0; i < state.windows.size(); ) {
                 TouchedWindow& touchedWindow = state.windows.editItemAt(i);
                 if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
                     ALOGD("Touched window was removed: %s",
-                            touchedWindow.windowHandle->getName().string());
+                            touchedWindow.windowHandle->getName().c_str());
 #endif
                     sp<InputChannel> touchedInputChannel =
                             touchedWindow.windowHandle->getInputChannel();
@@ -2919,7 +2979,9 @@
                         synthesizeCancelationEventsForInputChannelLocked(
                                 touchedInputChannel, options);
                     }
-                    state.windows.removeAt(i--);
+                    state.windows.removeAt(i);
+                } else {
+                  ++i;
                 }
             }
         }
@@ -2932,7 +2994,7 @@
             const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
             if (!hasWindowHandleLocked(oldWindowHandle)) {
 #if DEBUG_FOCUS
-                ALOGD("Window went away: %s", oldWindowHandle->getName().string());
+                ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
 #endif
                 oldWindowHandle->releaseInfo();
             }
@@ -3034,7 +3096,7 @@
         const sp<InputChannel>& toChannel) {
 #if DEBUG_FOCUS
     ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
-            fromChannel->getName().string(), toChannel->getName().string());
+            fromChannel->getName().c_str(), toChannel->getName().c_str());
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
@@ -3131,72 +3193,68 @@
 }
 
 void InputDispatcher::logDispatchStateLocked() {
-    String8 dump;
+    std::string dump;
     dumpDispatchStateLocked(dump);
 
-    char* text = dump.lockBuffer(dump.size());
-    char* start = text;
-    while (*start != '\0') {
-        char* end = strchr(start, '\n');
-        if (*end == '\n') {
-            *(end++) = '\0';
-        }
-        ALOGD("%s", start);
-        start = end;
+    std::istringstream stream(dump);
+    std::string line;
+
+    while (std::getline(stream, line, '\n')) {
+        ALOGD("%s", line.c_str());
     }
 }
 
-void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
-    dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
-    dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
+void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
+    dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
+    dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
 
     if (mFocusedApplicationHandle != NULL) {
-        dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
-                mFocusedApplicationHandle->getName().string(),
+        dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
+                mFocusedApplicationHandle->getName().c_str(),
                 mFocusedApplicationHandle->getDispatchingTimeout(
                         DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
     } else {
-        dump.append(INDENT "FocusedApplication: <null>\n");
+        dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
     }
-    dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
-            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>");
+    dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
+            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().c_str() : "<null>");
 
     if (!mTouchStatesByDisplay.isEmpty()) {
-        dump.appendFormat(INDENT "TouchStatesByDisplay:\n");
+        dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
         for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) {
             const TouchState& state = mTouchStatesByDisplay.valueAt(i);
-            dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
+            dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
                     state.displayId, toString(state.down), toString(state.split),
                     state.deviceId, state.source);
             if (!state.windows.isEmpty()) {
-                dump.append(INDENT3 "Windows:\n");
+                dump += INDENT3 "Windows:\n";
                 for (size_t i = 0; i < state.windows.size(); i++) {
                     const TouchedWindow& touchedWindow = state.windows[i];
-                    dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
-                            i, touchedWindow.windowHandle->getName().string(),
+                    dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
+                            i, touchedWindow.windowHandle->getName().c_str(),
                             touchedWindow.pointerIds.value,
                             touchedWindow.targetFlags);
                 }
             } else {
-                dump.append(INDENT3 "Windows: <none>\n");
+                dump += INDENT3 "Windows: <none>\n";
             }
         }
     } else {
-        dump.append(INDENT "TouchStates: <no displays touched>\n");
+        dump += INDENT "TouchStates: <no displays touched>\n";
     }
 
     if (!mWindowHandles.isEmpty()) {
-        dump.append(INDENT "Windows:\n");
+        dump += INDENT "Windows:\n";
         for (size_t i = 0; i < mWindowHandles.size(); i++) {
             const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
-            dump.appendFormat(INDENT2 "%zu: name='%s', displayId=%d, "
+            dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
                     "paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                     "frame=[%d,%d][%d,%d], scale=%f, "
                     "touchableRegion=",
-                    i, windowInfo->name.string(), windowInfo->displayId,
+                    i, windowInfo->name.c_str(), windowInfo->displayId,
                     toString(windowInfo->paused),
                     toString(windowInfo->hasFocus),
                     toString(windowInfo->hasWallpaper),
@@ -3208,140 +3266,141 @@
                     windowInfo->frameRight, windowInfo->frameBottom,
                     windowInfo->scaleFactor);
             dumpRegion(dump, windowInfo->touchableRegion);
-            dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures);
-            dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+            dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+            dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                     windowInfo->ownerPid, windowInfo->ownerUid,
                     windowInfo->dispatchingTimeout / 1000000.0);
         }
     } else {
-        dump.append(INDENT "Windows: <none>\n");
+        dump += INDENT "Windows: <none>\n";
     }
 
     if (!mMonitoringChannels.isEmpty()) {
-        dump.append(INDENT "MonitoringChannels:\n");
+        dump += INDENT "MonitoringChannels:\n";
         for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
             const sp<InputChannel>& channel = mMonitoringChannels[i];
-            dump.appendFormat(INDENT2 "%zu: '%s'\n", i, channel->getName().string());
+            dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
         }
     } else {
-        dump.append(INDENT "MonitoringChannels: <none>\n");
+        dump += INDENT "MonitoringChannels: <none>\n";
     }
 
     nsecs_t currentTime = now();
 
     // Dump recently dispatched or dropped events from oldest to newest.
     if (!mRecentQueue.isEmpty()) {
-        dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
+        dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
         for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
+            dump += INDENT2;
             entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
+            dump += StringPrintf(", age=%0.1fms\n",
                     (currentTime - entry->eventTime) * 0.000001f);
         }
     } else {
-        dump.append(INDENT "RecentQueue: <empty>\n");
+        dump += INDENT "RecentQueue: <empty>\n";
     }
 
     // Dump event currently being dispatched.
     if (mPendingEvent) {
-        dump.append(INDENT "PendingEvent:\n");
-        dump.append(INDENT2);
+        dump += INDENT "PendingEvent:\n";
+        dump += INDENT2;
         mPendingEvent->appendDescription(dump);
-        dump.appendFormat(", age=%0.1fms\n",
+        dump += StringPrintf(", age=%0.1fms\n",
                 (currentTime - mPendingEvent->eventTime) * 0.000001f);
     } else {
-        dump.append(INDENT "PendingEvent: <none>\n");
+        dump += INDENT "PendingEvent: <none>\n";
     }
 
     // Dump inbound events from oldest to newest.
     if (!mInboundQueue.isEmpty()) {
-        dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
+        dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
         for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
+            dump += INDENT2;
             entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
+            dump += StringPrintf(", age=%0.1fms\n",
                     (currentTime - entry->eventTime) * 0.000001f);
         }
     } else {
-        dump.append(INDENT "InboundQueue: <empty>\n");
+        dump += INDENT "InboundQueue: <empty>\n";
     }
 
     if (!mReplacedKeys.isEmpty()) {
-        dump.append(INDENT "ReplacedKeys:\n");
+        dump += INDENT "ReplacedKeys:\n";
         for (size_t i = 0; i < mReplacedKeys.size(); i++) {
             const KeyReplacement& replacement = mReplacedKeys.keyAt(i);
             int32_t newKeyCode = mReplacedKeys.valueAt(i);
-            dump.appendFormat(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n",
+            dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n",
                     i, replacement.keyCode, replacement.deviceId, newKeyCode);
         }
     } else {
-        dump.append(INDENT "ReplacedKeys: <empty>\n");
+        dump += INDENT "ReplacedKeys: <empty>\n";
     }
 
     if (!mConnectionsByFd.isEmpty()) {
-        dump.append(INDENT "Connections:\n");
+        dump += INDENT "Connections:\n";
         for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
             const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
-            dump.appendFormat(INDENT2 "%zu: channelName='%s', windowName='%s', "
+            dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', "
                     "status=%s, monitor=%s, inputPublisherBlocked=%s\n",
-                    i, connection->getInputChannelName(), connection->getWindowName(),
+                    i, connection->getInputChannelName().c_str(),
+                    connection->getWindowName().c_str(),
                     connection->getStatusLabel(), toString(connection->monitor),
                     toString(connection->inputPublisherBlocked));
 
             if (!connection->outboundQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n",
+                dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n",
                         connection->outboundQueue.count());
                 for (DispatchEntry* entry = connection->outboundQueue.head; entry;
                         entry = entry->next) {
                     dump.append(INDENT4);
                     entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
+                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
                             entry->targetFlags, entry->resolvedAction,
                             (currentTime - entry->eventEntry->eventTime) * 0.000001f);
                 }
             } else {
-                dump.append(INDENT3 "OutboundQueue: <empty>\n");
+                dump += INDENT3 "OutboundQueue: <empty>\n";
             }
 
             if (!connection->waitQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "WaitQueue: length=%u\n",
+                dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n",
                         connection->waitQueue.count());
                 for (DispatchEntry* entry = connection->waitQueue.head; entry;
                         entry = entry->next) {
-                    dump.append(INDENT4);
+                    dump += INDENT4;
                     entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, "
+                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
                             "age=%0.1fms, wait=%0.1fms\n",
                             entry->targetFlags, entry->resolvedAction,
                             (currentTime - entry->eventEntry->eventTime) * 0.000001f,
                             (currentTime - entry->deliveryTime) * 0.000001f);
                 }
             } else {
-                dump.append(INDENT3 "WaitQueue: <empty>\n");
+                dump += INDENT3 "WaitQueue: <empty>\n";
             }
         }
     } else {
-        dump.append(INDENT "Connections: <none>\n");
+        dump += INDENT "Connections: <none>\n";
     }
 
     if (isAppSwitchPendingLocked()) {
-        dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n",
+        dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n",
                 (mAppSwitchDueTime - now()) / 1000000.0);
     } else {
-        dump.append(INDENT "AppSwitch: not pending\n");
+        dump += INDENT "AppSwitch: not pending\n";
     }
 
-    dump.append(INDENT "Configuration:\n");
-    dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n",
+    dump += INDENT "Configuration:\n";
+    dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n",
             mConfig.keyRepeatDelay * 0.000001f);
-    dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
+    dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
             mConfig.keyRepeatTimeout * 0.000001f);
 }
 
 status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
+    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),
             toString(monitor));
 #endif
 
@@ -3350,7 +3409,7 @@
 
         if (getConnectionIndexLocked(inputChannel) >= 0) {
             ALOGW("Attempted to register already registered input channel '%s'",
-                    inputChannel->getName().string());
+                    inputChannel->getName().c_str());
             return BAD_VALUE;
         }
 
@@ -3373,7 +3432,7 @@
 
 status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
+    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str());
 #endif
 
     { // acquire lock
@@ -3396,7 +3455,7 @@
     ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
     if (connectionIndex < 0) {
         ALOGW("Attempted to unregister already unregistered input channel '%s'",
-                inputChannel->getName().string());
+                inputChannel->getName().c_str());
         return BAD_VALUE;
     }
 
@@ -3450,7 +3509,7 @@
 void InputDispatcher::onDispatchCycleBrokenLocked(
         nsecs_t currentTime, const sp<Connection>& connection) {
     ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
-            connection->getInputChannelName());
+            connection->getInputChannelName().c_str());
 
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
@@ -3465,7 +3524,7 @@
     float waitDuration = (currentTime - waitStartTime) * 0.000001f;
     ALOGI("Application is not responding: %s.  "
             "It has been %0.1fms since event, %0.1fms since wait started.  Reason: %s",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
+            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
             dispatchLatency, waitDuration, reason);
 
     // Capture a record of the InputDispatcher state at the time of the ANR.
@@ -3475,13 +3534,13 @@
     char timestr[64];
     strftime(timestr, sizeof(timestr), "%F %T", &tm);
     mLastANRState.clear();
-    mLastANRState.append(INDENT "ANR:\n");
-    mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr);
-    mLastANRState.appendFormat(INDENT2 "Window: %s\n",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
-    mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
-    mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
-    mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason);
+    mLastANRState += INDENT "ANR:\n";
+    mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
+    mLastANRState += StringPrintf(INDENT2 "Window: %s\n",
+            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str());
+    mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
+    mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
+    mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
     dumpDispatchStateLocked(mLastANRState);
 
     CommandEntry* commandEntry = postCommandLocked(
@@ -3537,8 +3596,13 @@
 
     mLock.unlock();
 
+    android::base::Timer t;
     nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
             &event, entry->policyFlags);
+    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+        ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
+                std::to_string(t.duration().count()).c_str());
+    }
 
     mLock.lock();
 
@@ -3565,11 +3629,11 @@
     if (dispatchEntry) {
         nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
         if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
-            String8 msg;
-            msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ",
-                    connection->getWindowName(), eventDuration * 0.000001f);
+            std::string msg =
+                    StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
+                    connection->getWindowName().c_str(), eventDuration * 0.000001f);
             dispatchEntry->eventEntry->appendDescription(msg);
-            ALOGI("%s", msg.string());
+            ALOGI("%s", msg.c_str());
         }
 
         bool restartEvent;
@@ -3736,15 +3800,15 @@
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             {
-                String8 msg;
+                std::string msg;
                 const KeyedVector<int32_t, int32_t>& fallbackKeys =
                         connection->inputState.getFallbackKeys();
                 for (size_t i = 0; i < fallbackKeys.size(); i++) {
-                    msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
+                    msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i),
                             fallbackKeys.valueAt(i));
                 }
-                ALOGD("Unhandled key event: %d currently tracked fallback keys%s.",
-                        fallbackKeys.size(), msg.string());
+                ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
+                        fallbackKeys.size(), msg.c_str());
             }
 #endif
 
@@ -3810,7 +3874,7 @@
 void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) {
     if (ATRACE_ENABLED()) {
         char counterName[40];
-        snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName());
+        snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
         ATRACE_INT(counterName, connection->outboundQueue.count());
     }
 }
@@ -3818,20 +3882,20 @@
 void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) {
     if (ATRACE_ENABLED()) {
         char counterName[40];
-        snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName());
+        snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
         ATRACE_INT(counterName, connection->waitQueue.count());
     }
 }
 
-void InputDispatcher::dump(String8& dump) {
+void InputDispatcher::dump(std::string& dump) {
     AutoMutex _l(mLock);
 
-    dump.append("Input Dispatcher State:\n");
+    dump += "Input Dispatcher State:\n";
     dumpDispatchStateLocked(dump);
 
-    if (!mLastANRState.isEmpty()) {
-        dump.append("\nInput Dispatcher State at time of last ANR:\n");
-        dump.append(mLastANRState);
+    if (!mLastANRState.empty()) {
+        dump += "\nInput Dispatcher State at time of last ANR:\n";
+        dump += mLastANRState;
     }
 }
 
@@ -3903,9 +3967,8 @@
 InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() {
 }
 
-void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const {
-    msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x",
-            policyFlags);
+void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags);
 }
 
 
@@ -3919,8 +3982,8 @@
 InputDispatcher::DeviceResetEntry::~DeviceResetEntry() {
 }
 
-void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
+void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
             deviceId, policyFlags);
 }
 
@@ -3942,12 +4005,12 @@
 InputDispatcher::KeyEntry::~KeyEntry() {
 }
 
-void InputDispatcher::KeyEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
+void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%s, "
             "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
             "repeatCount=%d), policyFlags=0x%08x",
-            deviceId, source, action, flags, keyCode, scanCode, metaState,
-            repeatCount, policyFlags);
+            deviceId, source, keyActionToString(action).c_str(), flags, keyCode,
+            scanCode, metaState, repeatCount, policyFlags);
 }
 
 void InputDispatcher::KeyEntry::recycle() {
@@ -3987,20 +4050,20 @@
 InputDispatcher::MotionEntry::~MotionEntry() {
 }
 
-void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%s, actionButton=0x%08x, "
             "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
             "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
-            xPrecision, yPrecision, displayId);
+            deviceId, source, motionActionToString(action).c_str(), actionButton, flags, metaState,
+            buttonState, edgeFlags, xPrecision, yPrecision, displayId);
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
-            msg.append(", ");
+            msg += ", ";
         }
-        msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id,
+        msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id,
                 pointerCoords[i].getX(), pointerCoords[i].getY());
     }
-    msg.appendFormat("]), policyFlags=0x%08x", policyFlags);
+    msg += StringPrintf("]), policyFlags=0x%08x", policyFlags);
 }
 
 
@@ -4397,9 +4460,9 @@
 InputDispatcher::Connection::~Connection() {
 }
 
-const char* InputDispatcher::Connection::getWindowName() const {
+const std::string InputDispatcher::Connection::getWindowName() const {
     if (inputWindowHandle != NULL) {
-        return inputWindowHandle->getName().string();
+        return inputWindowHandle->getName();
     }
     if (monitor) {
         return "monitor";
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 90c69ce..8da8450 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -24,7 +24,6 @@
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Looper.h>
 #include <utils/BitSet.h>
 #include <cutils/atomic.h>
@@ -209,7 +208,7 @@
      * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
             const sp<InputWindowHandle>& inputWindowHandle,
-            const String8& reason) = 0;
+            const std::string& reason) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
@@ -281,7 +280,7 @@
     /* Dumps the state of the input dispatcher.
      *
      * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
     virtual void monitor() = 0;
@@ -373,7 +372,7 @@
 public:
     explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
     virtual void dispatchOnce();
@@ -446,7 +445,7 @@
 
         void release();
 
-        virtual void appendDescription(String8& msg) const = 0;
+        virtual void appendDescription(std::string& msg) const = 0;
 
     protected:
         EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags);
@@ -456,7 +455,7 @@
 
     struct ConfigurationChangedEntry : EventEntry {
         explicit ConfigurationChangedEntry(nsecs_t eventTime);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~ConfigurationChangedEntry();
@@ -466,7 +465,7 @@
         int32_t deviceId;
 
         DeviceResetEntry(nsecs_t eventTime, int32_t deviceId);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~DeviceResetEntry();
@@ -498,7 +497,7 @@
                 int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
                 int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
                 int32_t repeatCount, nsecs_t downTime);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
         void recycle();
 
     protected:
@@ -531,7 +530,7 @@
                 int32_t displayId, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
                 float xOffset, float yOffset);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~MotionEntry();
@@ -602,7 +601,7 @@
         KeyEntry* keyEntry;
         sp<InputApplicationHandle> inputApplicationHandle;
         sp<InputWindowHandle> inputWindowHandle;
-        String8 reason;
+        std::string reason;
         int32_t userActivityEventType;
         uint32_t seq;
         bool handled;
@@ -832,9 +831,9 @@
         explicit Connection(const sp<InputChannel>& inputChannel,
                 const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
 
-        inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
+        inline const std::string getInputChannelName() const { return inputChannel->getName(); }
 
-        const char* getWindowName() const;
+        const std::string getWindowName() const;
         const char* getStatusLabel() const;
 
         DispatchEntry* findWaitQueueEntry(uint32_t seq);
@@ -994,7 +993,7 @@
     sp<InputApplicationHandle> mFocusedApplicationHandle;
 
     // Dispatcher state at time of last ANR.
-    String8 mLastANRState;
+    std::string mLastANRState;
 
     // Dispatch inbound events.
     bool dispatchConfigurationChangedLocked(
@@ -1055,10 +1054,10 @@
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
             int32_t x, int32_t y) const;
     bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
-    String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+    std::string getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
 
-    String8 checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
+    std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
             const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
             const char* targetType);
 
@@ -1096,7 +1095,7 @@
     void resetAndDropEverythingLocked(const char* reason);
 
     // Dump state.
-    void dumpDispatchStateLocked(String8& dump);
+    void dumpDispatchStateLocked(std::string& dump);
     void logDispatchStateLocked();
 
     // Registration.
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 2ee222b..520fea4 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -69,13 +69,15 @@
 NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
         uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+        int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp,
+        uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime) :
         eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
+        edgeFlags(edgeFlags), displayId(displayId), deviceTimestamp(deviceTimestamp),
+        pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -88,7 +90,8 @@
         policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount),
+        edgeFlags(other.edgeFlags), displayId(other.displayId),
+        deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index ea3dd1c..77afb34 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -90,6 +90,13 @@
     int32_t buttonState;
     int32_t edgeFlags;
     int32_t displayId;
+    /**
+     * A timestamp in the input device's time base, not the platform's.
+     * The units are microseconds since the last reset.
+     * This can only be compared to other device timestamps from the same device.
+     * This value will overflow after a little over an hour.
+     */
+    uint32_t deviceTimestamp;
     uint32_t pointerCount;
     PointerProperties pointerProperties[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
@@ -102,7 +109,7 @@
     NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
             int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+            int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
 
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index d4266f6..0b7e850 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -54,6 +54,7 @@
 
 #include <log/log.h>
 
+#include <android-base/stringprintf.h>
 #include <input/Keyboard.h>
 #include <input/VirtualKeyMap.h>
 
@@ -63,6 +64,8 @@
 #define INDENT4 "        "
 #define INDENT5 "          "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 // --- Constants ---
@@ -290,19 +293,19 @@
     mVirtualDisplays = viewports;
 }
 
-void InputReaderConfiguration::dump(String8& dump) const {
-    dump.append(INDENT4 "ViewportInternal:\n");
+void InputReaderConfiguration::dump(std::string& dump) const {
+    dump += INDENT4 "ViewportInternal:\n";
     dumpViewport(dump, mInternalDisplay);
-    dump.append(INDENT4 "ViewportExternal:\n");
+    dump += INDENT4 "ViewportExternal:\n";
     dumpViewport(dump, mExternalDisplay);
-    dump.append(INDENT4 "ViewportVirtual:\n");
+    dump += INDENT4 "ViewportVirtual:\n";
     for (const DisplayViewport& viewport : mVirtualDisplays) {
         dumpViewport(dump, viewport);
     }
 }
 
-void InputReaderConfiguration::dumpViewport(String8& dump, const DisplayViewport& viewport) const {
-    dump.appendFormat(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
+void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const {
+    dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
             "logicalFrame=[%d, %d, %d, %d], "
             "physicalFrame=[%d, %d, %d, %d], "
             "deviceSize=[%d, %d]\n",
@@ -429,7 +432,7 @@
                 batchSize += 1;
             }
 #if DEBUG_RAW_EVENTS
-            ALOGD("BatchSize: %d Count: %d", batchSize, count);
+            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
 #endif
             processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
         } else {
@@ -873,71 +876,71 @@
     return false;
 }
 
-void InputReader::dump(String8& dump) {
+void InputReader::dump(std::string& dump) {
     AutoMutex _l(mLock);
 
     mEventHub->dump(dump);
-    dump.append("\n");
+    dump += "\n";
 
-    dump.append("Input Reader State:\n");
+    dump += "Input Reader State:\n";
 
     for (size_t i = 0; i < mDevices.size(); i++) {
         mDevices.valueAt(i)->dump(dump);
     }
 
-    dump.append(INDENT "Configuration:\n");
-    dump.append(INDENT2 "ExcludedDeviceNames: [");
+    dump += INDENT "Configuration:\n";
+    dump += INDENT2 "ExcludedDeviceNames: [";
     for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
         if (i != 0) {
-            dump.append(", ");
+            dump += ", ";
         }
-        dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
+        dump += mConfig.excludedDeviceNames.itemAt(i).string();
     }
-    dump.append("]\n");
-    dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
+    dump += "]\n";
+    dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
             mConfig.virtualKeyQuietTime * 0.000001f);
 
-    dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
+    dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: "
             "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
             mConfig.pointerVelocityControlParameters.scale,
             mConfig.pointerVelocityControlParameters.lowThreshold,
             mConfig.pointerVelocityControlParameters.highThreshold,
             mConfig.pointerVelocityControlParameters.acceleration);
 
-    dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
+    dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: "
             "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
             mConfig.wheelVelocityControlParameters.scale,
             mConfig.wheelVelocityControlParameters.lowThreshold,
             mConfig.wheelVelocityControlParameters.highThreshold,
             mConfig.wheelVelocityControlParameters.acceleration);
 
-    dump.appendFormat(INDENT2 "PointerGesture:\n");
-    dump.appendFormat(INDENT3 "Enabled: %s\n",
+    dump += StringPrintf(INDENT2 "PointerGesture:\n");
+    dump += StringPrintf(INDENT3 "Enabled: %s\n",
             toString(mConfig.pointerGesturesEnabled));
-    dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n",
             mConfig.pointerGestureQuietInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
+    dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
             mConfig.pointerGestureDragMinSwitchSpeed);
-    dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n",
             mConfig.pointerGestureTapInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n",
             mConfig.pointerGestureTapDragInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
+    dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n",
             mConfig.pointerGestureTapSlop);
-    dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
             mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
+    dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
             mConfig.pointerGestureMultitouchMinDistance);
-    dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
+    dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
             mConfig.pointerGestureSwipeTransitionAngleCosine);
-    dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
             mConfig.pointerGestureSwipeMaxWidthRatio);
-    dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n",
             mConfig.pointerGestureMovementSpeedRatio);
-    dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n",
             mConfig.pointerGestureZoomSpeedRatio);
 
-    dump.append(INDENT3 "Viewports:\n");
+    dump += INDENT3 "Viewports:\n";
     mConfig.dump(dump);
 }
 
@@ -1069,21 +1072,21 @@
     bumpGeneration();
 }
 
-void InputDevice::dump(String8& dump) {
+void InputDevice::dump(std::string& dump) {
     InputDeviceInfo deviceInfo;
     getDeviceInfo(& deviceInfo);
 
-    dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
+    dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
             deviceInfo.getDisplayName().string());
-    dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
-    dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
-    dump.appendFormat(INDENT2 "HasMic:     %s\n", toString(mHasMic));
-    dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
-    dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+    dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
+    dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
+    dump += StringPrintf(INDENT2 "HasMic:     %s\n", toString(mHasMic));
+    dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+    dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     if (!ranges.isEmpty()) {
-        dump.append(INDENT2 "Motion Ranges:\n");
+        dump += INDENT2 "Motion Ranges:\n";
         for (size_t i = 0; i < ranges.size(); i++) {
             const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
             const char* label = getAxisLabel(range.axis);
@@ -1094,7 +1097,7 @@
             } else {
                 snprintf(name, sizeof(name), "%d", range.axis);
             }
-            dump.appendFormat(INDENT3 "%s: source=0x%08x, "
+            dump += StringPrintf(INDENT3 "%s: source=0x%08x, "
                     "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
                     name, range.source, range.min, range.max, range.flat, range.fuzz,
                     range.resolution);
@@ -1174,9 +1177,9 @@
     // gamepad button presses are handled by different mappers but they should be dispatched
     // in the order received.
     size_t numMappers = mMappers.size();
-    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
+    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
 #if DEBUG_RAW_EVENTS
-        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
+        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
                 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
                 rawEvent->when);
 #endif
@@ -1202,6 +1205,7 @@
                 mapper->process(rawEvent);
             }
         }
+        --count;
     }
 }
 
@@ -1783,7 +1787,7 @@
 
 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
         mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
-        mHaveStylus(false) {
+        mHaveStylus(false), mDeviceTimestamp(0) {
 }
 
 MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
@@ -1824,6 +1828,7 @@
     } else {
         clearSlots(-1);
     }
+    mDeviceTimestamp = 0;
 }
 
 void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
@@ -1851,7 +1856,7 @@
 #if DEBUG_POINTERS
             if (newSlot) {
                 ALOGW("MultiTouch device emitted invalid slot index %d but it "
-                        "should be between 0 and %d; ignoring this slot.",
+                        "should be between 0 and %zd; ignoring this slot.",
                         mCurrentSlot, mSlotCount - 1);
             }
 #endif
@@ -1917,6 +1922,8 @@
     } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
         // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
         mCurrentSlot += 1;
+    } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
+        mDeviceTimestamp = rawEvent->value;
     }
 }
 
@@ -1981,7 +1988,7 @@
     info->addSource(getSources());
 }
 
-void InputMapper::dump(String8& dump) {
+void InputMapper::dump(std::string& dump) {
 }
 
 void InputMapper::configure(nsecs_t when,
@@ -2043,21 +2050,21 @@
     mDevice->bumpGeneration();
 }
 
-void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
+void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump,
         const RawAbsoluteAxisInfo& axis, const char* name) {
     if (axis.valid) {
-        dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
+        dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
                 name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
     } else {
-        dump.appendFormat(INDENT4 "%s: unknown range\n", name);
+        dump += StringPrintf(INDENT4 "%s: unknown range\n", name);
     }
 }
 
-void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
-    dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
-    dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
-    dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
-    dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
+void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) {
+    dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when);
+    dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure);
+    dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons);
+    dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
 }
 
 // --- SwitchInputMapper ---
@@ -2111,9 +2118,9 @@
     return getEventHub()->getSwitchState(getDeviceId(), switchCode);
 }
 
-void SwitchInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Switch Input Mapper:\n");
-    dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues);
+void SwitchInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Switch Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues);
 }
 
 // --- VibratorInputMapper ---
@@ -2142,15 +2149,15 @@
 void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
         int32_t token) {
 #if DEBUG_VIBRATOR
-    String8 patternStr;
+    std::string patternStr;
     for (size_t i = 0; i < patternSize; i++) {
         if (i != 0) {
-            patternStr.append(", ");
+            patternStr += ", ";
         }
-        patternStr.appendFormat("%lld", pattern[i]);
+        patternStr += StringPrintf("%" PRId64, pattern[i]);
     }
-    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
-            getDeviceId(), patternStr.string(), repeat, token);
+    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d",
+            getDeviceId(), patternStr.c_str(), repeat, token);
 #endif
 
     mVibrating = true;
@@ -2198,8 +2205,7 @@
     nsecs_t duration = mPattern[mIndex];
     if (vibratorOn) {
 #if DEBUG_VIBRATOR
-        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
-                getDeviceId(), duration);
+        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
 #endif
         getEventHub()->vibrate(getDeviceId(), duration);
     } else {
@@ -2224,9 +2230,9 @@
     getEventHub()->cancelVibrate(getDeviceId());
 }
 
-void VibratorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Vibrator Input Mapper:\n");
-    dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
+void VibratorInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Vibrator Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
 }
 
 
@@ -2252,14 +2258,14 @@
     info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
 }
 
-void KeyboardInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Keyboard Input Mapper:\n");
+void KeyboardInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Keyboard Input Mapper:\n";
     dumpParameters(dump);
-    dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
-    dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
-    dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
+    dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
+    dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+    dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
+    dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
+    dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
 }
 
 
@@ -2319,13 +2325,13 @@
             mParameters.handlesKeyRepeat);
 }
 
-void KeyboardInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+void KeyboardInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
+    dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
             toString(mParameters.hasAssociatedDisplay));
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
-    dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n",
+    dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n",
             toString(mParameters.handlesKeyRepeat));
 }
 
@@ -2604,23 +2610,23 @@
     }
 }
 
-void CursorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Cursor Input Mapper:\n");
+void CursorInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Cursor Input Mapper:\n";
     dumpParameters(dump);
-    dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
+    dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale);
+    dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale);
+    dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
+    dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
+    dump += StringPrintf(INDENT3 "HaveVWheel: %s\n",
             toString(mCursorScrollAccumulator.haveRelativeVWheel()));
-    dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
+    dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
             toString(mCursorScrollAccumulator.haveRelativeHWheel()));
-    dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
-    dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
-    dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
-    dump.appendFormat(INDENT3 "DownTime: %lld\n", (long long)mDownTime);
+    dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
+    dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
+    dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+    dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
+    dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
+    dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
 }
 
 void CursorInputMapper::configure(nsecs_t when,
@@ -2728,26 +2734,26 @@
     }
 }
 
-void CursorInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+void CursorInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
+    dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
             toString(mParameters.hasAssociatedDisplay));
 
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
-        dump.append(INDENT4 "Mode: pointer\n");
+        dump += INDENT4 "Mode: pointer\n";
         break;
     case Parameters::MODE_POINTER_RELATIVE:
-        dump.append(INDENT4 "Mode: relative pointer\n");
+        dump += INDENT4 "Mode: relative pointer\n";
         break;
     case Parameters::MODE_NAVIGATION:
-        dump.append(INDENT4 "Mode: navigation\n");
+        dump += INDENT4 "Mode: navigation\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
 
@@ -2891,7 +2897,7 @@
                 NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        displayId, 1, &pointerProperties, &pointerCoords,
+                        displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime);
                 getListener()->notifyMotion(&releaseArgs);
             }
@@ -2900,7 +2906,7 @@
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 motionEventAction, 0, 0, metaState, currentButtonState,
                 AMOTION_EVENT_EDGE_FLAG_NONE,
-                displayId, 1, &pointerProperties, &pointerCoords,
+                displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime);
         getListener()->notifyMotion(&args);
 
@@ -2912,7 +2918,7 @@
                 NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        displayId, 1, &pointerProperties, &pointerCoords,
+                        displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime);
                 getListener()->notifyMotion(&pressArgs);
             }
@@ -2926,7 +2932,7 @@
             NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                     metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, 1, &pointerProperties, &pointerCoords,
+                    displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&hoverArgs);
         }
@@ -2939,7 +2945,7 @@
             NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, 1, &pointerProperties, &pointerCoords,
+                    displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&scrollArgs);
         }
@@ -3000,9 +3006,9 @@
     }
 }
 
-void RotaryEncoderInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Rotary Encoder Input Mapper:\n");
-    dump.appendFormat(INDENT3 "HaveWheel: %s\n",
+void RotaryEncoderInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Rotary Encoder Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "HaveWheel: %s\n",
             toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
 }
 
@@ -3069,7 +3075,7 @@
         NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
                 AMOTION_EVENT_EDGE_FLAG_NONE,
-                displayId, 1, &pointerProperties, &pointerCoords,
+                displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0);
         getListener()->notifyMotion(&scrollArgs);
     }
@@ -3083,6 +3089,7 @@
         InputMapper(device),
         mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
         mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
+        mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0),
         mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
 }
 
@@ -3151,8 +3158,8 @@
     }
 }
 
-void TouchInputMapper::dump(String8& dump) {
-    dump.appendFormat(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
+void TouchInputMapper::dump(std::string& dump) {
+    dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
     dumpParameters(dump);
     dumpVirtualKeys(dump);
     dumpRawPointerAxes(dump);
@@ -3160,30 +3167,30 @@
     dumpAffineTransformation(dump);
     dumpSurface(dump);
 
-    dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
-    dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
-    dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
-    dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
-    dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
-    dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
-    dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
-    dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
-    dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
-    dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
-    dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
-    dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
-    dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
+    dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
+    dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
+    dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
+    dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
+    dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
+    dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
+    dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
+    dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
+    dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
+    dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
+    dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
+    dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
+    dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
+    dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
+    dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
+    dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
+    dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
 
-    dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
-    dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
+    dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
+    dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
             mLastRawState.rawPointerData.pointerCount);
     for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
         const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
+        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
                 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
                 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
                 "toolType=%d, isHovering=%s\n", i,
@@ -3194,14 +3201,14 @@
                 pointer.toolType, toString(pointer.isHovering));
     }
 
-    dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
-    dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
+    dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
+    dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
             mLastCookedState.cookedPointerData.pointerCount);
     for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
         const PointerProperties& pointerProperties =
                 mLastCookedState.cookedPointerData.pointerProperties[i];
         const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
+        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
                 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
                 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
                 "toolType=%d, isHovering=%s\n", i,
@@ -3220,26 +3227,26 @@
                 toString(mLastCookedState.cookedPointerData.isHovering(i)));
     }
 
-    dump.append(INDENT3 "Stylus Fusion:\n");
-    dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
+    dump += INDENT3 "Stylus Fusion:\n";
+    dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n",
             toString(mExternalStylusConnected));
-    dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
-    dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
+    dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
+    dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
             mExternalStylusFusionTimeout);
-    dump.append(INDENT3 "External Stylus State:\n");
+    dump += INDENT3 "External Stylus State:\n";
     dumpStylusState(dump, mExternalStylusState);
 
     if (mDeviceMode == DEVICE_MODE_POINTER) {
-        dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
-        dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
+        dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
+        dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n",
                 mPointerXMovementScale);
-        dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n",
                 mPointerYMovementScale);
-        dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n",
                 mPointerXZoomScale);
-        dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n",
                 mPointerYZoomScale);
-        dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
+        dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n",
                 mPointerGestureMaxSwipeWidth);
     }
 }
@@ -3400,15 +3407,15 @@
             mParameters.wake);
 }
 
-void TouchInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
+void TouchInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
 
     switch (mParameters.gestureMode) {
     case Parameters::GESTURE_MODE_SINGLE_TOUCH:
-        dump.append(INDENT4 "GestureMode: single-touch\n");
+        dump += INDENT4 "GestureMode: single-touch\n";
         break;
     case Parameters::GESTURE_MODE_MULTI_TOUCH:
-        dump.append(INDENT4 "GestureMode: multi-touch\n");
+        dump += INDENT4 "GestureMode: multi-touch\n";
         break;
     default:
         assert(false);
@@ -3416,27 +3423,27 @@
 
     switch (mParameters.deviceType) {
     case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
-        dump.append(INDENT4 "DeviceType: touchScreen\n");
+        dump += INDENT4 "DeviceType: touchScreen\n";
         break;
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
-        dump.append(INDENT4 "DeviceType: touchPad\n");
+        dump += INDENT4 "DeviceType: touchPad\n";
         break;
     case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
-        dump.append(INDENT4 "DeviceType: touchNavigation\n");
+        dump += INDENT4 "DeviceType: touchNavigation\n";
         break;
     case Parameters::DEVICE_TYPE_POINTER:
-        dump.append(INDENT4 "DeviceType: pointer\n");
+        dump += INDENT4 "DeviceType: pointer\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(
+    dump += StringPrintf(
             INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n",
             toString(mParameters.hasAssociatedDisplay),
             toString(mParameters.associatedDisplayIsExternal),
             mParameters.uniqueDisplayId.c_str());
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
 
@@ -3444,8 +3451,8 @@
     mRawPointerAxes.clear();
 }
 
-void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
-    dump.append(INDENT3 "Raw Touch Axes:\n");
+void TouchInputMapper::dumpRawPointerAxes(std::string& dump) {
+    dump += INDENT3 "Raw Touch Axes:\n";
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
@@ -3590,6 +3597,11 @@
                 break;
             }
 
+            mPhysicalWidth = naturalPhysicalWidth;
+            mPhysicalHeight = naturalPhysicalHeight;
+            mPhysicalLeft = naturalPhysicalLeft;
+            mPhysicalTop = naturalPhysicalTop;
+
             mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
             mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
             mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
@@ -3598,6 +3610,11 @@
             mSurfaceOrientation = mParameters.orientationAware ?
                     mViewport.orientation : DISPLAY_ORIENTATION_0;
         } else {
+            mPhysicalWidth = rawWidth;
+            mPhysicalHeight = rawHeight;
+            mPhysicalLeft = 0;
+            mPhysicalTop = 0;
+
             mSurfaceWidth = rawWidth;
             mSurfaceHeight = rawHeight;
             mSurfaceLeft = 0;
@@ -3702,11 +3719,13 @@
 
         // Pressure factors.
         mPressureScale = 0;
+        float pressureMax = 1.0;
         if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
                 || mCalibration.pressureCalibration
                         == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
             if (mCalibration.havePressureScale) {
                 mPressureScale = mCalibration.pressureScale;
+                pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
             } else if (mRawPointerAxes.pressure.valid
                     && mRawPointerAxes.pressure.maxValue != 0) {
                 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
@@ -3716,7 +3735,7 @@
         mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
         mOrientedRanges.pressure.source = mSource;
         mOrientedRanges.pressure.min = 0;
-        mOrientedRanges.pressure.max = 1.0;
+        mOrientedRanges.pressure.max = pressureMax;
         mOrientedRanges.pressure.flat = 0;
         mOrientedRanges.pressure.fuzz = 0;
         mOrientedRanges.pressure.resolution = 0;
@@ -3890,8 +3909,8 @@
     }
 }
 
-void TouchInputMapper::dumpSurface(String8& dump) {
-    dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
+void TouchInputMapper::dumpSurface(std::string& dump) {
+    dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, "
             "logicalFrame=[%d, %d, %d, %d], "
             "physicalFrame=[%d, %d, %d, %d], "
             "deviceSize=[%d, %d]\n",
@@ -3902,11 +3921,15 @@
             mViewport.physicalRight, mViewport.physicalBottom,
             mViewport.deviceWidth, mViewport.deviceHeight);
 
-    dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
-    dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
-    dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
-    dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
-    dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
+    dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
+    dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
+    dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
+    dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
+    dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
+    dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
+    dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
+    dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop);
+    dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
 }
 
 void TouchInputMapper::configureVirtualKeys() {
@@ -3963,13 +3986,13 @@
     }
 }
 
-void TouchInputMapper::dumpVirtualKeys(String8& dump) {
+void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
     if (!mVirtualKeys.isEmpty()) {
-        dump.append(INDENT3 "Virtual Keys:\n");
+        dump += INDENT3 "Virtual Keys:\n";
 
         for (size_t i = 0; i < mVirtualKeys.size(); i++) {
             const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
-            dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
+            dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
                     "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
                     i, virtualKey.scanCode, virtualKey.keyCode,
                     virtualKey.hitLeft, virtualKey.hitRight,
@@ -4118,75 +4141,75 @@
     }
 }
 
-void TouchInputMapper::dumpCalibration(String8& dump) {
-    dump.append(INDENT3 "Calibration:\n");
+void TouchInputMapper::dumpCalibration(std::string& dump) {
+    dump += INDENT3 "Calibration:\n";
 
     // Size
     switch (mCalibration.sizeCalibration) {
     case Calibration::SIZE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.size.calibration: none\n");
+        dump += INDENT4 "touch.size.calibration: none\n";
         break;
     case Calibration::SIZE_CALIBRATION_GEOMETRIC:
-        dump.append(INDENT4 "touch.size.calibration: geometric\n");
+        dump += INDENT4 "touch.size.calibration: geometric\n";
         break;
     case Calibration::SIZE_CALIBRATION_DIAMETER:
-        dump.append(INDENT4 "touch.size.calibration: diameter\n");
+        dump += INDENT4 "touch.size.calibration: diameter\n";
         break;
     case Calibration::SIZE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.size.calibration: box\n");
+        dump += INDENT4 "touch.size.calibration: box\n";
         break;
     case Calibration::SIZE_CALIBRATION_AREA:
-        dump.append(INDENT4 "touch.size.calibration: area\n");
+        dump += INDENT4 "touch.size.calibration: area\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.haveSizeScale) {
-        dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n",
                 mCalibration.sizeScale);
     }
 
     if (mCalibration.haveSizeBias) {
-        dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n",
                 mCalibration.sizeBias);
     }
 
     if (mCalibration.haveSizeIsSummed) {
-        dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n",
+        dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n",
                 toString(mCalibration.sizeIsSummed));
     }
 
     // Pressure
     switch (mCalibration.pressureCalibration) {
     case Calibration::PRESSURE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.pressure.calibration: none\n");
+        dump += INDENT4 "touch.pressure.calibration: none\n";
         break;
     case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-        dump.append(INDENT4 "touch.pressure.calibration: physical\n");
+        dump += INDENT4 "touch.pressure.calibration: physical\n";
         break;
     case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
-        dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
+        dump += INDENT4 "touch.pressure.calibration: amplitude\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.havePressureScale) {
-        dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n",
                 mCalibration.pressureScale);
     }
 
     // Orientation
     switch (mCalibration.orientationCalibration) {
     case Calibration::ORIENTATION_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.orientation.calibration: none\n");
+        dump += INDENT4 "touch.orientation.calibration: none\n";
         break;
     case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
-        dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
+        dump += INDENT4 "touch.orientation.calibration: interpolated\n";
         break;
     case Calibration::ORIENTATION_CALIBRATION_VECTOR:
-        dump.append(INDENT4 "touch.orientation.calibration: vector\n");
+        dump += INDENT4 "touch.orientation.calibration: vector\n";
         break;
     default:
         ALOG_ASSERT(false);
@@ -4195,41 +4218,41 @@
     // Distance
     switch (mCalibration.distanceCalibration) {
     case Calibration::DISTANCE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.distance.calibration: none\n");
+        dump += INDENT4 "touch.distance.calibration: none\n";
         break;
     case Calibration::DISTANCE_CALIBRATION_SCALED:
-        dump.append(INDENT4 "touch.distance.calibration: scaled\n");
+        dump += INDENT4 "touch.distance.calibration: scaled\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.haveDistanceScale) {
-        dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n",
                 mCalibration.distanceScale);
     }
 
     switch (mCalibration.coverageCalibration) {
     case Calibration::COVERAGE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.coverage.calibration: none\n");
+        dump += INDENT4 "touch.coverage.calibration: none\n";
         break;
     case Calibration::COVERAGE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.coverage.calibration: box\n");
+        dump += INDENT4 "touch.coverage.calibration: box\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 }
 
-void TouchInputMapper::dumpAffineTransformation(String8& dump) {
-    dump.append(INDENT3 "Affine Transformation:\n");
+void TouchInputMapper::dumpAffineTransformation(std::string& dump) {
+    dump += INDENT3 "Affine Transformation:\n";
 
-    dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
-    dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
-    dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
-    dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
-    dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
-    dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
+    dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
+    dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
+    dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
+    dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
+    dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
+    dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
 }
 
 void TouchInputMapper::updateAffineTransformation() {
@@ -4724,6 +4747,7 @@
         int32_t buttonState = mCurrentCookedState.buttonState;
         dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                mCurrentCookedState.deviceTimestamp,
                 mCurrentCookedState.cookedPointerData.pointerProperties,
                 mCurrentCookedState.cookedPointerData.pointerCoords,
                 mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4746,6 +4770,7 @@
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4780,6 +4805,7 @@
 
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mLastCookedState.cookedPointerData.pointerProperties,
                     mLastCookedState.cookedPointerData.pointerCoords,
                     mLastCookedState.cookedPointerData.idToIndex,
@@ -4794,6 +4820,7 @@
             ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4812,6 +4839,7 @@
 
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4827,6 +4855,7 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         dispatchMotion(when, policyFlags, mSource,
                 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
+                mLastCookedState.deviceTimestamp,
                 mLastCookedState.cookedPointerData.pointerProperties,
                 mLastCookedState.cookedPointerData.pointerCoords,
                 mLastCookedState.cookedPointerData.idToIndex,
@@ -4843,6 +4872,7 @@
         if (!mSentHoverEnter) {
             dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
                     0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4854,6 +4884,7 @@
         dispatchMotion(when, policyFlags, mSource,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                 mCurrentRawState.buttonState, 0,
+                mCurrentCookedState.deviceTimestamp,
                 mCurrentCookedState.cookedPointerData.pointerProperties,
                 mCurrentCookedState.cookedPointerData.pointerCoords,
                 mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4873,6 +4904,7 @@
         dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
                     0, metaState, buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -4890,6 +4922,7 @@
         buttonState |= actionButton;
         dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
                     0, metaState, buttonState, 0,
+                    mCurrentCookedState.deviceTimestamp,
                     mCurrentCookedState.cookedPointerData.pointerProperties,
                     mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -4908,6 +4941,8 @@
     uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
 
     mCurrentCookedState.cookedPointerData.clear();
+    mCurrentCookedState.deviceTimestamp =
+            mCurrentRawState.deviceTimestamp;
     mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
     mCurrentCookedState.cookedPointerData.hoveringIdBits =
             mCurrentRawState.rawPointerData.hoveringIdBits;
@@ -5098,10 +5133,10 @@
             }
             break;
         case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale;
             y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
-            left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
-            right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
+            left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
+            right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
             bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
             top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
             orientation -= M_PI;
@@ -5110,10 +5145,10 @@
             }
             break;
         case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale;
             y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
-            right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
+            left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
+            right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
             bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             orientation += M_PI_2;
@@ -5300,7 +5335,7 @@
         if (cancelPreviousGesture) {
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                     mPointerGesture.lastGestureProperties,
                     mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
                     dispatchedGestureIdBits, -1, 0,
@@ -5321,6 +5356,7 @@
                 dispatchMotion(when, policyFlags, mSource,
                         AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        /* deviceTimestamp */ 0,
                         mPointerGesture.lastGestureProperties,
                         mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
                         dispatchedGestureIdBits, id,
@@ -5335,7 +5371,7 @@
     if (moveNeeded) {
         dispatchMotion(when, policyFlags, mSource,
                 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 mPointerGesture.currentGestureProperties,
                 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                 dispatchedGestureIdBits, -1,
@@ -5356,6 +5392,7 @@
 
             dispatchMotion(when, policyFlags, mSource,
                     AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+                    /* deviceTimestamp */ 0,
                     mPointerGesture.currentGestureProperties,
                     mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                     dispatchedGestureIdBits, id,
@@ -5367,7 +5404,7 @@
     if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
         dispatchMotion(when, policyFlags, mSource,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 mPointerGesture.currentGestureProperties,
                 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                 mPointerGesture.currentGestureIdBits, -1,
@@ -5394,7 +5431,7 @@
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                mViewport.displayId, 1, &pointerProperties, &pointerCoords,
+                mViewport.displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime);
         getListener()->notifyMotion(&args);
     }
@@ -5424,7 +5461,7 @@
         int32_t buttonState = mCurrentRawState.buttonState;
         dispatchMotion(when, policyFlags, mSource,
                 AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 mPointerGesture.lastGestureProperties,
                 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
                 mPointerGesture.lastGestureIdBits, -1,
@@ -5509,18 +5546,15 @@
     // Otherwise choose an arbitrary remaining pointer.
     // This guarantees we always have an active touch id when there is at least one pointer.
     // We keep the same active touch id for as long as possible.
-    bool activeTouchChanged = false;
     int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
     int32_t activeTouchId = lastActiveTouchId;
     if (activeTouchId < 0) {
         if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
-            activeTouchChanged = true;
             activeTouchId = mPointerGesture.activeTouchId =
                     mCurrentCookedState.fingerIdBits.firstMarkedBit();
             mPointerGesture.firstTouchTime = when;
         }
     } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
-        activeTouchChanged = true;
         if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
             activeTouchId = mPointerGesture.activeTouchId =
                     mCurrentCookedState.fingerIdBits.firstMarkedBit();
@@ -5616,7 +5650,6 @@
             }
             if (bestId >= 0 && bestId != activeTouchId) {
                 mPointerGesture.activeTouchId = activeTouchId = bestId;
-                activeTouchChanged = true;
 #if DEBUG_GESTURES
                 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
                         "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
@@ -6320,7 +6353,7 @@
         // Send up.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                  AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                 mViewport.displayId,
+                 mViewport.displayId, /* deviceTimestamp */ 0,
                  1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                  mOrientedXPrecision, mOrientedYPrecision,
                  mPointerSimple.downTime);
@@ -6333,7 +6366,7 @@
         // Send hover exit.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                mViewport.displayId,
+                mViewport.displayId, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6348,7 +6381,7 @@
             // Send down.
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                    mViewport.displayId,
+                    mViewport.displayId, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -6358,7 +6391,7 @@
         // Send move.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                mViewport.displayId,
+                mViewport.displayId, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6373,7 +6406,7 @@
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
                     mCurrentRawState.buttonState, 0,
-                    mViewport.displayId,
+                    mViewport.displayId, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -6384,7 +6417,7 @@
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                 mCurrentRawState.buttonState, 0,
-                mViewport.displayId,
+                mViewport.displayId, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6405,7 +6438,7 @@
 
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                mViewport.displayId,
+                mViewport.displayId, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6430,7 +6463,7 @@
 
 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
         int32_t action, int32_t actionButton, int32_t flags,
-        int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+        int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
         const PointerProperties* properties, const PointerCoords* coords,
         const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
         float xPrecision, float yPrecision, nsecs_t downTime) {
@@ -6468,7 +6501,7 @@
 
     NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
             action, actionButton, flags, metaState, buttonState, edgeFlags,
-            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
+            mViewport.displayId, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime);
     getListener()->notifyMotion(&args);
 }
@@ -6513,8 +6546,12 @@
 }
 
 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+    const float scaledX = x * mXScale;
+    const float scaledY = y * mYScale;
     return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
-            && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
+            && scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth
+            && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue
+            && scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight;
 }
 
 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
@@ -6631,7 +6668,7 @@
 #if DEBUG_POINTER_ASSIGNMENT
     ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
     for (size_t i = 0; i < heapSize; i++) {
-        ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+        ALOGD("  heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
                 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
                 heap[i].distance);
     }
@@ -6677,7 +6714,7 @@
 #if DEBUG_POINTER_ASSIGNMENT
                 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
                 for (size_t i = 0; i < heapSize; i++) {
-                    ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                    ALOGD("  heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
                             i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
                             heap[i].distance);
                 }
@@ -6703,7 +6740,8 @@
             usedIdBits.markBit(id);
 
 #if DEBUG_POINTER_ASSIGNMENT
-            ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+            ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32
+                    ", id=%" PRIu32 ", distance=%" PRIu64,
                     lastPointerIndex, currentPointerIndex, id, heap[0].distance);
 #endif
             break;
@@ -6721,8 +6759,7 @@
                 current->rawPointerData.isHovering(currentPointerIndex));
 
 #if DEBUG_POINTER_ASSIGNMENT
-        ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
-                currentPointerIndex, id);
+        ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id);
 #endif
     }
 }
@@ -6948,6 +6985,7 @@
         outCount += 1;
     }
 
+    outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp();
     outState->rawPointerData.pointerCount = outCount;
     mPointerIdBits = newPointerIdBits;
 
@@ -7009,11 +7047,11 @@
             0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
 }
 
-void ExternalStylusInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "External Stylus Input Mapper:\n");
-    dump.append(INDENT3 "Raw Stylus Axes:\n");
+void ExternalStylusInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "External Stylus Input Mapper:\n";
+    dump += INDENT3 "Raw Stylus Axes:\n";
     dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
-    dump.append(INDENT3 "Stylus State:\n");
+    dump += INDENT3 "Stylus State:\n";
     dumpStylusState(dump, mStylusState);
 }
 
@@ -7118,37 +7156,37 @@
     return -1;
 }
 
-void JoystickInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Joystick Input Mapper:\n");
+void JoystickInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Joystick Input Mapper:\n";
 
-    dump.append(INDENT3 "Axes:\n");
+    dump += INDENT3 "Axes:\n";
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
         const Axis& axis = mAxes.valueAt(i);
         const char* label = getAxisLabel(axis.axisInfo.axis);
         if (label) {
-            dump.appendFormat(INDENT4 "%s", label);
+            dump += StringPrintf(INDENT4 "%s", label);
         } else {
-            dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
+            dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis);
         }
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
             label = getAxisLabel(axis.axisInfo.highAxis);
             if (label) {
-                dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
+                dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue);
             } else {
-                dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
+                dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis,
                         axis.axisInfo.splitValue);
             }
         } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
-            dump.append(" (invert)");
+            dump += " (invert)";
         }
 
-        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
+        dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
                 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
-        dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
+        dump += StringPrintf(INDENT4 "  scale=%0.5f, offset=%0.5f, "
                 "highScale=%0.5f, highOffset=%0.5f\n",
                 axis.scale, axis.offset, axis.highScale, axis.highOffset);
-        dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
+        dump += StringPrintf(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
                 "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
                 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
                 axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
@@ -7387,7 +7425,8 @@
 
     NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
             AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
+            ADISPLAY_ID_NONE, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+            0, 0, 0);
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index a6b9798..2f98e69 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -32,7 +32,6 @@
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/BitSet.h>
 #include <utils/SortedVector.h>
 
@@ -207,8 +206,8 @@
     void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
 
 
-    void dump(String8& dump) const;
-    void dumpViewport(String8& dump, const DisplayViewport& viewport) const;
+    void dump(std::string& dump) const;
+    void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
 
 private:
     DisplayViewport mInternalDisplay;
@@ -292,7 +291,7 @@
     /* Dumps the state of the input reader.
      *
      * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
@@ -412,7 +411,7 @@
             const sp<InputListenerInterface>& listener);
     virtual ~InputReader();
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
     virtual void loopOnce();
@@ -569,7 +568,7 @@
     bool isEnabled();
     void setEnabled(bool enabled, nsecs_t when);
 
-    void dump(String8& dump);
+    void dump(std::string& dump);
     void addMapper(InputMapper* mapper);
     void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     void reset(nsecs_t when);
@@ -948,6 +947,7 @@
 
     inline size_t getSlotCount() const { return mSlotCount; }
     inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+    inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; }
 
 private:
     int32_t mCurrentSlot;
@@ -955,6 +955,7 @@
     size_t mSlotCount;
     bool mUsingSlotsProtocol;
     bool mHaveStylus;
+    uint32_t mDeviceTimestamp;
 
     void clearSlots(int32_t initialSlot);
 };
@@ -987,7 +988,7 @@
 
     virtual uint32_t getSources() = 0;
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent) = 0;
@@ -1017,9 +1018,9 @@
     status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo);
     void bumpGeneration();
 
-    static void dumpRawAbsoluteAxisInfo(String8& dump,
+    static void dumpRawAbsoluteAxisInfo(std::string& dump,
             const RawAbsoluteAxisInfo& axis, const char* name);
-    static void dumpStylusState(String8& dump, const StylusState& state);
+    static void dumpStylusState(std::string& dump, const StylusState& state);
 };
 
 
@@ -1032,7 +1033,7 @@
     virtual void process(const RawEvent* rawEvent);
 
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
 
 private:
     uint32_t mSwitchValues;
@@ -1056,7 +1057,7 @@
             int32_t token);
     virtual void cancelVibrate(int32_t token);
     virtual void timeoutExpired(nsecs_t when);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
 
 private:
     bool mVibrating;
@@ -1079,7 +1080,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1125,7 +1126,7 @@
     } mParameters;
 
     void configureParameters();
-    void dumpParameters(String8& dump);
+    void dumpParameters(std::string& dump);
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
     bool isMediaKey(int32_t keyCode);
@@ -1151,7 +1152,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1204,7 +1205,7 @@
     nsecs_t mDownTime;
 
     void configureParameters();
-    void dumpParameters(String8& dump);
+    void dumpParameters(std::string& dump);
 
     void sync(nsecs_t when);
 };
@@ -1217,7 +1218,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1239,7 +1240,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1397,6 +1398,7 @@
 
     struct RawState {
         nsecs_t when;
+        uint32_t deviceTimestamp;
 
         // Raw pointer sample data.
         RawPointerData rawPointerData;
@@ -1409,6 +1411,7 @@
 
         void copyFrom(const RawState& other) {
             when = other.when;
+            deviceTimestamp = other.deviceTimestamp;
             rawPointerData.copyFrom(other.rawPointerData);
             buttonState = other.buttonState;
             rawVScroll = other.rawVScroll;
@@ -1417,6 +1420,7 @@
 
         void clear() {
             when = 0;
+            deviceTimestamp = 0;
             rawPointerData.clear();
             buttonState = 0;
             rawVScroll = 0;
@@ -1425,6 +1429,7 @@
     };
 
     struct CookedState {
+        uint32_t deviceTimestamp;
         // Cooked pointer sample data.
         CookedPointerData cookedPointerData;
 
@@ -1436,6 +1441,7 @@
         int32_t buttonState;
 
         void copyFrom(const CookedState& other) {
+            deviceTimestamp = other.deviceTimestamp;
             cookedPointerData.copyFrom(other.cookedPointerData);
             fingerIdBits = other.fingerIdBits;
             stylusIdBits = other.stylusIdBits;
@@ -1444,6 +1450,7 @@
         }
 
         void clear() {
+            deviceTimestamp = 0;
             cookedPointerData.clear();
             fingerIdBits.clear();
             stylusIdBits.clear();
@@ -1482,18 +1489,18 @@
     Vector<VirtualKey> mVirtualKeys;
 
     virtual void configureParameters();
-    virtual void dumpParameters(String8& dump);
+    virtual void dumpParameters(std::string& dump);
     virtual void configureRawPointerAxes();
-    virtual void dumpRawPointerAxes(String8& dump);
+    virtual void dumpRawPointerAxes(std::string& dump);
     virtual void configureSurface(nsecs_t when, bool* outResetNeeded);
-    virtual void dumpSurface(String8& dump);
+    virtual void dumpSurface(std::string& dump);
     virtual void configureVirtualKeys();
-    virtual void dumpVirtualKeys(String8& dump);
+    virtual void dumpVirtualKeys(std::string& dump);
     virtual void parseCalibration();
     virtual void resolveCalibration();
-    virtual void dumpCalibration(String8& dump);
+    virtual void dumpCalibration(std::string& dump);
     virtual void updateAffineTransformation();
-    virtual void dumpAffineTransformation(String8& dump);
+    virtual void dumpAffineTransformation(std::string& dump);
     virtual void resolveExternalStylusPresence();
     virtual bool hasStylus() const = 0;
     virtual bool hasExternalStylus() const;
@@ -1510,13 +1517,21 @@
     // in the natural orientation.
     // The surface origin specifies how the surface coordinates should be translated
     // to align with the logical display coordinate space.
-    // The orientation may be different from the viewport orientation as it specifies
-    // the rotation of the surface coordinates required to produce the viewport's
-    // requested orientation, so it will depend on whether the device is orientation aware.
     int32_t mSurfaceWidth;
     int32_t mSurfaceHeight;
     int32_t mSurfaceLeft;
     int32_t mSurfaceTop;
+
+    // Similar to the surface coordinates, but in the raw display coordinate space rather than in
+    // the logical coordinate space.
+    int32_t mPhysicalWidth;
+    int32_t mPhysicalHeight;
+    int32_t mPhysicalLeft;
+    int32_t mPhysicalTop;
+
+    // The orientation may be different from the viewport orientation as it specifies
+    // the rotation of the surface coordinates required to produce the viewport's
+    // requested orientation, so it will depend on whether the device is orientation aware.
     int32_t mSurfaceOrientation;
 
     // Translation and scaling factors, orientation-independent.
@@ -1838,6 +1853,7 @@
     void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
             int32_t action, int32_t actionButton,
             int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+            uint32_t deviceTimestamp,
             const PointerProperties* properties, const PointerCoords* coords,
             const uint32_t* idToIndex, BitSet32 idBits,
             int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
@@ -1904,7 +1920,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1926,7 +1942,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 9eb2798..5a48375 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -23,7 +23,6 @@
 #include <ui/Region.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <utils/String8.h>
 
 #include "InputApplication.h"
 
@@ -116,7 +115,7 @@
     };
 
     sp<InputChannel> inputChannel;
-    String8 name;
+    std::string name;
     int32_t layoutParamsFlags;
     int32_t layoutParamsType;
     nsecs_t dispatchingTimeout;
@@ -173,8 +172,8 @@
         return mInfo ? mInfo->inputChannel : NULL;
     }
 
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
+    inline std::string getName() const {
+        return mInfo ? mInfo->name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index b8e9bce..775dbdc 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -32,6 +32,8 @@
     ],
 
     cflags: [
+        "-Wall",
+        "-Werror",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
@@ -47,6 +49,8 @@
 
     srcs: ["main.cpp"],
 
+    cflags: ["-Wall", "-Werror"],
+
     shared_libs: [
         "libbinder",
         "libinputflingerhost",
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 29d93f0..b1d5e61 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -7,15 +7,18 @@
         "InputDispatcher_test.cpp",
     ],
     test_per_src: true,
-    cflags: ["-Wno-unused-parameter"],
-    shared_libs = [
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    shared_libs: [
         "libcutils",
         "liblog",
         "libutils",
         "libhardware",
         "libhardware_legacy",
         "libui",
-        "libskia",
         "libinput",
         "libinputflinger",
         "libinputservice",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7ae36d8..aa6df24 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -54,7 +54,7 @@
 
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&,
             const sp<InputWindowHandle>&,
-            const String8&) {
+            const std::string&) {
         return 0;
     }
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 76291a5..22f15a0 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -798,7 +798,7 @@
         return false;
     }
 
-    virtual void dump(String8&) {
+    virtual void dump(std::string&) {
     }
 
     virtual void monitor() {
@@ -2954,8 +2954,8 @@
 const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
 const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
 const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = 0;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = 255;
 const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7;
 const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
 const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0;
@@ -4384,6 +4384,7 @@
     void processSlot(MultiTouchInputMapper* mapper, int32_t slot);
     void processToolType(MultiTouchInputMapper* mapper, int32_t toolType);
     void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value);
+    void processTimestamp(MultiTouchInputMapper* mapper, uint32_t value);
     void processMTSync(MultiTouchInputMapper* mapper);
     void processSync(MultiTouchInputMapper* mapper);
 };
@@ -4499,6 +4500,10 @@
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value);
 }
 
+void MultiTouchInputMapperTest::processTimestamp(MultiTouchInputMapper* mapper, uint32_t value) {
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_TIMESTAMP, value);
+}
+
 void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) {
     process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0);
 }
@@ -5316,6 +5321,12 @@
     addConfigurationProperty("touch.pressure.scale", "0.01");
     addMapperAndConfigure(mapper);
 
+    InputDeviceInfo info;
+    mapper->populateDeviceInfo(&info);
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN,
+            0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f));
+
     // These calculations are based on the input device calibration documentation.
     int32_t rawX = 100;
     int32_t rawY = 200;
@@ -5875,5 +5886,63 @@
             toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
 }
 
+TEST_F(MultiTouchInputMapperTest, Process_HandlesTimestamp) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION);
+    addMapperAndConfigure(mapper);
+    NotifyMotionArgs args;
+
+    // By default, deviceTimestamp should be zero
+    processPosition(mapper, 100, 100);
+    processMTSync(mapper);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(0U, args.deviceTimestamp);
+
+    // Now the timestamp of 1000 is reported by evdev and should appear in MotionArgs
+    processPosition(mapper, 0, 0);
+    processTimestamp(mapper, 1000);
+    processMTSync(mapper);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(1000U, args.deviceTimestamp);
+}
+
+TEST_F(MultiTouchInputMapperTest, WhenMapperIsReset_TimestampIsCleared) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION);
+    addMapperAndConfigure(mapper);
+    NotifyMotionArgs args;
+
+    // Send a touch event with a timestamp
+    processPosition(mapper, 100, 100);
+    processTimestamp(mapper, 1);
+    processMTSync(mapper);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(1U, args.deviceTimestamp);
+
+    // Since the data accumulates, and new timestamp has not arrived, deviceTimestamp won't change
+    processPosition(mapper, 100, 200);
+    processMTSync(mapper);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(1U, args.deviceTimestamp);
+
+    mapper->reset(/* when */ 0);
+    // After the mapper is reset, deviceTimestamp should become zero again
+    processPosition(mapper, 100, 300);
+    processMTSync(mapper);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(0U, args.deviceTimestamp);
+}
+
 
 } // namespace android
diff --git a/services/media/arcvideobridge/Android.bp b/services/media/arcvideobridge/Android.bp
new file mode 100644
index 0000000..ca5b896
--- /dev/null
+++ b/services/media/arcvideobridge/Android.bp
@@ -0,0 +1,28 @@
+cc_library_shared {
+    name: "libarcvideobridge",
+    product_variables: {
+        arc: {
+            srcs: [
+                "IArcVideoBridge.cpp",
+            ],
+            shared_libs: [
+                "libarcbridge",
+                "libarcbridgeservice",
+                "libbinder",
+                "libchrome",
+                "liblog",
+                "libmojo",
+                "libutils",
+            ],
+            cflags: [
+                "-Wall",
+                "-Werror",
+                "-Wunused",
+                "-Wunreachable-code",
+            ],
+            include_dirs: [
+                "frameworks/native/include/media/arcvideobridge",
+            ]
+        }
+    }
+}
diff --git a/services/media/arcvideobridge/IArcVideoBridge.cpp b/services/media/arcvideobridge/IArcVideoBridge.cpp
new file mode 100644
index 0000000..468b76b
--- /dev/null
+++ b/services/media/arcvideobridge/IArcVideoBridge.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IArcVideoBridge"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "IArcVideoBridge.h"
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android {
+
+enum {
+    BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY = IBinder::FIRST_CALL_TRANSACTION,
+    HOST_VERSION,
+};
+
+class BpArcVideoBridge : public BpInterface<IArcVideoBridge> {
+public:
+    BpArcVideoBridge(const sp<IBinder>& impl) : BpInterface<IArcVideoBridge>(impl) { }
+
+    virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() {
+        Parcel data, reply;
+        ALOGV("bootstrapVideoAcceleratorFactory");
+        data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
+        status_t status = remote()->transact(
+                BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY, data, &reply, 0);
+        if (status != 0) {
+            ALOGE("transact failed: %d", status);
+            return arc::MojoBootstrapResult();
+        }
+        return arc::MojoBootstrapResult::createFromParcel(reply);
+    }
+
+    virtual int32_t hostVersion() {
+        Parcel data, reply;
+        ALOGV("hostVersion");
+        data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
+        status_t status = remote()->transact(HOST_VERSION, data, &reply, 0);
+        if (status != 0) {
+            ALOGE("transact failed: %d", status);
+            return false;
+        }
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(ArcVideoBridge, "android.os.IArcVideoBridge");
+
+status_t BnArcVideoBridge::onTransact(
+        uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+    switch(code) {
+        case BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY: {
+            ALOGV("BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY");
+            CHECK_INTERFACE(IArcVideoBridge, data, reply);
+            arc::MojoBootstrapResult result = bootstrapVideoAcceleratorFactory();
+            return result.writeToParcel(reply);
+        }
+        case HOST_VERSION: {
+            ALOGV("HOST_VERSION");
+            CHECK_INTERFACE(IArcVideoBridge, data, reply);
+            reply->writeInt32(hostVersion());
+            return OK;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}  // namespace android
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index ca91b8e..0227164 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -3,6 +3,7 @@
     srcs: [
         "SchedulingPolicyService.cpp",
     ],
+    cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libhidlbase",
         "libhidltransport",
diff --git a/services/schedulerservice/SchedulingPolicyService.cpp b/services/schedulerservice/SchedulingPolicyService.cpp
index 1f6ed57..a1106cf 100644
--- a/services/schedulerservice/SchedulingPolicyService.cpp
+++ b/services/schedulerservice/SchedulingPolicyService.cpp
@@ -17,6 +17,8 @@
 
 #include "SchedulingPolicyService.h"
 
+#include <private/android_filesystem_config.h> // for AID_CAMERASERVER
+
 #include <log/log.h>
 #include <hwbinder/IPCThreadState.h>
 #include <mediautils/SchedulingPolicyService.h>
@@ -28,8 +30,9 @@
 namespace implementation {
 
 bool SchedulingPolicyService::isAllowed() {
-    // TODO(b/37291237)
-    return true;
+    using ::android::hardware::IPCThreadState;
+
+    return IPCThreadState::self()->getCallingUid() == AID_CAMERASERVER;
 }
 
 Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) {
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 8d381b1..a7f3a52 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -14,6 +14,7 @@
         "RecentEventLogger.cpp",
         "RotationVectorSensor.cpp",
         "SensorDevice.cpp",
+        "SensorDeviceUtils.cpp",
         "SensorDirectConnection.cpp",
         "SensorEventConnection.cpp",
         "SensorFusion.cpp",
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 452c8c6..d8e5b29 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -18,7 +18,7 @@
 #include <math.h>
 #include <sys/types.h>
 
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
@@ -78,12 +78,13 @@
     if (checkService()) {
         Mutex::Autolock _l(mActivationsLock);
         int64_t identity = IPCThreadState::self()->clearCallingIdentity();
-        for (size_t i=0 ; i<mActivations.size() ; i++) {
+        for (size_t i=0 ; i<mActivations.size() ; ) {
             const Info& info(mActivations[i]);
             if (info.uid == uid) {
                 mBatteryStatService->noteStopSensor(info.uid, info.handle);
                 mActivations.removeAt(i);
-                i--;
+            } else {
+              i++;
             }
         }
         IPCThreadState::self()->restoreCallingIdentity(identity);
@@ -105,4 +106,3 @@
 
 // ---------------------------------------------------------------------------
 }; // namespace android
-
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
new file mode 100644
index 0000000..d4393d6
--- /dev/null
+++ b/services/sensorservice/OWNERS
@@ -0,0 +1,2 @@
+arthuri@google.com
+bduddie@google.com
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index 62e9ce0..1025a88 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -100,7 +100,8 @@
 size_t RecentEventLogger::logSizeBySensorType(int sensorType) {
     return (sensorType == SENSOR_TYPE_STEP_COUNTER ||
             sensorType == SENSOR_TYPE_SIGNIFICANT_MOTION ||
-            sensorType == SENSOR_TYPE_ACCELEROMETER) ? LOG_SIZE_LARGE : LOG_SIZE;
+            sensorType == SENSOR_TYPE_ACCELEROMETER ||
+            sensorType == SENSOR_TYPE_LIGHT) ? LOG_SIZE_LARGE : LOG_SIZE;
 }
 
 RecentEventLogger::SensorEventLog::SensorEventLog(const sensors_event_t& e) : mEvent(e) {
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 7d9b0b7..115a983 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -18,7 +18,7 @@
 
 #include <android-base/logging.h>
 #include <sensors/convert.h>
-#include <utils/Atomic.h>
+#include <cutils/atomic.h>
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
@@ -26,11 +26,10 @@
 #include <cinttypes>
 #include <thread>
 
-using android::hardware::hidl_vec;
-
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
-
+using android::hardware::hidl_vec;
+using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -52,7 +51,8 @@
     }
 }
 
-SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+SensorDevice::SensorDevice()
+        : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
     if (!connectHidlService()) {
         return;
     }
@@ -87,35 +87,29 @@
 }
 
 bool SensorDevice::connectHidlService() {
-    // SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
-    constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+    // SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
     size_t retry = 10;
 
-    while (true) {
-        int initStep = 0;
+    while (retry-- > 0) {
         mSensors = ISensors::getService();
-        if (mSensors != nullptr) {
-            ++initStep;
-            // Poke ISensor service. If it has lingering connection from previous generation of
-            // system server, it will kill itself. There is no intention to handle the poll result,
-            // which will be done since the size is 0.
-            if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
-                // ok to continue
-                break;
-            }
-            // hidl service is restarting, pointer is invalid.
-            mSensors = nullptr;
-        }
-
-        if (--retry <= 0) {
-            ALOGE("Cannot connect to ISensors hidl service!");
+        if (mSensors == nullptr) {
+            // no sensor hidl service found
             break;
         }
-        // Delay 100ms before retry, hidl service is expected to come up in short time after
-        // crash.
-        ALOGI("%s unsuccessful, try again soon (remaining retry %zu).",
-                (initStep == 0) ? "getService()" : "poll() check", retry);
-        std::this_thread::sleep_for(RETRY_DELAY);
+
+        mRestartWaiter->reset();
+        // Poke ISensor service. If it has lingering connection from previous generation of
+        // system server, it will kill itself. There is no intention to handle the poll result,
+        // which will be done since the size is 0.
+        if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+            // ok to continue
+            break;
+        }
+
+        // hidl service is restarting, pointer is invalid.
+        mSensors = nullptr;
+        ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
+        mRestartWaiter->wait();
     }
     return (mSensors != nullptr);
 }
@@ -173,7 +167,7 @@
 }
 
 status_t SensorDevice::initCheck() const {
-    return mSensors != NULL ? NO_ERROR : NO_INIT;
+    return mSensors != nullptr ? NO_ERROR : NO_INIT;
 }
 
 ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
@@ -223,8 +217,13 @@
 }
 
 void SensorDevice::autoDisable(void *ident, int handle) {
-    Info& info( mActivationCount.editValueFor(handle) );
     Mutex::Autolock _l(mLock);
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
     info.removeBatchParamsForIdent(ident);
 }
 
@@ -235,7 +234,12 @@
     bool actuateHardware = false;
 
     Mutex::Autolock _l(mLock);
-    Info& info( mActivationCount.editValueFor(handle) );
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return BAD_VALUE;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
 
     ALOGD_IF(DEBUG_CONNECTIONS,
              "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
@@ -329,7 +333,12 @@
              ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
 
     Mutex::Autolock _l(mLock);
-    Info& info(mActivationCount.editValueFor(handle));
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return BAD_VALUE;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
 
     if (info.batchParams.indexOfKey(ident) < 0) {
         BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index fd6cee6..6d75051 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SENSOR_DEVICE_H
 #define ANDROID_SENSOR_DEVICE_H
 
+#include "SensorDeviceUtils.h"
 #include "SensorServiceUtils.h"
 
 #include <sensor/Sensor.h>
@@ -39,12 +40,9 @@
 namespace android {
 
 // ---------------------------------------------------------------------------
-using SensorServiceUtil::Dumpable;
-using hardware::Return;
 
-class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
+class SensorDevice : public Singleton<SensorDevice>, public SensorServiceUtil::Dumpable {
 public:
-
     class HidlTransportErrorLog {
      public:
 
@@ -105,7 +103,7 @@
 private:
     friend class Singleton<SensorDevice>;
 
-    sp<android::hardware::sensors::V1_0::ISensors> mSensors;
+    sp<hardware::sensors::V1_0::ISensors> mSensors;
     Vector<sensor_t> mSensorList;
     std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
 
@@ -174,6 +172,8 @@
         }
         return std::move(ret);
     }
+    //TODO(b/67425500): remove waiter after bug is resolved.
+    sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
     bool isClientDisabled(void* ident);
     bool isClientDisabledLocked(void* ident);
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
new file mode 100644
index 0000000..dbafffe
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorDeviceUtils.h"
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <thread>
+
+using ::android::hardware::Void;
+using namespace android::hardware::sensors::V1_0;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter() {
+}
+
+void HidlServiceRegistrationWaiter::onFirstRef() {
+    // Creating sp<...>(this) in the constructor should be avoided, hence
+    // registerForNotifications is called in onFirstRef callback.
+    mRegistered = ISensors::registerForNotifications("default", this);
+}
+
+Return<void> HidlServiceRegistrationWaiter::onRegistration(
+        const hidl_string &fqName, const hidl_string &name, bool preexisting) {
+    ALOGV("onRegistration fqName %s, name %s, preexisting %d",
+          fqName.c_str(), name.c_str(), preexisting);
+
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        mRestartObserved = true;
+    }
+    mCondition.notify_all();
+    return Void();
+}
+
+void HidlServiceRegistrationWaiter::reset() {
+    std::lock_guard<std::mutex> lk(mLock);
+    mRestartObserved = false;
+}
+
+bool HidlServiceRegistrationWaiter::wait() {
+    constexpr int DEFAULT_WAIT_MS = 100;
+    constexpr int TIMEOUT_MS = 1000;
+
+    if (!mRegistered) {
+        ALOGW("Cannot register service notification, use default wait(%d ms)", DEFAULT_WAIT_MS);
+        std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_WAIT_MS));
+        // not sure if service is actually restarted
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    return mCondition.wait_for(lk, std::chrono::milliseconds(TIMEOUT_MS),
+            [this]{return mRestartObserved;});
+}
+
+} // namespace SensorDeviceUtils
+} // namespace android
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
new file mode 100644
index 0000000..e2eb606
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_SENSOR_DEVICE_UTIL
+#define ANDROID_SENSOR_DEVICE_UTIL
+
+#include <android/hidl/manager/1.0/IServiceNotification.h>
+
+#include <condition_variable>
+#include <thread>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+class HidlServiceRegistrationWaiter : public IServiceNotification {
+public:
+
+    HidlServiceRegistrationWaiter();
+
+    Return<void> onRegistration(const hidl_string &fqName,
+                                const hidl_string &name,
+                                bool preexisting) override;
+
+    void reset();
+
+    /**
+     * Wait for service restart
+     *
+     * @return true if service is restart since last reset(); false otherwise.
+     */
+    bool wait();
+protected:
+    void onFirstRef() override;
+private:
+    bool mRegistered;
+
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    bool mRestartObserved;
+};
+
+} // namespace SensorDeviceUtils
+} // namespace android;
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0a05dd1..956844f 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -29,11 +29,11 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
-        const String16& opPackageName)
+        const String16& opPackageName, bool hasSensorAccess)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
       mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
-      mDestroyed(false) {
+      mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -223,6 +223,9 @@
         sensors_event_t* scratch,
         wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
     // filter out events not for this connection
+
+    sensors_event_t* sanitizedBuffer = nullptr;
+
     int count = 0;
     Mutex::Autolock _l(mConnectionLock);
     if (scratch) {
@@ -273,24 +276,36 @@
                     if (mapFlushEventsToConnections[i] == this) {
                         scratch[count++] = buffer[i];
                     }
-                    ++i;
                 } else {
                     // Regular sensor event, just copy it to the scratch buffer.
-                    scratch[count++] = buffer[i++];
+                    if (mHasSensorAccess) {
+                        scratch[count++] = buffer[i];
+                    }
                 }
+                i++;
             } while ((i<numEvents) && ((buffer[i].sensor == sensor_handle &&
                                         buffer[i].type != SENSOR_TYPE_META_DATA) ||
                                        (buffer[i].type == SENSOR_TYPE_META_DATA  &&
                                         buffer[i].meta_data.sensor == sensor_handle)));
         }
     } else {
-        scratch = const_cast<sensors_event_t *>(buffer);
-        count = numEvents;
+        if (mHasSensorAccess) {
+            scratch = const_cast<sensors_event_t *>(buffer);
+            count = numEvents;
+        } else {
+            scratch = sanitizedBuffer = new sensors_event_t[numEvents];
+            for (size_t i = 0; i < numEvents; i++) {
+                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                    scratch[count++] = buffer[i++];
+                }
+            }
+        }
     }
 
     sendPendingFlushEventsLocked();
     // Early return if there are no events for this connection.
     if (count == 0) {
+        delete sanitizedBuffer;
         return status_t(NO_ERROR);
     }
 
@@ -308,6 +323,7 @@
             // the max cache size that is desired.
             if (mCacheSize + count < computeMaxCacheSizeLocked()) {
                 reAllocateCacheLocked(scratch, count);
+                delete sanitizedBuffer;
                 return status_t(NO_ERROR);
             }
             // Some events need to be dropped.
@@ -326,16 +342,20 @@
             memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
                                             numEventsDropped * sizeof(sensors_event_t));
         }
+        delete sanitizedBuffer;
         return status_t(NO_ERROR);
     }
 
-    int index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
-    if (index_wake_up_event >= 0) {
-        scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
-        ++mWakeLockRefCount;
+    int index_wake_up_event = -1;
+    if (mHasSensorAccess) {
+        index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
+        if (index_wake_up_event >= 0) {
+            scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+            ++mWakeLockRefCount;
 #if DEBUG_CONNECTIONS
-        ++mTotalAcksNeeded;
+            ++mTotalAcksNeeded;
 #endif
+        }
     }
 
     // NOTE: ASensorEvent and sensors_event_t are the same type.
@@ -364,6 +384,7 @@
         // Add this file descriptor to the looper to get a callback when this fd is available for
         // writing.
         updateLooperRegistrationLocked(mService->getLooper());
+        delete sanitizedBuffer;
         return size;
     }
 
@@ -373,9 +394,15 @@
     }
 #endif
 
+    delete sanitizedBuffer;
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
+void SensorService::SensorEventConnection::setSensorAccess(const bool hasAccess) {
+    Mutex::Autolock _l(mConnectionLock);
+    mHasSensorAccess = hasAccess;
+}
+
 void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
                                                                  int count) {
     sensors_event_t *eventCache_new;
@@ -437,15 +464,18 @@
     sendPendingFlushEventsLocked();
     for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
         const int numEventsToWrite = helpers::min(mCacheSize - numEventsSent, maxWriteSize);
-        int index_wake_up_event =
-                  findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
-        if (index_wake_up_event >= 0) {
-            mEventCache[index_wake_up_event + numEventsSent].flags |=
-                    WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
-            ++mWakeLockRefCount;
+        int index_wake_up_event = -1;
+        if (mHasSensorAccess) {
+            index_wake_up_event =
+                      findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
+            if (index_wake_up_event >= 0) {
+                mEventCache[index_wake_up_event + numEventsSent].flags |=
+                        WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+                ++mWakeLockRefCount;
 #if DEBUG_CONNECTIONS
-            ++mTotalAcksNeeded;
+                ++mTotalAcksNeeded;
 #endif
+            }
         }
 
         ssize_t size = SensorEventQueue::write(mChannel,
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 6f282cd..032721e 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -49,7 +49,8 @@
 
 public:
     SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
-                          bool isDataInjectionMode, const String16& opPackageName);
+                          bool isDataInjectionMode, const String16& opPackageName,
+                          bool hasSensorAccess);
 
     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
                         wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
@@ -66,6 +67,8 @@
 
     uid_t getUid() const { return mUid; }
 
+    void setSensorAccess(const bool hasAccess);
+
 private:
     virtual ~SensorEventConnection();
     virtual void onFirstRef();
@@ -167,6 +170,7 @@
 
     mutable Mutex mDestroyLock;
     bool mDestroyed;
+    bool mHasSensorAccess;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 75e8989..bba8372 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -35,12 +35,12 @@
     }
 
     SensorRegistrationInfo(int32_t handle, const String8 &packageName,
-                           int32_t samplingRateNs, int32_t maxReportLatencyNs, bool activate) {
+                           int64_t samplingRateNs, int64_t maxReportLatencyNs, bool activate) {
         mSensorHandle = handle;
         mPackageName = packageName;
 
-        mSamplingRateUs = static_cast<int32_t>(samplingRateNs/1000);
-        mMaxReportLatencyUs = static_cast<int32_t>(maxReportLatencyNs/1000);
+        mSamplingRateUs = static_cast<int64_t>(samplingRateNs/1000);
+        mMaxReportLatencyUs = static_cast<int64_t>(maxReportLatencyNs/1000);
         mActivated = activate;
 
         IPCThreadState *thread = IPCThreadState::self();
@@ -82,8 +82,8 @@
     String8 mPackageName;
     pid_t   mPid;
     uid_t   mUid;
-    int32_t mSamplingRateUs;
-    int32_t mMaxReportLatencyUs;
+    int64_t mSamplingRateUs;
+    int64_t mMaxReportLatencyUs;
     bool mActivated;
     int8_t mHour, mMin, mSec;
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e5b6dcf..8e9e7fd 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <binder/ActivityManager.h>
 #include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
+#include <binder/PermissionController.h>
 #include <cutils/ashmem.h>
+#include <cutils/misc.h>
 #include <cutils/properties.h>
 #include <hardware/sensors.h>
 #include <hardware_legacy/power.h>
@@ -53,6 +56,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <private/android_filesystem_config.h>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -76,10 +81,12 @@
 // Permissions.
 static const String16 sDumpPermission("android.permission.DUMP");
 static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
+static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
 
 SensorService::SensorService()
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
       mWakeLockAcquired(false) {
+    mUidPolicy = new UidPolicy(this);
 }
 
 bool SensorService::initializeHmacKey() {
@@ -275,6 +282,22 @@
 
             // priority can only be changed after run
             enableSchedFifoMode();
+
+            // Start watching UID changes to apply policy.
+            mUidPolicy->registerSelf();
+        }
+    }
+}
+
+void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
+    SortedVector< sp<SensorEventConnection> > activeConnections;
+    populateActiveConnections(&activeConnections);
+    {
+        Mutex::Autolock _l(mLock);
+        for (size_t i = 0 ; i < activeConnections.size(); i++) {
+            if (activeConnections[i] != 0 && activeConnections[i]->getUid() == uid) {
+                activeConnections[i]->setSensorAccess(hasAccess);
+            }
         }
     }
 }
@@ -313,6 +336,7 @@
     for (auto && entry : mRecentEvent) {
         delete entry.second;
     }
+    mUidPolicy->unregisterSelf();
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -489,6 +513,82 @@
     return NO_ERROR;
 }
 
+// NOTE: This is a remote API - make sure all args are validated
+status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
+    if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
+        return PERMISSION_DENIED;
+    }
+    if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
+        return BAD_VALUE;
+    }
+    if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+        return handleSetUidState(args, err);
+    } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+        return handleResetUidState(args, err);
+    } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+        return handleGetUidState(args, out, err);
+    } else if (args.size() == 1 && args[0] == String16("help")) {
+        printHelp(out);
+        return NO_ERROR;
+    }
+    printHelp(err);
+    return BAD_VALUE;
+}
+
+status_t SensorService::handleSetUidState(Vector<String16>& args, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid <= 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    bool active = false;
+    if (args[2] == String16("active")) {
+        active = true;
+    } else if ((args[2] != String16("idle"))) {
+        ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
+        return BAD_VALUE;
+    }
+    mUidPolicy->addOverrideUid(uid, active);
+    return NO_ERROR;
+}
+
+status_t SensorService::handleResetUidState(Vector<String16>& args, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid < 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    mUidPolicy->removeOverrideUid(uid);
+    return NO_ERROR;
+}
+
+status_t SensorService::handleGetUidState(Vector<String16>& args, int out, int err) {
+    PermissionController pc;
+    int uid = pc.getPackageUid(args[1], 0);
+    if (uid < 0) {
+        ALOGE("Unknown package: '%s'", String8(args[1]).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+        return BAD_VALUE;
+    }
+    if (mUidPolicy->isUidActive(uid)) {
+        return dprintf(out, "active\n");
+    } else {
+        return dprintf(out, "idle\n");
+    }
+}
+
+status_t SensorService::printHelp(int out) {
+    return dprintf(out, "Sensor service commands:\n"
+        "  get-uid-state <PACKAGE> gets the uid state\n"
+        "  set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
+        "  reset-uid-state <PACKAGE> clears the uid state override\n"
+        "  help print this message\n");
+}
+
 //TODO: move to SensorEventConnection later
 void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
         sensors_event_t const* buffer, const int count) {
@@ -678,7 +778,6 @@
             }
         }
 
-
         // Send our events to clients. Check the state of wake lock for each client and release the
         // lock if none of the clients need it.
         bool needsWakeLock = false;
@@ -940,8 +1039,9 @@
             (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
     String16 connOpPackageName =
             (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
+    bool hasSensorAccess = mUidPolicy->isUidActive(uid);
     sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
-            requestedMode == DATA_INJECTION, connOpPackageName));
+            requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
     if (requestedMode == DATA_INJECTION) {
         if (mActiveConnections.indexOf(result) < 0) {
             mActiveConnections.add(result);
@@ -1536,4 +1636,98 @@
     return false;
 }
 
+void SensorService::UidPolicy::registerSelf() {
+    ActivityManager am;
+    am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+            | ActivityManager::UID_OBSERVER_IDLE
+            | ActivityManager::UID_OBSERVER_ACTIVE,
+            ActivityManager::PROCESS_STATE_UNKNOWN,
+            String16("android"));
+}
+
+void SensorService::UidPolicy::unregisterSelf() {
+    ActivityManager am;
+    am.unregisterUidObserver(this);
+}
+
+void SensorService::UidPolicy::onUidGone(__unused uid_t uid, __unused bool disabled) {
+    onUidIdle(uid, disabled);
+}
+
+void SensorService::UidPolicy::onUidActive(uid_t uid) {
+    {
+        Mutex::Autolock _l(mUidLock);
+        mActiveUids.insert(uid);
+    }
+    sp<SensorService> service = mService.promote();
+    if (service != nullptr) {
+        service->setSensorAccess(uid, true);
+    }
+}
+
+void SensorService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
+    bool deleted = false;
+    {
+        Mutex::Autolock _l(mUidLock);
+        if (mActiveUids.erase(uid) > 0) {
+            deleted = true;
+        }
+    }
+    if (deleted) {
+        sp<SensorService> service = mService.promote();
+        if (service != nullptr) {
+            service->setSensorAccess(uid, false);
+        }
+    }
+}
+
+void SensorService::UidPolicy::addOverrideUid(uid_t uid, bool active) {
+    updateOverrideUid(uid, active, true);
+}
+
+void SensorService::UidPolicy::removeOverrideUid(uid_t uid) {
+    updateOverrideUid(uid, false, false);
+}
+
+void SensorService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+    bool wasActive = false;
+    bool isActive = false;
+    {
+        Mutex::Autolock _l(mUidLock);
+        wasActive = isUidActiveLocked(uid);
+        mOverrideUids.erase(uid);
+        if (insert) {
+            mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
+        }
+        isActive = isUidActiveLocked(uid);
+    }
+    if (wasActive != isActive) {
+        sp<SensorService> service = mService.promote();
+        if (service != nullptr) {
+            service->setSensorAccess(uid, isActive);
+        }
+    }
+}
+
+bool SensorService::UidPolicy::isUidActive(uid_t uid) {
+    // Non-app UIDs are considered always active
+    if (uid < FIRST_APPLICATION_UID) {
+        return true;
+    }
+    Mutex::Autolock _l(mUidLock);
+    return isUidActiveLocked(uid);
+}
+
+bool SensorService::UidPolicy::isUidActiveLocked(uid_t uid) {
+    // Non-app UIDs are considered always active
+    if (uid < FIRST_APPLICATION_UID) {
+        return true;
+    }
+    auto it = mOverrideUids.find(uid);
+    if (it != mOverrideUids.end()) {
+        return it->second;
+    }
+    return mActiveUids.find(uid) != mActiveUids.end();
+}
+
 }; // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3e18394..f71723d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -21,6 +21,7 @@
 #include "RecentEventLogger.h"
 
 #include <binder/BinderService.h>
+#include <binder/IUidObserver.h>
 #include <cutils/compiler.h>
 #include <sensor/ISensorServer.h>
 #include <sensor/ISensorEventConnection.h>
@@ -85,6 +86,9 @@
     status_t flushSensor(const sp<SensorEventConnection>& connection,
                          const String16& opPackageName);
 
+
+    virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
+
 private:
     friend class BinderService<SensorService>;
 
@@ -93,6 +97,40 @@
     class SensorEventAckReceiver;
     class SensorRegistrationInfo;
 
+    // If accessing a sensor we need to make sure the UID has access to it. If
+    // the app UID is idle then it cannot access sensors and gets no trigger
+    // events, no on-change events, flush event behavior does not change, and
+    // recurring events are the same as the first one delivered in idle state
+    // emulating no sensor change. As soon as the app UID transitions to an
+    // active state we will start reporting events as usual and vise versa. This
+    // approach transparently handles observing sensors while the app UID transitions
+    // between idle/active state avoiding to get stuck in a state receiving sensor
+    // data while idle or not receiving sensor data while active.
+    class UidPolicy : public BnUidObserver {
+        public:
+            explicit UidPolicy(wp<SensorService> service)
+                    : mService(service) {}
+            void registerSelf();
+            void unregisterSelf();
+
+            bool isUidActive(uid_t uid);
+
+            void onUidGone(uid_t uid, bool disabled);
+            void onUidActive(uid_t uid);
+            void onUidIdle(uid_t uid, bool disabled);
+
+            void addOverrideUid(uid_t uid, bool active);
+            void removeOverrideUid(uid_t uid);
+        private:
+            bool isUidActiveLocked(uid_t uid);
+            void updateOverrideUid(uid_t uid, bool active, bool insert);
+
+            Mutex mUidLock;
+            wp<SensorService> mService;
+            std::unordered_set<uid_t> mActiveUids;
+            std::unordered_map<uid_t, bool> mOverrideUids;
+    };
+
     enum Mode {
        // The regular operating mode where any application can register/unregister/call flush on
        // sensors.
@@ -161,7 +199,6 @@
     virtual int setOperationParameter(
             int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
     virtual status_t dump(int fd, const Vector<String16>& args);
-
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
@@ -225,6 +262,18 @@
     // Enable SCHED_FIFO priority for thread
     void enableSchedFifoMode();
 
+    // Sets whether the given UID can get sensor data
+    void setSensorAccess(uid_t uid, bool hasAccess);
+
+    // Overrides the UID state as if it is idle
+    status_t handleSetUidState(Vector<String16>& args, int err);
+    // Clears the override for the UID state
+    status_t handleResetUidState(Vector<String16>& args, int err);
+    // Gets the UID state
+    status_t handleGetUidState(Vector<String16>& args, int out, int err);
+    // Prints the shell command help
+    status_t printHelp(int out);
+
     static uint8_t sHmacGlobalKey[128];
     static bool sHmacGlobalKeyIsValid;
 
@@ -257,6 +306,8 @@
 
     int mNextSensorRegIndex;
     Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
+
+    sp<UidPolicy> mUidPolicy;
 };
 
 } // namespace android
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
index e894655..8a9c36b 100644
--- a/services/sensorservice/tests/Android.mk
+++ b/services/sensorservice/tests/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES:= \
 	sensorservicetest.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libutils libsensor libandroid
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index cc93105..320e11f 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,4 +1,225 @@
-cc_library_static {
-    name: "libsurfaceflingerincludes",
-    export_include_dirs: ["."],
+cc_defaults {
+    name: "surfaceflinger_defaults",
+    cflags: [
+        "-DLOG_TAG=\"SurfaceFlinger\"",
+        "-Wall",
+        "-Werror",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    cppflags: ["-std=c++1z"],
 }
+
+cc_defaults {
+    name: "libsurfaceflinger_defaults",
+    defaults: ["surfaceflinger_defaults"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    shared_libs: [
+        "android.frameworks.vr.composer@1.0",
+        "android.hardware.configstore-utils",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore@1.1",
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.3",
+        "libbase",
+        "libbinder",
+        "libbufferhubqueue",
+        "libcutils",
+        "libdl",
+        "libEGL",
+        "libfmq",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libgui",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblayers_proto",
+        "liblog",
+        "libpdx_default_transport",
+        "libprotobuf-cpp-lite",
+        "libsync",
+        "libtimestats_proto",
+        "libui",
+        "libutils",
+        "libvulkan",
+    ],
+    static_libs: [
+        "libserviceutils",
+        "libtrace_proto",
+        "libvkjson",
+        "libvr_manager",
+        "libvrflinger",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    export_static_lib_headers: [
+        "libserviceutils",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.power@1.3",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+    ],
+}
+
+cc_library_headers {
+    name: "libsurfaceflinger_headers",
+    export_include_dirs: ["."],
+    static_libs: ["libserviceutils"],
+    export_static_lib_headers: ["libserviceutils"],
+}
+
+filegroup {
+    name: "libsurfaceflinger_sources",
+    srcs: [
+        "BufferLayer.cpp",
+        "BufferLayerConsumer.cpp",
+        "Client.cpp",
+        "ColorLayer.cpp",
+        "ContainerLayer.cpp",
+        "DisplayDevice.cpp",
+        "DisplayHardware/ComposerHal.cpp",
+        "DisplayHardware/FramebufferSurface.cpp",
+        "DisplayHardware/HWC2.cpp",
+        "DisplayHardware/HWComposer.cpp",
+        "DisplayHardware/HWComposerBufferCache.cpp",
+        "DisplayHardware/PowerAdvisor.cpp",
+        "DisplayHardware/VirtualDisplaySurface.cpp",
+        "DispSync.cpp",
+        "Effects/Daltonizer.cpp",
+        "EventControlThread.cpp",
+        "EventLog/EventLog.cpp",
+        "EventThread.cpp",
+        "FrameTracker.cpp",
+        "GpuService.cpp",
+        "Layer.cpp",
+        "LayerProtoHelper.cpp",
+        "LayerRejecter.cpp",
+        "LayerStats.cpp",
+        "LayerVector.cpp",
+        "MessageQueue.cpp",
+        "MonitoredProducer.cpp",
+        "RenderArea.cpp",
+        "RenderEngine/Description.cpp",
+        "RenderEngine/GLES20RenderEngine.cpp",
+        "RenderEngine/GLExtensions.cpp",
+        "RenderEngine/Image.cpp",
+        "RenderEngine/Mesh.cpp",
+        "RenderEngine/Program.cpp",
+        "RenderEngine/ProgramCache.cpp",
+        "RenderEngine/RenderEngine.cpp",
+        "RenderEngine/Surface.cpp",
+        "RenderEngine/Texture.cpp",
+        "StartPropertySetThread.cpp",
+        "SurfaceFlinger.cpp",
+        "SurfaceInterceptor.cpp",
+        "SurfaceTracing.cpp",
+        "TimeStats/TimeStats.cpp",
+        "Transform.cpp",
+    ],
+}
+
+cc_library_shared {
+    name: "libsurfaceflinger",
+    defaults: ["libsurfaceflinger_defaults"],
+    cflags: [
+        "-fvisibility=hidden",
+        "-Werror=format",
+    ],
+    srcs: [
+        ":libsurfaceflinger_sources",
+    ],
+    logtags: ["EventLog/EventLogTags.logtags"],
+    include_dirs: [
+        "frameworks/native/vulkan/vkjson",
+        "frameworks/native/vulkan/include",
+    ],
+    cppflags: [
+        "-fwhole-program-vtables", // requires ThinLTO
+    ],
+    lto: {
+        thin: true,
+    },
+}
+
+cc_binary {
+    name: "surfaceflinger",
+    defaults: ["surfaceflinger_defaults"],
+    init_rc: ["surfaceflinger.rc"],
+    srcs: ["main_surfaceflinger.cpp"],
+    whole_static_libs: [
+        "libsigchain",
+    ],
+    shared_libs: [
+        "android.frameworks.displayservice@1.0",
+        "android.hardware.configstore-utils",
+        "android.hardware.configstore@1.0",
+        "android.hardware.graphics.allocator@2.0",
+        "libbinder",
+        "libcutils",
+        "libdisplayservicehidl",
+        "libhidlbase",
+        "libhidltransport",
+        "liblayers_proto",
+        "liblog",
+        "libsurfaceflinger",
+        "libtimestats_proto",
+        "libutils",
+    ],
+    static_libs: [
+        "libserviceutils",
+        "libtrace_proto",
+    ],
+    ldflags: ["-Wl,--export-dynamic"],
+
+    // TODO(b/71715793): These version-scripts are required due to the use of
+    // whole_static_libs to pull in libsigchain. To work, the files had to be
+    // locally duplicated from their original location
+    // $ANDROID_ROOT/art/sigchainlib/
+    multilib: {
+        lib32: {
+            version_script: "version-script32.txt",
+        },
+        lib64: {
+            version_script: "version-script64.txt",
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libsurfaceflinger_ddmconnection",
+    defaults: ["surfaceflinger_defaults"],
+    srcs: ["DdmConnection.cpp"],
+    shared_libs: [
+        "libcutils",
+        "libdl",
+        "liblog",
+    ],
+    product_variables: {
+        // uses jni which may not be available in PDK
+        pdk: {
+            enabled: false,
+        },
+    },
+}
+
+subdirs = [
+    "layerproto",
+    "TimeStats/timestatsproto",
+    "tests",
+]
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
deleted file mode 100644
index 38529b6..0000000
--- a/services/surfaceflinger/Android.mk
+++ /dev/null
@@ -1,184 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := \
-    Client.cpp \
-    DisplayDevice.cpp \
-    DispSync.cpp \
-    EventControlThread.cpp \
-    StartPropertySetThread.cpp \
-    EventThread.cpp \
-    FrameTracker.cpp \
-    GpuService.cpp \
-    Layer.cpp \
-    LayerDim.cpp \
-    LayerRejecter.cpp \
-    LayerVector.cpp \
-    MessageQueue.cpp \
-    MonitoredProducer.cpp \
-    SurfaceFlingerConsumer.cpp \
-    SurfaceInterceptor.cpp \
-    Transform.cpp \
-    DisplayHardware/ComposerHal.cpp \
-    DisplayHardware/FramebufferSurface.cpp \
-    DisplayHardware/HWC2.cpp \
-    DisplayHardware/HWComposerBufferCache.cpp \
-    DisplayHardware/PowerHAL.cpp \
-    DisplayHardware/VirtualDisplaySurface.cpp \
-    Effects/Daltonizer.cpp \
-    EventLog/EventLogTags.logtags \
-    EventLog/EventLog.cpp \
-    RenderEngine/Description.cpp \
-    RenderEngine/Mesh.cpp \
-    RenderEngine/Program.cpp \
-    RenderEngine/ProgramCache.cpp \
-    RenderEngine/GLExtensions.cpp \
-    RenderEngine/RenderEngine.cpp \
-    RenderEngine/Texture.cpp \
-    RenderEngine/GLES20RenderEngine.cpp \
-
-LOCAL_MODULE := libsurfaceflinger
-LOCAL_C_INCLUDES := \
-    frameworks/native/vulkan/include \
-    external/vulkan-validation-layers/libs/vkjson \
-    system/libhwbinder/fast_msgq/include \
-
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-ifeq ($(TARGET_USES_HWC2),true)
-    LOCAL_CFLAGS += -DUSE_HWC2
-    LOCAL_SRC_FILES += \
-        SurfaceFlinger.cpp \
-        DisplayHardware/HWComposer.cpp
-else
-    LOCAL_SRC_FILES += \
-        SurfaceFlinger_hwc1.cpp \
-        DisplayHardware/HWComposer_hwc1.cpp
-endif
-
-LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-
-LOCAL_STATIC_LIBRARIES := \
-    libhwcomposer-command-buffer \
-    libtrace_proto \
-    libvkjson \
-    libvr_manager \
-    libvrflinger
-
-LOCAL_SHARED_LIBRARIES := \
-    android.frameworks.vr.composer@1.0 \
-    android.hardware.graphics.allocator@2.0 \
-    android.hardware.graphics.composer@2.1 \
-    android.hardware.configstore@1.0 \
-    android.hardware.configstore-utils \
-    libcutils \
-    liblog \
-    libdl \
-    libfmq \
-    libhardware \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder \
-    libutils \
-    libEGL \
-    libGLESv1_CM \
-    libGLESv2 \
-    libbinder \
-    libui \
-    libgui \
-    libpowermanager \
-    libvulkan \
-    libsync \
-    libprotobuf-cpp-lite \
-    libbase \
-    android.hardware.power@1.0
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-    android.hardware.graphics.allocator@2.0 \
-    android.hardware.graphics.composer@2.1 \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################
-# build surfaceflinger's executable
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-
-LOCAL_INIT_RC := surfaceflinger.rc
-
-ifeq ($(TARGET_USES_HWC2),true)
-    LOCAL_CFLAGS += -DUSE_HWC2
-endif
-
-LOCAL_SRC_FILES := \
-    main_surfaceflinger.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    android.frameworks.displayservice@1.0 \
-    android.hardware.configstore@1.0 \
-    android.hardware.configstore-utils \
-    android.hardware.graphics.allocator@2.0 \
-    libsurfaceflinger \
-    libcutils \
-    libdisplayservicehidl \
-    liblog \
-    libbinder \
-    libhidlbase \
-    libhidltransport \
-    libutils \
-    libui \
-    libgui \
-    libdl
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_STATIC_LIBRARIES := libtrace_proto
-
-LOCAL_MODULE := surfaceflinger
-
-ifdef TARGET_32_BIT_SURFACEFLINGER
-LOCAL_32_BIT_ONLY := true
-endif
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
-
-###############################################################
-# uses jni which may not be available in PDK
-ifneq ($(wildcard libnativehelper/include),)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-
-LOCAL_SRC_FILES := \
-    DdmConnection.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libdl
-
-LOCAL_MODULE := libsurfaceflinger_ddmconnection
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
-endif # libnativehelper
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
new file mode 100644
index 0000000..7ac1432
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferLayer.h"
+#include "Colorizer.h"
+#include "DisplayDevice.h"
+#include "LayerRejecter.h"
+#include "clz.h"
+
+#include "RenderEngine/RenderEngine.h"
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+
+#include <ui/DebugUtils.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <mutex>
+
+namespace android {
+
+BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                         uint32_t w, uint32_t h, uint32_t flags)
+      : Layer(flinger, client, name, w, h, flags),
+        mConsumer(nullptr),
+        mTextureName(UINT32_MAX),
+        mFormat(PIXEL_FORMAT_NONE),
+        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+        mBufferLatched(false),
+        mPreviousFrameNumber(0),
+        mUpdateTexImageFailed(false),
+        mRefreshPending(false) {
+    ALOGV("Creating Layer %s", name.string());
+
+    mTextureName = mFlinger->getNewTexture();
+    mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
+
+    if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
+
+    mCurrentState.requested = mCurrentState.active;
+
+    // drawing state & current state are identical
+    mDrawingState = mCurrentState;
+}
+
+BufferLayer::~BufferLayer() {
+    mFlinger->deleteTextureAsync(mTextureName);
+
+    if (!getBE().mHwcLayers.empty()) {
+        ALOGE("Found stale hardware composer layers when destroying "
+              "surface flinger layer %s",
+              mName.string());
+        destroyAllHwcLayers();
+    }
+}
+
+void BufferLayer::useSurfaceDamage() {
+    if (mFlinger->mForceFullDamage) {
+        surfaceDamageRegion = Region::INVALID_REGION;
+    } else {
+        surfaceDamageRegion = mConsumer->getSurfaceDamage();
+    }
+}
+
+void BufferLayer::useEmptyDamage() {
+    surfaceDamageRegion.clear();
+}
+
+bool BufferLayer::isProtected() const {
+    const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
+    return (buffer != 0) &&
+            (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+bool BufferLayer::isVisible() const {
+    return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
+            (getBE().compositionInfo.mBuffer != nullptr ||
+             getBE().compositionInfo.hwc.sidebandStream != nullptr);
+}
+
+bool BufferLayer::isFixedSize() const {
+    return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
+    uint32_t const maxSurfaceDims =
+            min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
+
+    // never allow a surface larger than what our underlying GL implementation
+    // can handle.
+    if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
+        ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+        return BAD_VALUE;
+    }
+
+    mFormat = format;
+
+    mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
+    mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
+    mCurrentOpacity = getOpacityForFormat(format);
+
+    mConsumer->setDefaultBufferSize(w, h);
+    mConsumer->setDefaultBufferFormat(format);
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+
+    return NO_ERROR;
+}
+
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+    const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+    const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    mat4 tr;
+
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        tr = tr * rot90;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        tr = tr * flipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        tr = tr * flipV;
+    }
+    return inverse(tr);
+}
+
+/*
+ * onDraw will draw the current layer onto the presentable buffer
+ */
+void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
+                         bool useIdentityTransform) const {
+    ATRACE_CALL();
+
+    if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
+        // the texture has not been created yet, this Layer has
+        // in fact never been drawn into. This happens frequently with
+        // SurfaceView because the WindowManager can't know when the client
+        // has drawn the first time.
+
+        // If there is nothing under us, we paint the screen in black, otherwise
+        // we just skip this update.
+
+        // figure out if there is something below us
+        Region under;
+        bool finished = false;
+        mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (finished || layer == static_cast<BufferLayer const*>(this)) {
+                finished = true;
+                return;
+            }
+            under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
+        });
+        // if not everything below us is covered, we plug the holes!
+        Region holes(clip.subtract(under));
+        if (!holes.isEmpty()) {
+            clearWithOpenGL(renderArea, 0, 0, 0, 1);
+        }
+        return;
+    }
+
+    // Bind the current buffer to the GL texture, and wait for it to be
+    // ready for us to draw into.
+    status_t err = mConsumer->bindTextureImage();
+    if (err != NO_ERROR) {
+        ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
+        // Go ahead and draw the buffer anyway; no matter what we do the screen
+        // is probably going to have something visibly wrong.
+    }
+
+    bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+
+    auto& engine(mFlinger->getRenderEngine());
+
+    if (!blackOutLayer) {
+        // TODO: we could be more subtle with isFixedSize()
+        const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
+
+        // Query the texture matrix given our current filtering mode.
+        float textureMatrix[16];
+        mConsumer->setFilteringEnabled(useFiltering);
+        mConsumer->getTransformMatrix(textureMatrix);
+
+        if (getTransformToDisplayInverse()) {
+            /*
+             * the code below applies the primary display's inverse transform to
+             * the texture transform
+             */
+            uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+            mat4 tr = inverseOrientation(transform);
+
+            /**
+             * TODO(b/36727915): This is basically a hack.
+             *
+             * Ensure that regardless of the parent transformation,
+             * this buffer is always transformed from native display
+             * orientation to display orientation. For example, in the case
+             * of a camera where the buffer remains in native orientation,
+             * we want the pixels to always be upright.
+             */
+            sp<Layer> p = mDrawingParent.promote();
+            if (p != nullptr) {
+                const auto parentTransform = p->getTransform();
+                tr = tr * inverseOrientation(parentTransform.getOrientation());
+            }
+
+            // and finally apply it to the original texture matrix
+            const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+            memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+        }
+
+        // Set things up for texturing.
+        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
+                               getBE().compositionInfo.mBuffer->getHeight());
+        mTexture.setFiltering(useFiltering);
+        mTexture.setMatrix(textureMatrix);
+
+        engine.setupLayerTexturing(mTexture);
+    } else {
+        engine.setupLayerBlackedOut();
+    }
+    drawWithOpenGL(renderArea, useIdentityTransform);
+    engine.disableTexturing();
+}
+
+void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+    mConsumer->setReleaseFence(releaseFence);
+}
+
+void BufferLayer::abandon() {
+    mConsumer->abandon();
+}
+
+bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
+    if (mSidebandStreamChanged || mAutoRefresh) {
+        return true;
+    }
+
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        return false;
+    }
+    auto timestamp = mQueueItems[0].mTimestamp;
+    nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
+
+    // Ignore timestamps more than a second in the future
+    bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+    ALOGW_IF(!isPlausible,
+             "[%s] Timestamp %" PRId64 " seems implausible "
+             "relative to expectedPresent %" PRId64,
+             mName.string(), timestamp, expectedPresent);
+
+    bool isDue = timestamp < expectedPresent;
+    return isDue || !isPlausible;
+}
+
+void BufferLayer::setTransformHint(uint32_t orientation) const {
+    mConsumer->setTransformHint(orientation);
+}
+
+bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
+    if (mBufferLatched) {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
+                                             refreshStartTime);
+    }
+    mRefreshPending = false;
+    return mQueuedFrames > 0 || mSidebandStreamChanged ||
+            mAutoRefresh;
+}
+bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+                                    const std::shared_ptr<FenceTime>& presentFence,
+                                    const CompositorTiming& compositorTiming) {
+    // mFrameLatencyNeeded is true when a new frame was latched for the
+    // composition.
+    if (!mFrameLatencyNeeded) return false;
+
+    // Update mFrameEventHistory.
+    {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence,
+                                              presentFence, compositorTiming);
+    }
+
+    // Update mFrameTracker.
+    nsecs_t desiredPresentTime = mConsumer->getTimestamp();
+    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
+
+    const std::string layerName(getName().c_str());
+    mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
+
+    std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime();
+    if (frameReadyFence->isValid()) {
+        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
+    } else {
+        // There was no fence for this frame, so assume that it was ready
+        // to be presented at the desired present time.
+        mFrameTracker.setFrameReadyTime(desiredPresentTime);
+    }
+
+    if (presentFence->isValid()) {
+        mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
+        mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+    } else {
+        // The HWC doesn't support present fences, so use the refresh
+        // timestamp instead.
+        const nsecs_t actualPresentTime =
+                mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+        mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
+        mFrameTracker.setActualPresentTime(actualPresentTime);
+    }
+
+    mFrameTracker.advanceFrame();
+    mFrameLatencyNeeded = false;
+    return true;
+}
+
+std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
+    std::vector<OccupancyTracker::Segment> history;
+    status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
+    if (result != NO_ERROR) {
+        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+        return {};
+    }
+    return history;
+}
+
+bool BufferLayer::getTransformToDisplayInverse() const {
+    return mConsumer->getTransformToDisplayInverse();
+}
+
+void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+    if (!mConsumer->releasePendingBuffer()) {
+        return;
+    }
+
+    auto releaseFenceTime =
+            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    mReleaseTimeline.updateSignalTimes();
+    mReleaseTimeline.push(releaseFenceTime);
+
+    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    if (mPreviousFrameNumber != 0) {
+        mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+                                      std::move(releaseFenceTime));
+    }
+}
+
+Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+    ATRACE_CALL();
+
+    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was true
+        mSidebandStream = mConsumer->getSidebandStream();
+        // replicated in LayerBE until FE/BE is ready to be synchronized
+        getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
+        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+            setTransactionFlags(eTransactionNeeded);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
+        }
+        recomputeVisibleRegions = true;
+
+        const State& s(getDrawingState());
+        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+    }
+
+    Region outDirtyRegion;
+    if (mQueuedFrames <= 0 && !mAutoRefresh) {
+        return outDirtyRegion;
+    }
+
+    // if we've already called updateTexImage() without going through
+    // a composition step, we have to skip this layer at this point
+    // because we cannot call updateTeximage() without a corresponding
+    // compositionComplete() call.
+    // we'll trigger an update in onPreComposition().
+    if (mRefreshPending) {
+        return outDirtyRegion;
+    }
+
+    // If the head buffer's acquire fence hasn't signaled yet, return and
+    // try again later
+    if (!headFenceHasSignaled()) {
+        mFlinger->signalLayerUpdate();
+        return outDirtyRegion;
+    }
+
+    // Capture the old state of the layer for comparisons later
+    const State& s(getDrawingState());
+    const bool oldOpacity = isOpaque(s);
+    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
+
+    if (!allTransactionsSignaled()) {
+        mFlinger->signalLayerUpdate();
+        return outDirtyRegion;
+    }
+
+    // This boolean is used to make sure that SurfaceFlinger's shadow copy
+    // of the buffer queue isn't modified when the buffer queue is returning
+    // BufferItem's that weren't actually queued. This can happen in shared
+    // buffer mode.
+    bool queuedBuffer = false;
+    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+                    getProducerStickyTransform() != 0, mName.string(),
+                    mOverrideScalingMode, mFreezeGeometryUpdates);
+    status_t updateResult =
+            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
+                                                    &mAutoRefresh, &queuedBuffer,
+                                                    mLastFrameNumberReceived);
+    if (updateResult == BufferQueue::PRESENT_LATER) {
+        // Producer doesn't want buffer to be displayed yet.  Signal a
+        // layer update so we check again at the next opportunity.
+        mFlinger->signalLayerUpdate();
+        return outDirtyRegion;
+    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
+        // If the buffer has been rejected, remove it from the shadow queue
+        // and return early
+        if (queuedBuffer) {
+            Mutex::Autolock lock(mQueueItemLock);
+            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mQueueItems.removeAt(0);
+            android_atomic_dec(&mQueuedFrames);
+        }
+        return outDirtyRegion;
+    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+        // This can occur if something goes wrong when trying to create the
+        // EGLImage for this buffer. If this happens, the buffer has already
+        // been released, so we need to clean up the queue and bug out
+        // early.
+        if (queuedBuffer) {
+            Mutex::Autolock lock(mQueueItemLock);
+            mQueueItems.clear();
+            android_atomic_and(0, &mQueuedFrames);
+            mTimeStats.clearLayerRecord(getName().c_str());
+        }
+
+        // Once we have hit this state, the shadow queue may no longer
+        // correctly reflect the incoming BufferQueue's contents, so even if
+        // updateTexImage starts working, the only safe course of action is
+        // to continue to ignore updates.
+        mUpdateTexImageFailed = true;
+
+        return outDirtyRegion;
+    }
+
+    if (queuedBuffer) {
+        // Autolock scope
+        auto currentFrameNumber = mConsumer->getFrameNumber();
+
+        Mutex::Autolock lock(mQueueItemLock);
+
+        // Remove any stale buffers that have been dropped during
+        // updateTexImage
+        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mQueueItems.removeAt(0);
+            android_atomic_dec(&mQueuedFrames);
+        }
+
+        const std::string layerName(getName().c_str());
+        mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
+        mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+
+        mQueueItems.removeAt(0);
+    }
+
+    // Decrement the queued-frames count.  Signal another event if we
+    // have more frames pending.
+    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
+        mAutoRefresh) {
+        mFlinger->signalLayerUpdate();
+    }
+
+    // update the active buffer
+    getBE().compositionInfo.mBuffer =
+            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
+    // replicated in LayerBE until FE/BE is ready to be synchronized
+    mActiveBuffer = getBE().compositionInfo.mBuffer;
+    if (getBE().compositionInfo.mBuffer == nullptr) {
+        // this can only happen if the very first buffer was rejected.
+        return outDirtyRegion;
+    }
+
+    mBufferLatched = true;
+    mPreviousFrameNumber = mCurrentFrameNumber;
+    mCurrentFrameNumber = mConsumer->getFrameNumber();
+
+    {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+    }
+
+    mRefreshPending = true;
+    mFrameLatencyNeeded = true;
+    if (oldBuffer == nullptr) {
+        // the first time we receive a buffer, we need to trigger a
+        // geometry invalidation.
+        recomputeVisibleRegions = true;
+    }
+
+    ui::Dataspace dataSpace = mConsumer->getCurrentDataSpace();
+    // treat modern dataspaces as legacy dataspaces whenever possible, until
+    // we can trust the buffer producers
+    switch (dataSpace) {
+        case ui::Dataspace::V0_SRGB:
+            dataSpace = ui::Dataspace::SRGB;
+            break;
+        case ui::Dataspace::V0_SRGB_LINEAR:
+            dataSpace = ui::Dataspace::SRGB_LINEAR;
+            break;
+        case ui::Dataspace::V0_JFIF:
+            dataSpace = ui::Dataspace::JFIF;
+            break;
+        case ui::Dataspace::V0_BT601_625:
+            dataSpace = ui::Dataspace::BT601_625;
+            break;
+        case ui::Dataspace::V0_BT601_525:
+            dataSpace = ui::Dataspace::BT601_525;
+            break;
+        case ui::Dataspace::V0_BT709:
+            dataSpace = ui::Dataspace::BT709;
+            break;
+        default:
+            break;
+    }
+    mCurrentDataSpace = dataSpace;
+
+    Rect crop(mConsumer->getCurrentCrop());
+    const uint32_t transform(mConsumer->getCurrentTransform());
+    const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
+    if ((crop != mCurrentCrop) ||
+        (transform != mCurrentTransform) ||
+        (scalingMode != mCurrentScalingMode)) {
+        mCurrentCrop = crop;
+        mCurrentTransform = transform;
+        mCurrentScalingMode = scalingMode;
+        recomputeVisibleRegions = true;
+    }
+
+    if (oldBuffer != nullptr) {
+        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
+        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) ||
+            bufHeight != uint32_t(oldBuffer->height)) {
+            recomputeVisibleRegions = true;
+        }
+    }
+
+    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
+    if (oldOpacity != isOpaque(s)) {
+        recomputeVisibleRegions = true;
+    }
+
+    // Remove any sync points corresponding to the buffer which was just
+    // latched
+    {
+        Mutex::Autolock lock(mLocalSyncPointMutex);
+        auto point = mLocalSyncPoints.begin();
+        while (point != mLocalSyncPoints.end()) {
+            if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
+                // This sync point must have been added since we started
+                // latching. Don't drop it yet.
+                ++point;
+                continue;
+            }
+
+            if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+                point = mLocalSyncPoints.erase(point);
+            } else {
+                ++point;
+            }
+        }
+    }
+
+    // FIXME: postedRegion should be dirty & bounds
+    Region dirtyRegion(Rect(s.active.w, s.active.h));
+
+    // transform the dirty region to window-manager space
+    outDirtyRegion = (getTransform().transform(dirtyRegion));
+
+    return outDirtyRegion;
+}
+
+void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    mConsumer->setDefaultBufferSize(w, h);
+}
+
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+    // Apply this display's projection's viewport to the visible region
+    // before giving it to the HWC HAL.
+    const Transform& tr = displayDevice->getTransform();
+    const auto& viewport = displayDevice->getViewport();
+    Region visible = tr.transform(visibleRegion.intersect(viewport));
+    auto hwcId = displayDevice->getHwcDisplayId();
+    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    auto& hwcLayer = hwcInfo.layer;
+    auto error = hwcLayer->setVisibleRegion(visible);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        visible.dump(LOG_TAG);
+    }
+
+    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        surfaceDamageRegion.dump(LOG_TAG);
+    }
+
+    // Sideband layers
+    if (getBE().compositionInfo.hwc.sidebandStream.get()) {
+        setCompositionType(hwcId, HWC2::Composition::Sideband);
+        ALOGV("[%s] Requesting Sideband composition", mName.string());
+        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
+        if (error != HWC2::Error::None) {
+            ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
+                  getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+                  static_cast<int32_t>(error));
+        }
+        return;
+    }
+
+    // Device or Cursor layers
+    if (mPotentialCursor) {
+        ALOGV("[%s] Requesting Cursor composition", mName.string());
+        setCompositionType(hwcId, HWC2::Composition::Cursor);
+    } else {
+        ALOGV("[%s] Requesting Device composition", mName.string());
+        setCompositionType(hwcId, HWC2::Composition::Device);
+    }
+
+    ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
+    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
+    error = hwcLayer->setPerFrameMetadata(displayDevice->getSupportedPerFrameMetadata(), metadata);
+    if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+        ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    uint32_t hwcSlot = 0;
+    sp<GraphicBuffer> hwcBuffer;
+    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
+                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
+
+    auto acquireFence = mConsumer->getCurrentFence();
+    error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+              getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
+}
+
+bool BufferLayer::isOpaque(const Layer::State& s) const {
+    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
+    // layer's opaque flag.
+    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
+        return false;
+    }
+
+    // if the layer has the opaque flag, then we're always opaque,
+    // otherwise we use the current buffer's format.
+    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
+}
+
+void BufferLayer::onFirstRef() {
+    Layer::onFirstRef();
+
+    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer, true);
+    mProducer = new MonitoredProducer(producer, mFlinger, this);
+    {
+        // Grab the SF state lock during this since it's the only safe way to access RenderEngine
+        Mutex::Autolock lock(mFlinger->mStateLock);
+        mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName,
+                                            this);
+    }
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+    mConsumer->setContentsChangedListener(this);
+    mConsumer->setName(mName);
+
+    if (mFlinger->isLayerTripleBufferingDisabled()) {
+        mProducer->setMaxDequeuedBufferCount(2);
+    }
+
+    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+    updateTransformHint(hw);
+}
+
+// ---------------------------------------------------------------------------
+// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
+// ---------------------------------------------------------------------------
+
+void BufferLayer::onFrameAvailable(const BufferItem& item) {
+    // Add this buffer from our internal queue tracker
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
+        mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+                                                 item.mGraphicBuffer->getHeight(),
+                                                 item.mFrameNumber);
+        // Reset the frame number tracker when we receive the first buffer after
+        // a frame number reset
+        if (item.mFrameNumber == 1) {
+            mLastFrameNumberReceived = 0;
+        }
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                                                               ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
+        mQueueItems.push_back(item);
+        android_atomic_inc(&mQueuedFrames);
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
+    }
+
+    mFlinger->signalLayerUpdate();
+}
+
+void BufferLayer::onFrameReplaced(const BufferItem& item) {
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                                                               ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
+        if (mQueueItems.empty()) {
+            ALOGE("Can't replace a frame on an empty queue");
+            return;
+        }
+        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
+    }
+}
+
+void BufferLayer::onSidebandStreamChanged() {
+    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+}
+
+bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
+    return mNeedsFiltering || renderArea.needsFiltering();
+}
+
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool BufferLayer::getOpacityForFormat(uint32_t format) {
+    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+        return true;
+    }
+    switch (format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+            return false;
+    }
+    // in all other case, we have no blending (also for unknown formats)
+    return true;
+}
+
+bool BufferLayer::isHdrY410() const {
+    // pixel format is HDR Y410 masquerading as RGBA_1010102
+    return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
+            mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
+            getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+}
+
+void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
+    ATRACE_CALL();
+    const State& s(getDrawingState());
+
+    computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
+
+    /*
+     * NOTE: the way we compute the texture coordinates here produces
+     * different results than when we take the HWC path -- in the later case
+     * the "source crop" is rounded to texel boundaries.
+     * This can produce significantly different results when the texture
+     * is scaled by a large amount.
+     *
+     * The GL code below is more logical (imho), and the difference with
+     * HWC is due to a limitation of the HWC API to integers -- a question
+     * is suspend is whether we should ignore this problem or revert to
+     * GL composition when a buffer scaling is applied (maybe with some
+     * minimal value)? Or, we could make GL behave like HWC -- but this feel
+     * like more of a hack.
+     */
+    const Rect bounds{computeBounds()}; // Rounds from FloatRect
+
+    Transform t = getTransform();
+    Rect win = bounds;
+    if (!s.finalCrop.isEmpty()) {
+        win = t.transform(win);
+        if (!win.intersect(s.finalCrop, &win)) {
+            win.clear();
+        }
+        win = t.inverse().transform(win);
+        if (!win.intersect(bounds, &win)) {
+            win.clear();
+        }
+    }
+
+    float left = float(win.left) / float(s.active.w);
+    float top = float(win.top) / float(s.active.h);
+    float right = float(win.right) / float(s.active.w);
+    float bottom = float(win.bottom) / float(s.active.h);
+
+    // TODO: we probably want to generate the texture coords with the mesh
+    // here we assume that we only have 4 vertices
+    Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
+    texCoords[0] = vec2(left, 1.0f - top);
+    texCoords[1] = vec2(left, 1.0f - bottom);
+    texCoords[2] = vec2(right, 1.0f - bottom);
+    texCoords[3] = vec2(right, 1.0f - top);
+
+    auto& engine(mFlinger->getRenderEngine());
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
+                              getColor());
+    engine.setSourceDataSpace(mCurrentDataSpace);
+
+    if (isHdrY410()) {
+        engine.setSourceY410BT2020(true);
+    }
+
+    engine.drawMesh(getBE().mMesh);
+    engine.disableBlending();
+
+    engine.setSourceY410BT2020(false);
+}
+
+uint32_t BufferLayer::getProducerStickyTransform() const {
+    int producerStickyTransform = 0;
+    int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
+    if (ret != OK) {
+        ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
+              strerror(-ret), ret);
+        return 0;
+    }
+    return static_cast<uint32_t>(producerStickyTransform);
+}
+
+bool BufferLayer::latchUnsignaledBuffers() {
+    static bool propertyLoaded = false;
+    static bool latch = false;
+    static std::mutex mutex;
+    std::lock_guard<std::mutex> lock(mutex);
+    if (!propertyLoaded) {
+        char value[PROPERTY_VALUE_MAX] = {};
+        property_get("debug.sf.latch_unsignaled", value, "0");
+        latch = atoi(value);
+        propertyLoaded = true;
+    }
+    return latch;
+}
+
+uint64_t BufferLayer::getHeadFrameNumber() const {
+    Mutex::Autolock lock(mQueueItemLock);
+    if (!mQueueItems.empty()) {
+        return mQueueItems[0].mFrameNumber;
+    } else {
+        return mCurrentFrameNumber;
+    }
+}
+
+bool BufferLayer::headFenceHasSignaled() const {
+    if (latchUnsignaledBuffers()) {
+        return true;
+    }
+
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        return true;
+    }
+    if (mQueueItems[0].mIsDroppable) {
+        // Even though this buffer's fence may not have signaled yet, it could
+        // be replaced by another buffer before it has a chance to, which means
+        // that it's possible to get into a situation where a buffer is never
+        // able to be latched. To avoid this, grab this buffer anyway.
+        return true;
+    }
+    return mQueueItems[0].mFenceTime->getSignalTime() !=
+            Fence::SIGNAL_TIME_PENDING;
+}
+
+uint32_t BufferLayer::getEffectiveScalingMode() const {
+    if (mOverrideScalingMode >= 0) {
+        return mOverrideScalingMode;
+    }
+    return mCurrentScalingMode;
+}
+
+// ----------------------------------------------------------------------------
+// transaction
+// ----------------------------------------------------------------------------
+
+void BufferLayer::notifyAvailableFrames() {
+    auto headFrameNumber = getHeadFrameNumber();
+    bool headFenceSignaled = headFenceHasSignaled();
+    Mutex::Autolock lock(mLocalSyncPointMutex);
+    for (auto& point : mLocalSyncPoints) {
+        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+            point->setFrameAvailable();
+        }
+    }
+}
+
+sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
+    return mProducer;
+}
+
+// ---------------------------------------------------------------------------
+// h/w composer set-up
+// ---------------------------------------------------------------------------
+
+bool BufferLayer::allTransactionsSignaled() {
+    auto headFrameNumber = getHeadFrameNumber();
+    bool matchingFramesFound = false;
+    bool allTransactionsApplied = true;
+    Mutex::Autolock lock(mLocalSyncPointMutex);
+
+    for (auto& point : mLocalSyncPoints) {
+        if (point->getFrameNumber() > headFrameNumber) {
+            break;
+        }
+        matchingFramesFound = true;
+
+        if (!point->frameIsAvailable()) {
+            // We haven't notified the remote layer that the frame for
+            // this point is available yet. Notify it now, and then
+            // abort this attempt to latch.
+            point->setFrameAvailable();
+            allTransactionsApplied = false;
+            break;
+        }
+
+        allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
+    }
+    return !matchingFramesFound || allTransactionsApplied;
+}
+
+} // namespace android
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
new file mode 100644
index 0000000..bf0ca69
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BufferLayerConsumer.h"
+#include "Client.h"
+#include "Layer.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "FrameTracker.h"
+#include "LayerVector.h"
+#include "MonitoredProducer.h"
+#include "RenderEngine/Mesh.h"
+#include "RenderEngine/Texture.h"
+#include "SurfaceFlinger.h"
+#include "Transform.h"
+
+#include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+
+#include <ui/FrameStats.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <list>
+
+namespace android {
+
+/*
+ * A new BufferQueue and a new BufferLayerConsumer are created when the
+ * BufferLayer is first referenced.
+ *
+ * This also implements onFrameAvailable(), which notifies SurfaceFlinger
+ * that new data has arrived.
+ */
+class BufferLayer : public Layer, public BufferLayerConsumer::ContentsChangedListener {
+public:
+    BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+                uint32_t h, uint32_t flags);
+
+    ~BufferLayer() override;
+
+    // If we have received a new buffer this frame, we will pass its surface
+    // damage down to hardware composer. Otherwise, we must send a region with
+    // one empty rect.
+    void useSurfaceDamage();
+    void useEmptyDamage();
+
+    // -----------------------------------------------------------------------
+    // Overriden from Layer
+    // -----------------------------------------------------------------------
+
+    /*
+     * getTypeId - Provide unique string for each class type in the Layer
+     * hierarchy
+     */
+    const char* getTypeId() const override { return "BufferLayer"; }
+
+    /*
+     * isProtected - true if the layer may contain protected content in the
+     * GRALLOC_USAGE_PROTECTED sense.
+     */
+    bool isProtected() const;
+
+    /*
+     * isVisible - true if this layer is visible, false otherwise
+     */
+    bool isVisible() const override;
+
+    /*
+     * isFixedSize - true if content has a fixed size
+     */
+    bool isFixedSize() const override;
+
+    // the this layer's size and format
+    status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+    /*
+     * onDraw - draws the surface.
+     */
+    void onDraw(const RenderArea& renderArea, const Region& clip,
+                bool useIdentityTransform) const override;
+
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
+    void abandon() override;
+    bool shouldPresentNow(const DispSync& dispSync) const override;
+    void setTransformHint(uint32_t orientation) const override;
+    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+                           const std::shared_ptr<FenceTime>& presentFence,
+                           const CompositorTiming& compositorTiming) override;
+    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
+    bool getTransformToDisplayInverse() const override;
+
+public:
+    bool onPreComposition(nsecs_t refreshStartTime) override;
+
+    // If a buffer was replaced this frame, release the former buffer
+    void releasePendingBuffer(nsecs_t dequeueReadyTime);
+
+    /*
+     * latchBuffer - called each time the screen is redrawn and returns whether
+     * the visible regions need to be recomputed (this is a fairly heavy
+     * operation, so this should be set only if needed). Typically this is used
+     * to figure out if the content or size of a surface has changed.
+     */
+    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+    bool isBufferLatched() const override { return mRefreshPending; }
+    void setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+    bool isHdrY410() const override;
+
+    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+
+    bool isOpaque(const Layer::State& s) const override;
+
+private:
+    void onFirstRef() override;
+
+    // Interface implementation for
+    // BufferLayerConsumer::ContentsChangedListener
+    void onFrameAvailable(const BufferItem& item) override;
+    void onFrameReplaced(const BufferItem& item) override;
+    void onSidebandStreamChanged() override;
+
+    // needsLinearFiltering - true if this surface's state requires filtering
+    bool needsFiltering(const RenderArea& renderArea) const;
+
+    static bool getOpacityForFormat(uint32_t format);
+
+    // drawing
+    void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+
+    // Temporary - Used only for LEGACY camera mode.
+    uint32_t getProducerStickyTransform() const;
+
+    // Loads the corresponding system property once per process
+    static bool latchUnsignaledBuffers();
+
+    uint64_t getHeadFrameNumber() const;
+    bool headFenceHasSignaled() const;
+
+    // Returns the current scaling mode, unless mOverrideScalingMode
+    // is set, in which case, it returns mOverrideScalingMode
+    uint32_t getEffectiveScalingMode() const override;
+
+public:
+    void notifyAvailableFrames() override;
+
+    PixelFormat getPixelFormat() const override { return mFormat; }
+    sp<IGraphicBufferProducer> getProducer() const;
+
+private:
+    sp<BufferLayerConsumer> mConsumer;
+
+    // Check all of the local sync points to ensure that all transactions
+    // which need to have been applied prior to the frame which is about to
+    // be latched have signaled
+    bool allTransactionsSignaled();
+    sp<IGraphicBufferProducer> mProducer;
+
+    // constants
+    uint32_t mTextureName; // from GLES
+    PixelFormat mFormat;
+
+    // main thread
+    uint32_t mCurrentScalingMode;
+    bool mBufferLatched = false;   // TODO: Use mActiveBuffer?
+    uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
+    // The texture used to draw the layer in GLES composition mode
+    mutable Texture mTexture;
+
+    bool mUpdateTexImageFailed; // This is only accessed on the main thread.
+    bool mRefreshPending;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
new file mode 100644
index 0000000..87333d0
--- /dev/null
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "BufferLayerConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include "BufferLayerConsumer.h"
+
+#include "DispSync.h"
+#include "Layer.h"
+#include "RenderEngine/Image.h"
+#include "RenderEngine/RenderEngine.h"
+
+#include <inttypes.h>
+
+#include <cutils/compiler.h>
+
+#include <hardware/hardware.h>
+
+#include <math/mat4.h>
+
+#include <gui/BufferItem.h>
+#include <gui/GLConsumer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/gui/ComposerService.h>
+#include <private/gui/SyncFeatures.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+// Macros for including the BufferLayerConsumer name in log messages
+#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
+//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+
+static const mat4 mtxIdentity;
+
+BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq,
+                                         RE::RenderEngine& engine, uint32_t tex, Layer* layer)
+      : ConsumerBase(bq, false),
+        mCurrentCrop(Rect::EMPTY_RECT),
+        mCurrentTransform(0),
+        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+        mCurrentFence(Fence::NO_FENCE),
+        mCurrentTimestamp(0),
+        mCurrentDataSpace(ui::Dataspace::UNKNOWN),
+        mCurrentFrameNumber(0),
+        mCurrentTransformToDisplayInverse(false),
+        mCurrentSurfaceDamage(),
+        mCurrentApi(0),
+        mDefaultWidth(1),
+        mDefaultHeight(1),
+        mFilteringEnabled(true),
+        mRE(engine),
+        mTexName(tex),
+        mLayer(layer),
+        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
+    BLC_LOGV("BufferLayerConsumer");
+
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
+
+    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+}
+
+status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
+        return NO_INIT;
+    }
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return mConsumer->setDefaultBufferSize(w, h);
+}
+
+void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) {
+    setFrameAvailableListener(listener);
+    Mutex::Autolock lock(mMutex);
+    mContentsChangedListener = listener;
+}
+
+// We need to determine the time when a buffer acquired now will be
+// displayed.  This can be calculated:
+//   time when previous buffer's actual-present fence was signaled
+//    + current display refresh rate * HWC latency
+//    + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing.  If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it.  We
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss.  We want to do it here, not in every app.  A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) {
+    // The HWC doesn't currently have a way to report additional latency.
+    // Assume that whatever we submit now will appear right after the flip.
+    // For a smart panel this might be 1.  This is expressed in frames,
+    // rather than time, because we expect to have a constant frame delay
+    // regardless of the refresh rate.
+    const uint32_t hwcLatency = 0;
+
+    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
+
+    // The DispSync time is already adjusted for the difference between
+    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
+    // we don't need to factor that in here.  Pad a little to avoid
+    // weird effects if apps might be requesting times right on the edge.
+    nsecs_t extraPadding = 0;
+    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
+        extraPadding = 1000000; // 1ms (6% of 60Hz)
+    }
+
+    return nextRefresh + extraPadding;
+}
+
+status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+                                             bool* autoRefresh, bool* queuedBuffer,
+                                             uint64_t maxFrameNumber) {
+    ATRACE_CALL();
+    BLC_LOGV("updateTexImage");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
+        return NO_INIT;
+    }
+
+    // Make sure RenderEngine is current
+    if (!mRE.isCurrent()) {
+        BLC_LOGE("updateTexImage: RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+
+    BufferItem item;
+
+    // Acquire the next buffer.
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
+    if (err != NO_ERROR) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            err = NO_ERROR;
+        } else if (err == BufferQueue::PRESENT_LATER) {
+            // return the error, without logging
+        } else {
+            BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
+        }
+        return err;
+    }
+
+    if (autoRefresh) {
+        *autoRefresh = item.mAutoRefresh;
+    }
+
+    if (queuedBuffer) {
+        *queuedBuffer = item.mQueuedBuffer;
+    }
+
+    // We call the rejecter here, in case the caller has a reason to
+    // not accept this buffer.  This is used by SurfaceFlinger to
+    // reject buffers which have the wrong size
+    int slot = item.mSlot;
+    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
+        return BUFFER_REJECTED;
+    }
+
+    // Release the previous buffer.
+    err = updateAndReleaseLocked(item, &mPendingRelease);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+        // Bind the new buffer to the GL texture.
+        //
+        // Older devices require the "implicit" synchronization provided
+        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
+        // devices will either call this in Layer::onDraw, or (if it's not
+        // a GL-composited layer) not at all.
+        err = bindTextureImageLocked();
+    }
+
+    return err;
+}
+
+status_t BufferLayerConsumer::bindTextureImage() {
+    Mutex::Autolock lock(mMutex);
+    return bindTextureImageLocked();
+}
+
+void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
+    if (!fence->isValid()) {
+        return;
+    }
+
+    auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture;
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
+        return;
+    }
+
+    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
+                                            : mCurrentTextureImage->graphicBuffer();
+    auto err = addReleaseFence(slot, buffer, fence);
+    if (err != OK) {
+        BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
+    }
+}
+
+bool BufferLayerConsumer::releasePendingBuffer() {
+    if (!mPendingRelease.isPending) {
+        BLC_LOGV("Pending buffer already released");
+        return false;
+    }
+    BLC_LOGV("Releasing pending buffer");
+    Mutex::Autolock lock(mMutex);
+    status_t result =
+            releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer);
+    if (result < NO_ERROR) {
+        BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result);
+    }
+    mPendingRelease = PendingRelease();
+    return true;
+}
+
+sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const {
+    Mutex::Autolock lock(mMutex);
+    return ConsumerBase::mPrevFinalReleaseFence;
+}
+
+status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+                                                  uint64_t maxFrameNumber) {
+    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // If item->mGraphicBuffer is not null, this buffer has not been acquired
+    // before, so any prior EglImage created is using a stale buffer. This
+    // replaces any old EglImage with a new one (using the new buffer).
+    if (item->mGraphicBuffer != nullptr) {
+        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
+    }
+
+    return NO_ERROR;
+}
+
+bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
+    // If the crop rect is not at the origin, we can't set the crop on the
+    // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+    // extension.  In the future we can add a layered extension that
+    // removes this restriction if there is hardware that can support it.
+    return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
+}
+
+status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
+                                                     PendingRelease* pendingRelease) {
+    status_t err = NO_ERROR;
+
+    int slot = item.mSlot;
+
+    // Do whatever sync ops we need to do before releasing the old slot.
+    if (slot != mCurrentTexture) {
+        err = syncForReleaseLocked();
+        if (err != NO_ERROR) {
+            // Release the buffer we just acquired.  It's not safe to
+            // release the old buffer, so instead we just drop the new frame.
+            // As we are still under lock since acquireBuffer, it is safe to
+            // release by slot.
+            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
+            return err;
+        }
+    }
+
+    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
+             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
+             slot, mSlots[slot].mGraphicBuffer->handle);
+
+    // Hang onto the pointer so that it isn't freed in the call to
+    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
+    // the same.
+    sp<Image> nextTextureImage = mImages[slot];
+
+    // release old buffer
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        if (pendingRelease == nullptr) {
+            status_t status =
+                    releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
+            if (status < NO_ERROR) {
+                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
+                         status);
+                err = status;
+                // keep going, with error raised [?]
+            }
+        } else {
+            pendingRelease->currentTexture = mCurrentTexture;
+            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
+            pendingRelease->isPending = true;
+        }
+    }
+
+    // Update the BufferLayerConsumer state.
+    mCurrentTexture = slot;
+    mCurrentTextureImage = nextTextureImage;
+    mCurrentCrop = item.mCrop;
+    mCurrentTransform = item.mTransform;
+    mCurrentScalingMode = item.mScalingMode;
+    mCurrentTimestamp = item.mTimestamp;
+    mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace);
+    mCurrentHdrMetadata = item.mHdrMetadata;
+    mCurrentFence = item.mFence;
+    mCurrentFenceTime = item.mFenceTime;
+    mCurrentFrameNumber = item.mFrameNumber;
+    mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
+    mCurrentSurfaceDamage = item.mSurfaceDamage;
+    mCurrentApi = item.mApi;
+
+    computeCurrentTransformMatrixLocked();
+
+    return err;
+}
+
+status_t BufferLayerConsumer::bindTextureImageLocked() {
+    ATRACE_CALL();
+    mRE.checkErrors();
+
+    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
+        BLC_LOGE("bindTextureImage: no currently-bound texture");
+        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
+        return NO_INIT;
+    }
+
+    const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
+    status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
+    if (err != NO_ERROR) {
+        BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
+        return UNKNOWN_ERROR;
+    }
+
+    mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
+
+    // Wait for the new buffer to be ready.
+    return doFenceWaitLocked();
+}
+
+status_t BufferLayerConsumer::syncForReleaseLocked() {
+    BLC_LOGV("syncForReleaseLocked");
+
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        if (SyncFeatures::getInstance().useNativeFenceSync()) {
+            base::unique_fd fenceFd = mRE.flush();
+            if (fenceFd == -1) {
+                BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
+                return UNKNOWN_ERROR;
+            }
+            sp<Fence> fence(new Fence(std::move(fenceFd)));
+            status_t err = addReleaseFenceLocked(mCurrentTexture,
+                                                 mCurrentTextureImage->graphicBuffer(), fence);
+            if (err != OK) {
+                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
+                         "%s (%d)",
+                         strerror(-err), err);
+                return err;
+            }
+        }
+    }
+
+    return OK;
+}
+
+void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
+    Mutex::Autolock lock(mMutex);
+    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
+        return;
+    }
+    bool needsRecompute = mFilteringEnabled != enabled;
+    mFilteringEnabled = enabled;
+
+    if (needsRecompute && mCurrentTextureImage == nullptr) {
+        BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == nullptr");
+    }
+
+    if (needsRecompute && mCurrentTextureImage != nullptr) {
+        computeCurrentTransformMatrixLocked();
+    }
+}
+
+void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
+    BLC_LOGV("computeCurrentTransformMatrixLocked");
+    sp<GraphicBuffer> buf =
+            (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
+    if (buf == nullptr) {
+        BLC_LOGD("computeCurrentTransformMatrixLocked: "
+                 "mCurrentTextureImage is nullptr");
+    }
+    const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
+                                       mFilteringEnabled);
+}
+
+nsecs_t BufferLayerConsumer::getTimestamp() {
+    BLC_LOGV("getTimestamp");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTimestamp;
+}
+
+ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() {
+    BLC_LOGV("getCurrentDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentDataSpace;
+}
+
+const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const {
+    BLC_LOGV("getCurrentHdrMetadata");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentHdrMetadata;
+}
+
+uint64_t BufferLayerConsumer::getFrameNumber() {
+    BLC_LOGV("getFrameNumber");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFrameNumber;
+}
+
+bool BufferLayerConsumer::getTransformToDisplayInverse() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTransformToDisplayInverse;
+}
+
+const Region& BufferLayerConsumer::getSurfaceDamage() const {
+    return mCurrentSurfaceDamage;
+}
+
+int BufferLayerConsumer::getCurrentApi() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentApi;
+}
+
+sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
+    Mutex::Autolock lock(mMutex);
+
+    if (outSlot != nullptr) {
+        *outSlot = mCurrentTexture;
+    }
+
+    return (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
+}
+
+Rect BufferLayerConsumer::getCurrentCrop() const {
+    Mutex::Autolock lock(mMutex);
+    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+            ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+            : mCurrentCrop;
+}
+
+uint32_t BufferLayerConsumer::getCurrentTransform() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTransform;
+}
+
+uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentScalingMode;
+}
+
+sp<Fence> BufferLayerConsumer::getCurrentFence() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFence;
+}
+
+std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFenceTime;
+}
+
+status_t BufferLayerConsumer::doFenceWaitLocked() const {
+    if (!mRE.isCurrent()) {
+        BLC_LOGE("doFenceWait: RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+
+    if (mCurrentFence->isValid()) {
+        if (SyncFeatures::getInstance().useWaitSync()) {
+            base::unique_fd fenceFd(mCurrentFence->dup());
+            if (fenceFd == -1) {
+                BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
+                return -errno;
+            }
+            if (!mRE.waitFence(std::move(fenceFd))) {
+                BLC_LOGE("doFenceWait: failed to wait on fence fd");
+                return UNKNOWN_ERROR;
+            }
+        } else {
+            status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked");
+            if (err != NO_ERROR) {
+                BLC_LOGE("doFenceWait: error waiting for fence: %d", err);
+                return err;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
+    BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    if (slotIndex == mCurrentTexture) {
+        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+    }
+    mImages[slotIndex].clear();
+    ConsumerBase::freeBufferLocked(slotIndex);
+}
+
+void BufferLayerConsumer::onDisconnect() {
+    sp<Layer> l = mLayer.promote();
+    if (l.get()) {
+        l->onDisconnect();
+    }
+}
+
+void BufferLayerConsumer::onSidebandStreamChanged() {
+    FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+    {
+        Mutex::Autolock lock(mFrameAvailableMutex);
+        unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
+    }
+    sp<ContentsChangedListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
+        listener = mContentsChangedListener.promote();
+    }
+
+    if (listener != nullptr) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
+void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+                                                   FrameEventHistoryDelta* outDelta) {
+    sp<Layer> l = mLayer.promote();
+    if (l.get()) {
+        l->addAndGetFrameTimestamps(newTimestamps, outDelta);
+    }
+}
+
+void BufferLayerConsumer::abandonLocked() {
+    BLC_LOGV("abandonLocked");
+    mCurrentTextureImage.clear();
+    ConsumerBase::abandonLocked();
+}
+
+status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
+    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
+}
+
+void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
+    result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
+                        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+                        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
+                        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
+                        mCurrentTransform);
+
+    ConsumerBase::dumpLocked(result, prefix);
+}
+
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine)
+      : mGraphicBuffer(graphicBuffer),
+        mImage{engine.createImage()},
+        mCreated(false),
+        mCropWidth(0),
+        mCropHeight(0) {}
+
+BufferLayerConsumer::Image::~Image() = default;
+
+status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
+    const int32_t cropWidth = imageCrop.width();
+    const int32_t cropHeight = imageCrop.height();
+    if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
+        return OK;
+    }
+
+    mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
+                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
+                                             cropWidth, cropHeight);
+    if (mCreated) {
+        mCropWidth = cropWidth;
+        mCropHeight = cropHeight;
+    } else {
+        mCropWidth = 0;
+        mCropHeight = 0;
+
+        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
+              buffer->getPixelFormat());
+    }
+
+    return mCreated ? OK : UNKNOWN_ERROR;
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
new file mode 100644
index 0000000..f81cdb1
--- /dev/null
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2010 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 ANDROID_BUFFERLAYERCONSUMER_H
+#define ANDROID_BUFFERLAYERCONSUMER_H
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/ConsumerBase.h>
+#include <gui/HdrMetadata.h>
+
+#include <ui/FenceTime.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Region.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class DispSync;
+class Layer;
+class String8;
+
+namespace RE {
+class RenderEngine;
+class Image;
+} // namespace RE
+
+/*
+ * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
+ * and makes them available to RenderEngine as a texture.
+ *
+ * A typical usage pattern is to call updateTexImage() when a new frame is
+ * desired.  If a new frame is available, the frame is latched.  If not, the
+ * previous contents are retained.  The texture is attached and updated after
+ * bindTextureImage() is called.
+ *
+ * All calls to updateTexImage must be made with RenderEngine being current.
+ * The texture is attached to the TEXTURE_EXTERNAL texture target.
+ */
+class BufferLayerConsumer : public ConsumerBase {
+public:
+    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
+    class BufferRejecter {
+        friend class BufferLayerConsumer;
+        virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0;
+
+    protected:
+        virtual ~BufferRejecter() {}
+    };
+
+    struct ContentsChangedListener : public FrameAvailableListener {
+        virtual void onSidebandStreamChanged() = 0;
+    };
+
+    // BufferLayerConsumer constructs a new BufferLayerConsumer object.  The
+    // tex parameter indicates the name of the RenderEngine texture to which
+    // images are to be streamed.
+    BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RE::RenderEngine& engine,
+                        uint32_t tex, Layer* layer);
+
+    // Sets the contents changed listener. This should be used instead of
+    // ConsumerBase::setFrameAvailableListener().
+    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
+
+    nsecs_t computeExpectedPresent(const DispSync& dispSync);
+
+    // updateTexImage acquires the most recently queued buffer, and sets the
+    // image contents of the target texture to it.
+    //
+    // This call may only be made while RenderEngine is current.
+    //
+    // This calls doFenceWait to ensure proper synchronization unless native
+    // fence is supported.
+    //
+    // Unlike the GLConsumer version, this version takes a functor that may be
+    // used to reject the newly acquired buffer.  It also does not bind the
+    // RenderEngine texture until bindTextureImage is called.
+    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
+                            bool* queuedBuffer, uint64_t maxFrameNumber);
+
+    // See BufferLayerConsumer::bindTextureImageLocked().
+    status_t bindTextureImage();
+
+    // setReleaseFence stores a fence that will signal when the current buffer
+    // is no longer being read. This fence will be returned to the producer
+    // when the current buffer is released by updateTexImage(). Multiple
+    // fences can be set for a given buffer; they will be merged into a single
+    // union fence.
+    void setReleaseFence(const sp<Fence>& fence);
+
+    bool releasePendingBuffer();
+
+    sp<Fence> getPrevFinalReleaseFence() const;
+
+    // See GLConsumer::getTransformMatrix.
+    void getTransformMatrix(float mtx[16]);
+
+    // getTimestamp retrieves the timestamp associated with the texture image
+    // set by the most recent call to updateTexImage.
+    //
+    // The timestamp is in nanoseconds, and is monotonically increasing. Its
+    // other semantics (zero point, etc) are source-dependent and should be
+    // documented by the source.
+    int64_t getTimestamp();
+
+    // getDataSpace retrieves the DataSpace associated with the texture image
+    // set by the most recent call to updateTexImage.
+    ui::Dataspace getCurrentDataSpace();
+
+    // getCurrentHdrMetadata retrieves the HDR metadata associated with the
+    // texture image set by the most recent call to updateTexImage.
+    const HdrMetadata& getCurrentHdrMetadata() const;
+
+    // getFrameNumber retrieves the frame number associated with the texture
+    // image set by the most recent call to updateTexImage.
+    //
+    // The frame number is an incrementing counter set to 0 at the creation of
+    // the BufferQueue associated with this consumer.
+    uint64_t getFrameNumber();
+
+    bool getTransformToDisplayInverse() const;
+
+    // must be called from SF main thread
+    const Region& getSurfaceDamage() const;
+
+    // getCurrentApi retrieves the API which queues the current buffer.
+    int getCurrentApi() const;
+
+    // See GLConsumer::setDefaultBufferSize.
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // setFilteringEnabled sets whether the transform matrix should be computed
+    // for use with bilinear filtering.
+    void setFilteringEnabled(bool enabled);
+
+    // getCurrentBuffer returns the buffer associated with the current image.
+    // When outSlot is not nullptr, the current buffer slot index is also
+    // returned.
+    sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
+
+    // getCurrentCrop returns the cropping rectangle of the current buffer.
+    Rect getCurrentCrop() const;
+
+    // getCurrentTransform returns the transform of the current buffer.
+    uint32_t getCurrentTransform() const;
+
+    // getCurrentScalingMode returns the scaling mode of the current buffer.
+    uint32_t getCurrentScalingMode() const;
+
+    // getCurrentFence returns the fence indicating when the current buffer is
+    // ready to be read from.
+    sp<Fence> getCurrentFence() const;
+
+    // getCurrentFence returns the FenceTime indicating when the current
+    // buffer is ready to be read from.
+    std::shared_ptr<FenceTime> getCurrentFenceTime() const;
+
+    // setConsumerUsageBits overrides the ConsumerBase method to OR
+    // DEFAULT_USAGE_FLAGS to usage.
+    status_t setConsumerUsageBits(uint64_t usage);
+
+protected:
+    // abandonLocked overrides the ConsumerBase method to clear
+    // mCurrentTextureImage in addition to the ConsumerBase behavior.
+    virtual void abandonLocked();
+
+    // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer-
+    // specific info in addition to the ConsumerBase behavior.
+    virtual void dumpLocked(String8& result, const char* prefix) const;
+
+    // acquireBufferLocked overrides the ConsumerBase method to update the
+    // mImages array in addition to the ConsumerBase behavior.
+    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+                                         uint64_t maxFrameNumber = 0) override;
+
+    bool canUseImageCrop(const Rect& crop) const;
+
+    struct PendingRelease {
+        PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {}
+
+        bool isPending;
+        int currentTexture;
+        sp<GraphicBuffer> graphicBuffer;
+    };
+
+    // This releases the buffer in the slot referenced by mCurrentTexture,
+    // then updates state to refer to the BufferItem, which must be a
+    // newly-acquired buffer. If pendingRelease is not null, the parameters
+    // which would have been passed to releaseBufferLocked upon the successful
+    // completion of the method will instead be returned to the caller, so that
+    // it may call releaseBufferLocked itself later.
+    status_t updateAndReleaseLocked(const BufferItem& item,
+                                    PendingRelease* pendingRelease = nullptr);
+
+    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.  Uses
+    // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
+    // bind succeeds, this calls doFenceWait.
+    status_t bindTextureImageLocked();
+
+private:
+    // Image is a utility class for tracking and creating RE::Images. There
+    // is primarily just one image per slot, but there is also special cases:
+    //  - After freeBuffer, we must still keep the current image/buffer
+    // Reference counting RE::Images lets us handle all these cases easily while
+    // also only creating new RE::Images from buffers when required.
+    class Image : public LightRefBase<Image> {
+    public:
+        Image(sp<GraphicBuffer> graphicBuffer, RE::RenderEngine& engine);
+
+        Image(const Image& rhs) = delete;
+        Image& operator=(const Image& rhs) = delete;
+
+        // createIfNeeded creates an RE::Image if required (we haven't created
+        // one yet, or the crop-rect has changed).
+        status_t createIfNeeded(const Rect& imageCrop);
+
+        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+        const native_handle* graphicBufferHandle() {
+            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
+        }
+
+        const RE::Image& image() const { return *mImage; }
+
+    private:
+        // Only allow instantiation using ref counting.
+        friend class LightRefBase<Image>;
+        virtual ~Image();
+
+        // mGraphicBuffer is the buffer that was used to create this image.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mImage is the image created from mGraphicBuffer.
+        std::unique_ptr<RE::Image> mImage;
+        bool mCreated;
+        int32_t mCropWidth;
+        int32_t mCropHeight;
+    };
+
+    // freeBufferLocked frees up the given buffer slot. If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in
+    // that slot and destroy the RE::Image in that slot.  Otherwise it has no
+    // effect.
+    //
+    // This method must be called with mMutex locked.
+    virtual void freeBufferLocked(int slotIndex);
+
+    // IConsumerListener interface
+    void onDisconnect() override;
+    void onSidebandStreamChanged() override;
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+                                  FrameEventHistoryDelta* outDelta) override;
+
+    // computeCurrentTransformMatrixLocked computes the transform matrix for the
+    // current texture.  It uses mCurrentTransform and the current GraphicBuffer
+    // to compute this matrix and stores it in mCurrentTransformMatrix.
+    // mCurrentTextureImage must not be nullptr.
+    void computeCurrentTransformMatrixLocked();
+
+    // doFenceWaitLocked inserts a wait command into the RenderEngine command
+    // stream to ensure that it is safe for future RenderEngine commands to
+    // access the current texture buffer.
+    status_t doFenceWaitLocked() const;
+
+    // syncForReleaseLocked performs the synchronization needed to release the
+    // current slot from RenderEngine.  If needed it will set the current
+    // slot's fence to guard against a producer accessing the buffer before
+    // the outstanding accesses have completed.
+    status_t syncForReleaseLocked();
+
+    // The default consumer usage flags that BufferLayerConsumer always sets on its
+    // BufferQueue instance; these will be OR:d with any additional flags passed
+    // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
+    // consume buffers as hardware textures.
+    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+
+    // mCurrentTextureImage is the Image/buffer of the current texture. It's
+    // possible that this buffer is not associated with any buffer slot, so we
+    // must track it separately in order to support the getCurrentBuffer method.
+    sp<Image> mCurrentTextureImage;
+
+    // mCurrentCrop is the crop rectangle that applies to the current texture.
+    // It gets set each time updateTexImage is called.
+    Rect mCurrentCrop;
+
+    // mCurrentTransform is the transform identifier for the current texture. It
+    // gets set each time updateTexImage is called.
+    uint32_t mCurrentTransform;
+
+    // mCurrentScalingMode is the scaling mode for the current texture. It gets
+    // set each time updateTexImage is called.
+    uint32_t mCurrentScalingMode;
+
+    // mCurrentFence is the fence received from BufferQueue in updateTexImage.
+    sp<Fence> mCurrentFence;
+
+    // The FenceTime wrapper around mCurrentFence.
+    std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
+
+    // mCurrentTransformMatrix is the transform matrix for the current texture.
+    // It gets computed by computeTransformMatrix each time updateTexImage is
+    // called.
+    float mCurrentTransformMatrix[16];
+
+    // mCurrentTimestamp is the timestamp for the current texture. It
+    // gets set each time updateTexImage is called.
+    int64_t mCurrentTimestamp;
+
+    // mCurrentDataSpace is the dataspace for the current texture. It
+    // gets set each time updateTexImage is called.
+    ui::Dataspace mCurrentDataSpace;
+
+    // mCurrentHdrMetadata is the HDR metadata for the current texture. It
+    // gets set each time updateTexImage is called.
+    HdrMetadata mCurrentHdrMetadata;
+
+    // mCurrentFrameNumber is the frame counter for the current texture.
+    // It gets set each time updateTexImage is called.
+    uint64_t mCurrentFrameNumber;
+
+    // Indicates this buffer must be transformed by the inverse transform of the screen
+    // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform.
+    // This must be set/read from SurfaceFlinger's main thread.
+    bool mCurrentTransformToDisplayInverse;
+
+    // The portion of this surface that has changed since the previous frame
+    Region mCurrentSurfaceDamage;
+
+    int mCurrentApi;
+
+    uint32_t mDefaultWidth, mDefaultHeight;
+
+    // mFilteringEnabled indicates whether the transform matrix is computed for
+    // use with bilinear filtering. It defaults to true and is changed by
+    // setFilteringEnabled().
+    bool mFilteringEnabled;
+
+    RE::RenderEngine& mRE;
+
+    // mTexName is the name of the RenderEngine texture to which streamed
+    // images will be bound when bindTexImage is called. It is set at
+    // construction time.
+    const uint32_t mTexName;
+
+    // The layer for this BufferLayerConsumer
+    const wp<Layer> mLayer;
+
+    wp<ContentsChangedListener> mContentsChangedListener;
+
+    // mImages stores the buffers that have been allocated by the BufferQueue
+    // for each buffer slot.  It is initialized to null pointers, and gets
+    // filled in with the result of BufferQueue::acquire when the
+    // client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+    int mCurrentTexture;
+
+    // A release that is pending on the receipt of a new release fence from
+    // presentDisplay
+    PendingRelease mPendingRelease;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFERLAYERCONSUMER_H
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 8ba6cb9..0b59147 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -47,18 +47,32 @@
 
 Client::~Client()
 {
+    // We need to post a message to remove our remaining layers rather than
+    // do so directly by acquiring the SurfaceFlinger lock. If we were to
+    // attempt to directly call the lock it becomes effectively impossible
+    // to use sp<Client> while holding the SF lock as descoping it could
+    // then trigger a dead-lock.
+
     const size_t count = mLayers.size();
     for (size_t i=0 ; i<count ; i++) {
         sp<Layer> l = mLayers.valueAt(i).promote();
-        if (l != nullptr) {
-            mFlinger->removeLayer(l);
+        if (l == nullptr) {
+            continue;
         }
+        mFlinger->postMessageAsync(new LambdaMessage([flinger = mFlinger, l]() {
+            flinger->removeLayer(l);
+        }));
     }
 }
 
-void Client::setParentLayer(const sp<Layer>& parentLayer) {
+void Client::updateParent(const sp<Layer>& parentLayer) {
     Mutex::Autolock _l(mLock);
-    mParentLayer = parentLayer;
+
+    // If we didn't ever have a parent, then we must instead be
+    // relying on permissions and we never need a parent.
+    if (mParentLayer != nullptr) {
+        mParentLayer = parentLayer;
+    }
 }
 
 sp<Layer> Client::getParentLayer(bool* outParentDied) const {
@@ -134,13 +148,14 @@
 status_t Client::createSurface(
         const String8& name,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        const sp<IBinder>& parentHandle, uint32_t windowType, uint32_t ownerUid,
+        const sp<IBinder>& parentHandle, int32_t windowType, int32_t ownerUid,
         sp<IBinder>* handle,
         sp<IGraphicBufferProducer>* gbp)
 {
     sp<Layer> parent = nullptr;
     if (parentHandle != nullptr) {
-        parent = getLayerUser(parentHandle);
+        auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
+        parent = layerHandle->owner.promote();
         if (parent == nullptr) {
             return NAME_NOT_FOUND;
         }
@@ -155,48 +170,8 @@
         }
     }
 
-    /*
-     * createSurface must be called from the GL thread so that it can
-     * have access to the GL context.
-     */
-    class MessageCreateLayer : public MessageBase {
-        SurfaceFlinger* flinger;
-        Client* client;
-        sp<IBinder>* handle;
-        sp<IGraphicBufferProducer>* gbp;
-        status_t result;
-        const String8& name;
-        uint32_t w, h;
-        PixelFormat format;
-        uint32_t flags;
-        sp<Layer>* parent;
-        uint32_t windowType;
-        uint32_t ownerUid;
-    public:
-        MessageCreateLayer(SurfaceFlinger* flinger,
-                const String8& name, Client* client,
-                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-                sp<IBinder>* handle, uint32_t windowType, uint32_t ownerUid,
-                sp<IGraphicBufferProducer>* gbp,
-                sp<Layer>* parent)
-            : flinger(flinger), client(client),
-              handle(handle), gbp(gbp), result(NO_ERROR),
-              name(name), w(w), h(h), format(format), flags(flags),
-              parent(parent), windowType(windowType), ownerUid(ownerUid) {
-        }
-        status_t getResult() const { return result; }
-        virtual bool handler() {
-            result = flinger->createLayer(name, client, w, h, format, flags,
-                    windowType, ownerUid, handle, gbp, parent);
-            return true;
-        }
-    };
-
-    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
-            name, this, w, h, format, flags, handle,
-            windowType, ownerUid, gbp, &parent);
-    mFlinger->postMessageSync(msg);
-    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
+    return mFlinger->createLayer(name, this, w, h, format, flags, windowType,
+                                 ownerUid, handle, gbp, &parent);
 }
 
 status_t Client::destroySurface(const sp<IBinder>& handle) {
@@ -205,7 +180,7 @@
 
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
     sp<Layer> layer = getLayerUser(handle);
-    if (layer == NULL) {
+    if (layer == nullptr) {
         return NAME_NOT_FOUND;
     }
     layer->clearFrameStats();
@@ -214,7 +189,7 @@
 
 status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
     sp<Layer> layer = getLayerUser(handle);
-    if (layer == NULL) {
+    if (layer == nullptr) {
         return NAME_NOT_FOUND;
     }
     layer->getFrameStats(outStats);
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 2aab28f..49437ed 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -51,14 +51,14 @@
 
     sp<Layer> getLayerUser(const sp<IBinder>& handle) const;
 
-    void setParentLayer(const sp<Layer>& parentLayer);
+    void updateParent(const sp<Layer>& parentLayer);
 
 private:
     // ISurfaceComposerClient interface
     virtual status_t createSurface(
             const String8& name,
             uint32_t w, uint32_t h,PixelFormat format, uint32_t flags,
-            const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
+            const sp<IBinder>& parent, int32_t windowType, int32_t ownerUid,
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
new file mode 100644
index 0000000..512564c
--- /dev/null
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "ColorLayer"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include "ColorLayer.h"
+#include "DisplayDevice.h"
+#include "RenderEngine/RenderEngine.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                       uint32_t w, uint32_t h, uint32_t flags)
+      : Layer(flinger, client, name, w, h, flags) {
+    // drawing state & current state are identical
+    mDrawingState = mCurrentState;
+}
+
+void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
+                        bool useIdentityTransform) const {
+    half4 color = getColor();
+    if (color.a > 0) {
+        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+        computeGeometry(renderArea, mesh, useIdentityTransform);
+        auto& engine(mFlinger->getRenderEngine());
+        engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
+                                  true /* disableTexture */, color);
+        engine.drawMesh(mesh);
+        engine.disableBlending();
+    }
+}
+
+bool ColorLayer::isVisible() const {
+    const Layer::State& s(getDrawingState());
+    return !isHiddenByPolicy() && s.color.a;
+}
+
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+    const Transform& tr = displayDevice->getTransform();
+    const auto& viewport = displayDevice->getViewport();
+    Region visible = tr.transform(visibleRegion.intersect(viewport));
+    auto hwcId = displayDevice->getHwcDisplayId();
+    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    auto& hwcLayer = hwcInfo.layer;
+    auto error = hwcLayer->setVisibleRegion(visible);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        visible.dump(LOG_TAG);
+    }
+
+    setCompositionType(hwcId, HWC2::Composition::SolidColor);
+
+    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    half4 color = getColor();
+    error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
+                                static_cast<uint8_t>(std::round(255.0f * color.g)),
+                                static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
+
+    // Clear out the transform, because it doesn't make sense absent a source buffer
+    error = hwcLayer->setTransform(HWC2::Transform::None);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
new file mode 100644
index 0000000..0cde398
--- /dev/null
+++ b/services/surfaceflinger/ColorLayer.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <cstdint>
+
+#include "Layer.h"
+
+namespace android {
+
+class ColorLayer : public Layer {
+public:
+    ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+               uint32_t h, uint32_t flags);
+    virtual ~ColorLayer() = default;
+
+    virtual const char* getTypeId() const { return "ColorLayer"; }
+    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+                        bool useIdentityTransform) const;
+    bool isVisible() const override;
+
+    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
new file mode 100644
index 0000000..f259d93
--- /dev/null
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "ContainerLayer"
+
+#include "ContainerLayer.h"
+
+namespace android {
+
+ContainerLayer::ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+                               const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+      : Layer(flinger, client, name, w, h, flags) {
+    mDrawingState = mCurrentState;
+}
+
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
+
+bool ContainerLayer::isVisible() const {
+    return !isHiddenByPolicy();
+}
+
+void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
new file mode 100644
index 0000000..b352b96
--- /dev/null
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <cstdint>
+
+#include "Layer.h"
+
+namespace android {
+
+class ContainerLayer : public Layer {
+public:
+    ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                   uint32_t w, uint32_t h, uint32_t flags);
+    virtual ~ContainerLayer() = default;
+
+    const char* getTypeId() const override { return "ContainerLayer"; }
+    void onDraw(const RenderArea& renderArea, const Region& clip,
+                bool useIdentityTransform) const override;
+    bool isVisible() const override;
+
+    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+
+    bool isCreatedFromMainThread() const override { return true; }
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bef12ea..37dc27d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -33,8 +33,8 @@
 #include <ui/FenceTime.h>
 
 #include "DispSync.h"
-#include "SurfaceFlinger.h"
 #include "EventLog/EventLog.h"
+#include "SurfaceFlinger.h"
 
 using std::max;
 using std::min;
@@ -53,15 +53,14 @@
 // needed to re-synchronize the software vsync model with the hardware.  The
 // error metric used is the mean of the squared difference between each
 // present time and the nearest software-predicted vsync.
-static const nsecs_t kErrorThreshold = 160000000000;    // 400 usec squared
+static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
 
 #undef LOG_TAG
 #define LOG_TAG "DispSyncThread"
-class DispSyncThread: public Thread {
+class DispSyncThread : public Thread {
 public:
-
-    explicit DispSyncThread(const char* name):
-            mName(name),
+    explicit DispSyncThread(const char* name)
+          : mName(name),
             mStop(false),
             mPeriod(0),
             mPhase(0),
@@ -78,8 +77,8 @@
         mPhase = phase;
         mReferenceTime = referenceTime;
         ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
-                " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mPhase), ns2us(mReferenceTime));
+              " mReferenceTime = %" PRId64,
+              mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
         mCond.signal();
     }
 
@@ -115,8 +114,7 @@
                 if (mPeriod == 0) {
                     err = mCond.wait(mMutex);
                     if (err != NO_ERROR) {
-                        ALOGE("error waiting for new events: %s (%d)",
-                                strerror(-err), err);
+                        ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
                         return false;
                     }
                     continue;
@@ -133,16 +131,14 @@
                         ALOGV("[%s] Waiting forever", mName);
                         err = mCond.wait(mMutex);
                     } else {
-                        ALOGV("[%s] Waiting until %" PRId64, mName,
-                                ns2us(targetTime));
+                        ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
                         err = mCond.waitRelative(mMutex, targetTime - now);
                     }
 
                     if (err == TIMED_OUT) {
                         isWakeup = true;
                     } else if (err != NO_ERROR) {
-                        ALOGE("error waiting for next event: %s (%d)",
-                                strerror(-err), err);
+                        ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
                         return false;
                     }
                 }
@@ -153,8 +149,7 @@
                 static const nsecs_t kMaxWakeupLatency = us2ns(1500);
 
                 if (isWakeup) {
-                    mWakeupLatency = ((mWakeupLatency * 63) +
-                            (now - targetTime)) / 64;
+                    mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
                     mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
                     if (kTraceDetailedInfo) {
                         ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
@@ -173,8 +168,7 @@
         return false;
     }
 
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<DispSync::Callback>& callback) {
+    status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
@@ -191,8 +185,7 @@
 
         // We want to allow the firstmost future event to fire without
         // allowing any past events to fire
-        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
-                mWakeupLatency;
+        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
 
         mEventListeners.push(listener);
 
@@ -201,7 +194,7 @@
         return NO_ERROR;
     }
 
-    status_t removeEventListener(const sp<DispSync::Callback>& callback) {
+    status_t removeEventListener(DispSync::Callback* callback) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
@@ -216,6 +209,34 @@
         return BAD_VALUE;
     }
 
+    status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
+        Mutex::Autolock lock(mMutex);
+
+        for (size_t i = 0; i < mEventListeners.size(); i++) {
+            if (mEventListeners[i].mCallback == callback) {
+                EventListener& listener = mEventListeners.editItemAt(i);
+                const nsecs_t oldPhase = listener.mPhase;
+                listener.mPhase = phase;
+
+                // Pretend that the last time this event was handled at the same frame but with the
+                // new offset to allow for a seamless offset change without double-firing or
+                // skipping.
+                nsecs_t diff = oldPhase - phase;
+                if (diff > mPeriod / 2) {
+                    diff -= mPeriod;
+                } else if (diff < -mPeriod / 2) {
+                    diff += mPeriod;
+                }
+                listener.mLastEventTime -= diff;
+                mCond.signal();
+                return NO_ERROR;
+            }
+        }
+
+        return BAD_VALUE;
+    }
+
     // This method is only here to handle the !SurfaceFlinger::hasSyncFramework
     // case.
     bool hasAnyEventListeners() {
@@ -225,16 +246,15 @@
     }
 
 private:
-
     struct EventListener {
         const char* mName;
         nsecs_t mPhase;
         nsecs_t mLastEventTime;
-        sp<DispSync::Callback> mCallback;
+        DispSync::Callback* mCallback;
     };
 
     struct CallbackInvocation {
-        sp<DispSync::Callback> mCallback;
+        DispSync::Callback* mCallback;
         nsecs_t mEventTime;
     };
 
@@ -243,8 +263,7 @@
         ALOGV("[%s] computeNextEventTimeLocked", mName);
         nsecs_t nextEventTime = INT64_MAX;
         for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    now);
+            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
 
             if (t < nextEventTime) {
                 nextEventTime = t;
@@ -257,22 +276,19 @@
 
     Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
         if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
-                ns2us(now));
+        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
 
         Vector<CallbackInvocation> callbackInvocations;
         nsecs_t onePeriodAgo = now - mPeriod;
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    onePeriodAgo);
+            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
 
             if (t < now) {
                 CallbackInvocation ci;
                 ci.mCallback = mEventListeners[i].mCallback;
                 ci.mEventTime = t;
-                ALOGV("[%s] [%s] Preparing to fire", mName,
-                        mEventListeners[i].mName);
+                ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
                 callbackInvocations.push(ci);
                 mEventListeners.editItemAt(i).mLastEventTime = t;
             }
@@ -281,18 +297,16 @@
         return callbackInvocations;
     }
 
-    nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
-            nsecs_t baseTime) {
+    nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
         if (kTraceDetailedInfo) ATRACE_CALL();
-        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
-                mName, listener.mName, ns2us(baseTime));
+        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
+              ns2us(baseTime));
 
         nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
         ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
         if (baseTime < lastEventTime) {
             baseTime = lastEventTime;
-            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
-                    ns2us(baseTime));
+            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
         }
 
         baseTime -= mReferenceTime;
@@ -374,11 +388,8 @@
     bool mParity;
 };
 
-DispSync::DispSync(const char* name) :
-        mName(name),
-        mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)) {
-}
+DispSync::DispSync(const char* name)
+      : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
 
 DispSync::~DispSync() {}
 
@@ -404,7 +415,8 @@
         // not needed because any time there is an event registered we will
         // turn on the HW vsync events.
         if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
-            addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
+            mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+            addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
         }
     }
 }
@@ -451,8 +463,8 @@
         mPhase = 0;
         mReferenceTime = timestamp;
         ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
-                "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
-                ns2us(mReferenceTime));
+              "mReferenceTime = %" PRId64,
+              mName, ns2us(mPeriod), ns2us(mReferenceTime));
         mThread->updateModel(mPeriod, mPhase, mReferenceTime);
     }
 
@@ -480,16 +492,13 @@
     // Check against kErrorThreshold / 2 to add some hysteresis before having to
     // resync again
     bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
-    ALOGV("[%s] addResyncSample returning %s", mName,
-            modelLocked ? "locked" : "unlocked");
+    ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
     return !modelLocked;
 }
 
-void DispSync::endResync() {
-}
+void DispSync::endResync() {}
 
-status_t DispSync::addEventListener(const char* name, nsecs_t phase,
-        const sp<Callback>& callback) {
+status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback) {
     Mutex::Autolock lock(mMutex);
     return mThread->addEventListener(name, phase, callback);
 }
@@ -501,11 +510,16 @@
     updateModelLocked();
 }
 
-status_t DispSync::removeEventListener(const sp<Callback>& callback) {
+status_t DispSync::removeEventListener(Callback* callback) {
     Mutex::Autolock lock(mMutex);
     return mThread->removeEventListener(callback);
 }
 
+status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
+    Mutex::Autolock lock(mMutex);
+    return mThread->changePhaseOffset(callback, phase);
+}
+
 void DispSync::setPeriod(nsecs_t period) {
     Mutex::Autolock lock(mMutex);
     mPeriod = period;
@@ -597,8 +611,7 @@
         // call getSignalTime() periodically so the cache is updated when the
         // fence signals.
         nsecs_t time = mPresentFences[i]->getCachedSignalTime();
-        if (time == Fence::SIGNAL_TIME_PENDING ||
-                time == Fence::SIGNAL_TIME_INVALID) {
+        if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
             continue;
         }
 
@@ -622,9 +635,8 @@
         mError = 0;
         // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
         mZeroErrSamplesCount++;
-        ALOGE_IF(
-                (mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
-                "No present times for model error.");
+        ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
+                 "No present times for model error.");
     }
 
     if (kTraceDetailedInfo) {
@@ -650,17 +662,14 @@
 
 void DispSync::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
-    result.appendFormat("present fences are %s\n",
-            mIgnorePresentFences ? "ignored" : "used");
-    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
-            mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
+    result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
+    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
+                        1000000000.0 / mPeriod, mRefreshSkipCount);
     result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
-    result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
-            mError, sqrt(mError));
+    result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
     result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
-            mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
-    result.appendFormat("mNumResyncSamples: %zd (max %d)\n",
-            mNumResyncSamples, MAX_RESYNC_SAMPLES);
+                        mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+    result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES);
 
     result.appendFormat("mResyncSamples:\n");
     nsecs_t previous = -1;
@@ -670,14 +679,13 @@
         if (i == 0) {
             result.appendFormat("  %" PRId64 "\n", sampleTime);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 ")\n",
-                    sampleTime, sampleTime - previous);
+            result.appendFormat("  %" PRId64 " (+%" PRId64 ")\n", sampleTime,
+                                sampleTime - previous);
         }
         previous = sampleTime;
     }
 
-    result.appendFormat("mPresentFences [%d]:\n",
-            NUM_PRESENT_SAMPLES);
+    result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     previous = Fence::SIGNAL_TIME_INVALID;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
@@ -685,17 +693,16 @@
         nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
         if (presentTime == Fence::SIGNAL_TIME_PENDING) {
             result.appendFormat("  [unsignaled fence]\n");
-        } else if(presentTime == Fence::SIGNAL_TIME_INVALID) {
+        } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  [invalid fence]\n");
         } else if (previous == Fence::SIGNAL_TIME_PENDING ||
-                previous == Fence::SIGNAL_TIME_INVALID) {
+                   previous == Fence::SIGNAL_TIME_INVALID) {
             result.appendFormat("  %" PRId64 "  (%.3f ms ago)\n", presentTime,
-                    (now - presentTime) / 1000000.0);
+                                (now - presentTime) / 1000000.0);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n",
-                    presentTime, presentTime - previous,
-                    (presentTime - previous) / (double) mPeriod,
-                    (now - presentTime) / 1000000.0);
+            result.appendFormat("  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n", presentTime,
+                                presentTime - previous, (presentTime - previous) / (double)mPeriod,
+                                (now - presentTime) / 1000000.0);
         }
         previous = presentTime;
     }
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 880a24d..077256a 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -20,8 +20,8 @@
 #include <stddef.h>
 
 #include <utils/Mutex.h>
-#include <utils/Timers.h>
 #include <utils/RefBase.h>
+#include <utils/Timers.h>
 
 #include <ui/FenceTime.h>
 
@@ -47,12 +47,10 @@
 // false to indicate that a resynchronization (via addResyncSample) is not
 // needed.
 class DispSync {
-
 public:
-
-    class Callback: public virtual RefBase {
+    class Callback {
     public:
-        virtual ~Callback() {};
+        virtual ~Callback(){};
         virtual void onDispSyncEvent(nsecs_t when) = 0;
     };
 
@@ -108,13 +106,17 @@
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
     // (i.e. within a few hundred microseconds).
-    status_t addEventListener(const char* name, nsecs_t phase,
-            const sp<Callback>& callback);
+    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
     // DispSync object.
-    status_t removeEventListener(const sp<Callback>& callback);
+    status_t removeEventListener(Callback* callback);
+
+    // changePhaseOffset changes the phase offset of an already-registered event callback. The
+    // method will make sure that there is no skipping or double-firing on the listener per frame,
+    // even when changing the offsets multiple times.
+    status_t changePhaseOffset(Callback* callback, nsecs_t phase);
 
     // computeNextRefresh computes when the next refresh is expected to begin.
     // The periodOffset value can be used to move forward or backward; an
@@ -126,7 +128,6 @@
     void dump(String8& result) const;
 
 private:
-
     void updateModelLocked();
     void updateErrorLocked();
     void resetErrorLocked();
@@ -174,8 +175,7 @@
 
     // These member variables store information about the present fences used
     // to validate the currently computed model.
-    std::shared_ptr<FenceTime>
-            mPresentFences[NUM_PRESENT_SAMPLES] {FenceTime::NO_FENCE};
+    std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
     size_t mPresentSampleOffset;
 
     int mRefreshSkipCount;
@@ -193,8 +193,10 @@
     // Ignore present (retire) fences if the device doesn't have support for the
     // sync framework
     bool mIgnorePresentFences;
+
+    std::unique_ptr<Callback> mZeroPhaseTracer;
 };
 
-}
+} // namespace android
 
 #endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b28c9ba..db095a5 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -18,6 +18,9 @@
 #undef LOG_TAG
 #define LOG_TAG "DisplayDevice"
 
+#include <array>
+#include <unordered_set>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -28,6 +31,7 @@
 #include <utils/RefBase.h>
 #include <utils/Log.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
 
@@ -37,9 +41,7 @@
 
 #include "DisplayHardware/DisplaySurface.h"
 #include "DisplayHardware/HWComposer.h"
-#ifdef USE_HWC2
 #include "DisplayHardware/HWC2.h"
-#endif
 #include "RenderEngine/RenderEngine.h"
 
 #include "clz.h"
@@ -50,28 +52,15 @@
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 
-// ----------------------------------------------------------------------------
-using namespace android;
-// ----------------------------------------------------------------------------
-
-#ifdef EGL_ANDROID_swap_rectangle
-static constexpr bool kEGLAndroidSwapRectangle = true;
-#else
-static constexpr bool kEGLAndroidSwapRectangle = false;
-#endif
+namespace android {
 
 // retrieve triple buffer setting from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
-
-static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
-
-#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
-// Dummy implementation in case it is missing.
-inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) {
-}
-#endif
+using android::ui::ColorMode;
+using android::ui::Dataspace;
+using android::ui::Hdr;
+using android::ui::RenderIntent;
 
 /*
  * Initialize the display to the specified values.
@@ -80,137 +69,246 @@
 
 uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
 
+namespace {
+
+// ordered list of known SDR color modes
+const std::array<ColorMode, 2> sSdrColorModes = {
+        ColorMode::DISPLAY_P3,
+        ColorMode::SRGB,
+};
+
+// ordered list of known HDR color modes
+const std::array<ColorMode, 2> sHdrColorModes = {
+        ColorMode::BT2100_PQ,
+        ColorMode::BT2100_HLG,
+};
+
+// ordered list of known SDR render intents
+const std::array<RenderIntent, 2> sSdrRenderIntents = {
+        RenderIntent::ENHANCE,
+        RenderIntent::COLORIMETRIC,
+};
+
+// ordered list of known HDR render intents
+const std::array<RenderIntent, 2> sHdrRenderIntents = {
+        RenderIntent::TONE_MAP_ENHANCE,
+        RenderIntent::TONE_MAP_COLORIMETRIC,
+};
+
+// map known color mode to dataspace
+Dataspace colorModeToDataspace(ColorMode mode) {
+    switch (mode) {
+        case ColorMode::SRGB:
+            return Dataspace::SRGB;
+        case ColorMode::DISPLAY_P3:
+            return Dataspace::DISPLAY_P3;
+        case ColorMode::BT2100_HLG:
+            return Dataspace::BT2020_HLG;
+        case ColorMode::BT2100_PQ:
+            return Dataspace::BT2020_PQ;
+        default:
+            return Dataspace::UNKNOWN;
+    }
+}
+
+// Return a list of candidate color modes.
+std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
+    std::vector<ColorMode> candidates;
+
+    // add mode itself
+    candidates.push_back(mode);
+
+    // check if mode is HDR
+    bool isHdr = false;
+    for (auto hdrMode : sHdrColorModes) {
+        if (hdrMode == mode) {
+            isHdr = true;
+            break;
+        }
+    }
+
+    // add other HDR candidates when mode is HDR
+    if (isHdr) {
+        for (auto hdrMode : sHdrColorModes) {
+            if (hdrMode != mode) {
+                candidates.push_back(hdrMode);
+            }
+        }
+    }
+
+    // add other SDR candidates
+    for (auto sdrMode : sSdrColorModes) {
+        if (sdrMode != mode) {
+            candidates.push_back(sdrMode);
+        }
+    }
+
+    return candidates;
+}
+
+// Return a list of candidate render intents.
+std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
+    std::vector<RenderIntent> candidates;
+
+    // add intent itself
+    candidates.push_back(intent);
+
+    // check if intent is HDR
+    bool isHdr = false;
+    for (auto hdrIntent : sHdrRenderIntents) {
+        if (hdrIntent == intent) {
+            isHdr = true;
+            break;
+        }
+    }
+
+    if (isHdr) {
+        // add other HDR candidates when intent is HDR
+        for (auto hdrIntent : sHdrRenderIntents) {
+            if (hdrIntent != intent) {
+                candidates.push_back(hdrIntent);
+            }
+        }
+    } else {
+        // add other SDR candidates when intent is SDR
+        for (auto sdrIntent : sSdrRenderIntents) {
+            if (sdrIntent != intent) {
+                candidates.push_back(sdrIntent);
+            }
+        }
+    }
+
+    return candidates;
+}
+
+// Return the best color mode supported by HWC.
+ColorMode getHwcColorMode(
+        const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+        ColorMode mode) {
+    std::vector<ColorMode> candidates = getColorModeCandidates(mode);
+    for (auto candidate : candidates) {
+        auto iter = hwcColorModes.find(candidate);
+        if (iter != hwcColorModes.end()) {
+            return candidate;
+        }
+    }
+
+    return ColorMode::NATIVE;
+}
+
+// Return the best render intent supported by HWC.
+RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
+    std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
+    for (auto candidate : candidates) {
+        for (auto hwcIntent : hwcIntents) {
+            if (candidate == hwcIntent) {
+                return candidate;
+            }
+        }
+    }
+
+    return RenderIntent::COLORIMETRIC;
+}
+
+} // anonymous namespace
+
 // clang-format off
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
         DisplayType type,
         int32_t hwcId,
-#ifndef USE_HWC2
-        int format,
-#endif
         bool isSecure,
         const wp<IBinder>& displayToken,
+        const sp<ANativeWindow>& nativeWindow,
         const sp<DisplaySurface>& displaySurface,
-        const sp<IGraphicBufferProducer>& producer,
-        EGLConfig config,
-        bool supportWideColor)
+        std::unique_ptr<RE::Surface> renderSurface,
+        int displayWidth,
+        int displayHeight,
+        bool hasWideColorGamut,
+        const HdrCapabilities& hdrCapabilities,
+        const int32_t supportedPerFrameMetadata,
+        const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+        int initialPowerMode)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
       mType(type),
       mHwcDisplayId(hwcId),
       mDisplayToken(displayToken),
+      mNativeWindow(nativeWindow),
       mDisplaySurface(displaySurface),
-      mDisplay(EGL_NO_DISPLAY),
-      mSurface(EGL_NO_SURFACE),
-      mDisplayWidth(),
-      mDisplayHeight(),
-#ifndef USE_HWC2
-      mFormat(),
-#endif
-      mFlags(),
-      mPageFlipCount(),
+      mSurface{std::move(renderSurface)},
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mPageFlipCount(0),
       mIsSecure(isSecure),
       mLayerStack(NO_LAYER_STACK),
       mOrientation(),
-      mPowerMode(HWC_POWER_MODE_OFF),
-      mActiveConfig(0)
+      mViewport(Rect::INVALID_RECT),
+      mFrame(Rect::INVALID_RECT),
+      mPowerMode(initialPowerMode),
+      mActiveConfig(0),
+      mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
+      mHasWideColorGamut(hasWideColorGamut),
+      mHasHdr10(false),
+      mHasHLG(false),
+      mHasDolbyVision(false),
+      mSupportedPerFrameMetadata(supportedPerFrameMetadata)
 {
     // clang-format on
-    Surface* surface;
-    mNativeWindow = surface = new Surface(producer, false);
-    ANativeWindow* const window = mNativeWindow.get();
+    populateColorModes(hwcColorModes);
 
-#ifdef USE_HWC2
-    mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-    mDisplayHasWideColor = supportWideColor;
-#else
-    (void) supportWideColor;
-#endif
-    /*
-     * Create our display's surface
-     */
-
-    EGLSurface eglSurface;
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (config == EGL_NO_CONFIG) {
-#ifdef USE_HWC2
-        config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888,
-                                               /*logConfig*/ false);
-#else
-        config = RenderEngine::chooseEglConfig(display, format,
-                                               /*logConfig*/ false);
-#endif
+    std::vector<Hdr> types = hdrCapabilities.getSupportedHdrTypes();
+    for (Hdr hdrType : types) {
+        switch (hdrType) {
+            case Hdr::HDR10:
+                mHasHdr10 = true;
+                break;
+            case Hdr::HLG:
+                mHasHLG = true;
+                break;
+            case Hdr::DOLBY_VISION:
+                mHasDolbyVision = true;
+                break;
+            default:
+                ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
+        }
     }
-    eglSurface = eglCreateWindowSurface(display, config, window, NULL);
-    eglQuerySurface(display, eglSurface, EGL_WIDTH,  &mDisplayWidth);
-    eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight);
 
-    // Make sure that composition can never be stalled by a virtual display
-    // consumer that isn't processing buffers fast enough. We have to do this
-    // in two places:
-    // * Here, in case the display is composed entirely by HWC.
-    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
-    //   window's swap interval in eglMakeCurrent, so they'll override the
-    //   interval we set here.
-    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
-        window->setSwapInterval(window, 0);
+    float minLuminance = hdrCapabilities.getDesiredMinLuminance();
+    float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
+    float maxAverageLuminance = hdrCapabilities.getDesiredMaxAverageLuminance();
 
-    mConfig = config;
-    mDisplay = display;
-    mSurface = eglSurface;
-#ifndef USE_HWC2
-    mFormat = format;
-#endif
-    mPageFlipCount = 0;
-    mViewport.makeInvalid();
-    mFrame.makeInvalid();
+    minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
+    maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
+    maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
+    if (this->hasWideColorGamut()) {
+        // insert HDR10/HLG as we will force client composition for HDR10/HLG
+        // layers
+        if (!hasHDR10Support()) {
+          types.push_back(Hdr::HDR10);
+        }
 
-    // virtual displays are always considered enabled
-    mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
-                  HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
-
-    // Name the display.  The name will be replaced shortly if the display
-    // was created with createDisplay().
-    switch (mType) {
-        case DISPLAY_PRIMARY:
-            mDisplayName = "Built-in Screen";
-            break;
-        case DISPLAY_EXTERNAL:
-            mDisplayName = "HDMI Screen";
-            break;
-        default:
-            mDisplayName = "Virtual Screen";    // e.g. Overlay #n
-            break;
+        if (!hasHLGSupport()) {
+          types.push_back(Hdr::HLG);
+        }
     }
+    mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
 
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
-
-    if (useTripleFramebuffer) {
-        surface->allocateBuffers();
-    }
 }
 
-DisplayDevice::~DisplayDevice() {
-    if (mSurface != EGL_NO_SURFACE) {
-        eglDestroySurface(mDisplay, mSurface);
-        mSurface = EGL_NO_SURFACE;
-    }
-}
+DisplayDevice::~DisplayDevice() = default;
 
 void DisplayDevice::disconnect(HWComposer& hwc) {
     if (mHwcDisplayId >= 0) {
         hwc.disconnectDisplay(mHwcDisplayId);
-#ifndef USE_HWC2
-        if (mHwcDisplayId >= DISPLAY_VIRTUAL)
-            hwc.freeDisplayId(mHwcDisplayId);
-#endif
         mHwcDisplayId = -1;
     }
 }
 
 bool DisplayDevice::isValid() const {
-    return mFlinger != NULL;
+    return mFlinger != nullptr;
 }
 
 int DisplayDevice::getWidth() const {
@@ -221,16 +319,6 @@
     return mDisplayHeight;
 }
 
-#ifndef USE_HWC2
-PixelFormat DisplayDevice::getFormat() const {
-    return mFormat;
-}
-#endif
-
-EGLSurface DisplayDevice::getEGLSurface() const {
-    return mSurface;
-}
-
 void DisplayDevice::setDisplayName(const String8& displayName) {
     if (!displayName.isEmpty()) {
         // never override the name with an empty name
@@ -242,25 +330,9 @@
     return mPageFlipCount;
 }
 
-#ifndef USE_HWC2
-status_t DisplayDevice::compositionComplete() const {
-    return mDisplaySurface->compositionComplete();
-}
-#endif
-
-void DisplayDevice::flip(const Region& dirty) const
+void DisplayDevice::flip() const
 {
     mFlinger->getRenderEngine().checkErrors();
-
-    if (kEGLAndroidSwapRectangle) {
-        if (mFlags & SWAP_RECTANGLE) {
-            const Region newDirty(dirty.intersect(bounds()));
-            const Rect b(newDirty.getBounds());
-            eglSetSwapRectangleANDROID(mDisplay, mSurface,
-                    b.left, b.top, b.width(), b.height());
-        }
-    }
-
     mPageFlipCount++;
 }
 
@@ -268,7 +340,6 @@
     return mDisplaySurface->beginFrame(mustRecompose);
 }
 
-#ifdef USE_HWC2
 status_t DisplayDevice::prepareFrame(HWComposer& hwc) {
     status_t error = hwc.prepare(*this);
     if (error != NO_ERROR) {
@@ -292,53 +363,10 @@
     }
     return mDisplaySurface->prepareFrame(compositionType);
 }
-#else
-status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
-    DisplaySurface::CompositionType compositionType;
-    bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
-    bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId);
-    if (haveGles && haveHwc) {
-        compositionType = DisplaySurface::COMPOSITION_MIXED;
-    } else if (haveGles) {
-        compositionType = DisplaySurface::COMPOSITION_GLES;
-    } else if (haveHwc) {
-        compositionType = DisplaySurface::COMPOSITION_HWC;
-    } else {
-        // Nothing to do -- when turning the screen off we get a frame like
-        // this. Call it a HWC frame since we won't be doing any GLES work but
-        // will do a prepare/set cycle.
-        compositionType = DisplaySurface::COMPOSITION_HWC;
-    }
-    return mDisplaySurface->prepareFrame(compositionType);
-}
-#endif
 
 void DisplayDevice::swapBuffers(HWComposer& hwc) const {
-#ifdef USE_HWC2
-    if (hwc.hasClientComposition(mHwcDisplayId)) {
-#else
-    // We need to call eglSwapBuffers() if:
-    //  (1) we don't have a hardware composer, or
-    //  (2) we did GLES composition this frame, and either
-    //    (a) we have framebuffer target support (not present on legacy
-    //        devices, where HWComposer::commit() handles things); or
-    //    (b) this is a virtual display
-    if (hwc.initCheck() != NO_ERROR ||
-            (hwc.hasGlesComposition(mHwcDisplayId) &&
-             (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
-#endif
-        EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
-        if (!success) {
-            EGLint error = eglGetError();
-            if (error == EGL_CONTEXT_LOST ||
-                    mType == DisplayDevice::DISPLAY_PRIMARY) {
-                LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
-                        mDisplay, mSurface, error);
-            } else {
-                ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",
-                        mDisplay, mSurface, error);
-            }
-        }
+    if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) {
+        mSurface->swapBuffers();
     }
 
     status_t result = mDisplaySurface->advanceFrame();
@@ -348,35 +376,14 @@
     }
 }
 
-#ifdef USE_HWC2
 void DisplayDevice::onSwapBuffersCompleted() const {
     mDisplaySurface->onFrameCommitted();
 }
-#else
-void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const {
-    if (hwc.initCheck() == NO_ERROR) {
-        mDisplaySurface->onFrameCommitted();
-    }
-}
-#endif
 
-uint32_t DisplayDevice::getFlags() const
-{
-    return mFlags;
-}
-
-EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const {
-    EGLBoolean result = EGL_TRUE;
-    EGLSurface sur = eglGetCurrentSurface(EGL_DRAW);
-    if (sur != mSurface) {
-        result = eglMakeCurrent(dpy, mSurface, mSurface, ctx);
-        if (result == EGL_TRUE) {
-            if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
-                eglSwapInterval(dpy, 0);
-        }
-    }
+bool DisplayDevice::makeCurrent() const {
+    bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface);
     setViewportAndProjection();
-    return result;
+    return success;
 }
 
 void DisplayDevice::setViewportAndProjection() const {
@@ -401,6 +408,14 @@
     return mVisibleLayersSortedByZ;
 }
 
+void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
+    mLayersNeedingFences = layers;
+}
+
+const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
+    return mLayersNeedingFences;
+}
+
 Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
     Region dirty;
     if (repaintEverything) {
@@ -436,20 +451,41 @@
 }
 
 // ----------------------------------------------------------------------------
-#ifdef USE_HWC2
-void DisplayDevice::setActiveColorMode(android_color_mode_t mode) {
+void DisplayDevice::setActiveColorMode(ColorMode mode) {
     mActiveColorMode = mode;
 }
 
-android_color_mode_t DisplayDevice::getActiveColorMode() const {
+ColorMode DisplayDevice::getActiveColorMode() const {
     return mActiveColorMode;
 }
 
-void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
-    ANativeWindow* const window = mNativeWindow.get();
-    native_window_set_buffers_data_space(window, dataspace);
+RenderIntent DisplayDevice::getActiveRenderIntent() const {
+    return mActiveRenderIntent;
 }
-#endif
+
+void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
+    mActiveRenderIntent = renderIntent;
+}
+
+void DisplayDevice::setColorTransform(const mat4& transform) {
+    const bool isIdentity = (transform == mat4());
+    mColorTransform =
+            isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+android_color_transform_t DisplayDevice::getColorTransform() const {
+    return mColorTransform;
+}
+
+void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
+    mCompositionDataSpace = dataspace;
+    ANativeWindow* const window = mNativeWindow.get();
+    native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
+}
+
+ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
+    return mCompositionDataSpace;
+}
 
 // ----------------------------------------------------------------------------
 
@@ -506,17 +542,14 @@
 void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
     dirtyRegion.set(getBounds());
 
-    if (mSurface != EGL_NO_SURFACE) {
-        eglDestroySurface(mDisplay, mSurface);
-        mSurface = EGL_NO_SURFACE;
-    }
+    mSurface->setNativeWindow(nullptr);
 
     mDisplaySurface->resizeBuffers(newWidth, newHeight);
 
     ANativeWindow* const window = mNativeWindow.get();
-    mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL);
-    eglQuerySurface(mDisplay, mSurface, EGL_WIDTH,  &mDisplayWidth);
-    eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight);
+    mSurface->setNativeWindow(window);
+    mDisplayWidth = mSurface->queryWidth();
+    mDisplayHeight = mSurface->queryHeight();
 
     LOG_FATAL_IF(mDisplayWidth != newWidth,
                 "Unable to set new width to %d", newWidth);
@@ -574,6 +607,15 @@
     TL.set(-src_x, -src_y);
     TP.set(dst_x, dst_y);
 
+    // need to take care of primary display rotation for mGlobalTransform
+    // for case if the panel is not installed aligned with device orientation
+    if (mType == DisplayType::DISPLAY_PRIMARY) {
+        int primaryDisplayOrientation = mFlinger->getPrimaryDisplayOrientation();
+        DisplayDevice::orientationToTransfrom(
+                (orientation + primaryDisplayOrientation) % (DisplayState::eOrientation270 + 1),
+                w, h, &R);
+    }
+
     // The viewport and frame are both in the logical orientation.
     // Apply the logical translation, scale to physical size, apply the
     // physical translation and finally rotate to the physical orientation.
@@ -617,17 +659,14 @@
 
 void DisplayDevice::dump(String8& result) const {
     const Transform& tr(mGlobalTransform);
-    EGLint redSize, greenSize, blueSize, alphaSize;
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize);
+    ANativeWindow* const window = mNativeWindow.get();
     result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
     result.appendFormat("   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
                         "(%d:%d:%d:%d), orient=%2d (type=%08x), "
                         "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
-                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight,
-                        mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
+                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+                        mSurface->queryRedSize(), mSurface->queryGreenSize(),
+                        mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
                         tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
                         mVisibleLayersSortedByZ.size());
     result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
@@ -636,12 +675,122 @@
                         mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
                         mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
                         tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
+    auto const surface = static_cast<Surface*>(window);
+    ui::Dataspace dataspace = surface->getBuffersDataSpace();
+    result.appendFormat("   wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
+                        mHasWideColorGamut, mHasHdr10,
+                        decodeColorMode(mActiveColorMode).c_str(),
+                        dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
     result.append(surfaceDump);
 }
 
+// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
+// supported by HWC.
+void DisplayDevice::addColorMode(
+        const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+        const ColorMode mode, const RenderIntent intent) {
+    // find the best color mode
+    const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
+
+    // find the best render intent
+    auto iter = hwcColorModes.find(hwcColorMode);
+    const auto& hwcIntents =
+            iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
+    const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
+
+    const Dataspace dataspace = colorModeToDataspace(mode);
+    const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
+
+    ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mHwcDisplayId,
+          dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+          decodeRenderIntent(intent).c_str(),
+          dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
+          decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
+
+    mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+}
+
+void DisplayDevice::populateColorModes(
+        const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) {
+    if (!hasWideColorGamut()) {
+        return;
+    }
+
+    // collect all known SDR render intents
+    std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
+                                                      sSdrRenderIntents.end());
+    auto iter = hwcColorModes.find(ColorMode::SRGB);
+    if (iter != hwcColorModes.end()) {
+        for (auto intent : iter->second) {
+            sdrRenderIntents.insert(intent);
+        }
+    }
+
+    // add all known SDR combinations
+    for (auto intent : sdrRenderIntents) {
+        for (auto mode : sSdrColorModes) {
+            addColorMode(hwcColorModes, mode, intent);
+        }
+    }
+
+    // collect all known HDR render intents
+    std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
+                                                      sHdrRenderIntents.end());
+    iter = hwcColorModes.find(ColorMode::BT2100_PQ);
+    if (iter != hwcColorModes.end()) {
+        for (auto intent : iter->second) {
+            hdrRenderIntents.insert(intent);
+        }
+    }
+
+    // add all known HDR combinations
+    for (auto intent : sHdrRenderIntents) {
+        for (auto mode : sHdrColorModes) {
+            addColorMode(hwcColorModes, mode, intent);
+        }
+    }
+}
+
+bool DisplayDevice::hasRenderIntent(RenderIntent intent) const {
+    // assume a render intent is supported when SRGB supports it; we should
+    // get rid of that assumption.
+    auto iter = mColorModes.find(getColorModeKey(Dataspace::SRGB, intent));
+    return iter != mColorModes.end() && iter->second.renderIntent == intent;
+}
+
+bool DisplayDevice::hasLegacyHdrSupport(Dataspace dataspace) const {
+    if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
+        (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
+        auto iter =
+                mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
+        return iter == mColorModes.end() || iter->second.dataspace != dataspace;
+    }
+
+    return false;
+}
+
+void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent,
+                                     Dataspace* outDataspace, ColorMode* outMode,
+                                     RenderIntent* outIntent) const {
+    auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
+    if (iter != mColorModes.end()) {
+        *outDataspace = iter->second.dataspace;
+        *outMode = iter->second.colorMode;
+        *outIntent = iter->second.renderIntent;
+    } else {
+        ALOGE("map unknown (%s)/(%s) to default color mode",
+              dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+              decodeRenderIntent(intent).c_str());
+
+        *outDataspace = Dataspace::UNKNOWN;
+        *outMode = ColorMode::NATIVE;
+        *outIntent = RenderIntent::COLORIMETRIC;
+    }
+}
+
 std::atomic<int32_t> DisplayDeviceState::nextDisplayId(1);
 
 DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure)
@@ -655,3 +804,5 @@
     viewport.makeInvalid();
     frame.makeInvalid();
 }
+
+}  // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8636e2a..6c3bd91 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -20,28 +20,25 @@
 #include "Transform.h"
 
 #include <stdlib.h>
+#include <unordered_map>
 
-#ifndef USE_HWC2
-#include <ui/PixelFormat.h>
-#endif
-#include <ui/Region.h>
+#include <math/mat4.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#ifdef USE_HWC2
 #include <binder/IBinder.h>
+#include <gui/ISurfaceComposer.h>
+#include <hardware/hwcomposer_defs.h>
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+#include <ui/Region.h>
 #include <utils/RefBase.h>
-#endif
 #include <utils/Mutex.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
-#include <hardware/hwcomposer_defs.h>
+#include "RenderArea.h"
+#include "RenderEngine/Surface.h"
 
-#ifdef USE_HWC2
 #include <memory>
-#endif
 
 struct ANativeWindow;
 
@@ -58,11 +55,12 @@
 class DisplayDevice : public LightRefBase<DisplayDevice>
 {
 public:
+    constexpr static float sDefaultMinLumiance = 0.0;
+    constexpr static float sDefaultMaxLumiance = 500.0;
+
     // region in layer-stack space
     mutable Region dirtyRegion;
     // region in screen space
-    mutable Region swapRegion;
-    // region in screen space
     Region undefinedRegion;
     bool lastCompositionHadVisibleLayers;
 
@@ -75,11 +73,6 @@
     };
 
     enum {
-        PARTIAL_UPDATES = 0x00020000, // video driver feature
-        SWAP_RECTANGLE  = 0x00080000,
-    };
-
-    enum {
         NO_LAYER_STACK = 0xFFFFFFFF,
     };
 
@@ -88,15 +81,18 @@
             const sp<SurfaceFlinger>& flinger,
             DisplayType type,
             int32_t hwcId,
-#ifndef USE_HWC2
-            int format,
-#endif
             bool isSecure,
             const wp<IBinder>& displayToken,
+            const sp<ANativeWindow>& nativeWindow,
             const sp<DisplaySurface>& displaySurface,
-            const sp<IGraphicBufferProducer>& producer,
-            EGLConfig config,
-            bool supportWideColor);
+            std::unique_ptr<RE::Surface> renderSurface,
+            int displayWidth,
+            int displayHeight,
+            bool hasWideColorGamut,
+            const HdrCapabilities& hdrCapabilities,
+            const int32_t supportedPerFrameMetadata,
+            const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes,
+            int initialPowerMode);
     // clang-format on
 
     ~DisplayDevice();
@@ -111,19 +107,15 @@
 
     // Flip the front and back buffers if the back buffer is "dirty".  Might
     // be instantaneous, might involve copying the frame buffer around.
-    void flip(const Region& dirty) const;
+    void flip() const;
 
     int         getWidth() const;
     int         getHeight() const;
-#ifndef USE_HWC2
-    PixelFormat getFormat() const;
-#endif
-    uint32_t    getFlags() const;
-
-    EGLSurface  getEGLSurface() const;
 
     void                    setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
     const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
+    void                    setLayersNeedingFences(const Vector< sp<Layer> >& layers);
+    const Vector< sp<Layer> >& getLayersNeedingFences() const;
     Region                  getDirtyRegion(bool repaintEverything) const;
 
     void                    setLayerStack(uint32_t stack);
@@ -145,27 +137,42 @@
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
+    int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
+
     // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
     // machine happy without actually queueing a buffer if nothing has changed
     status_t beginFrame(bool mustRecompose) const;
-#ifdef USE_HWC2
     status_t prepareFrame(HWComposer& hwc);
-    bool getWideColorSupport() const { return mDisplayHasWideColor; }
-#else
-    status_t prepareFrame(const HWComposer& hwc) const;
-#endif
+
+    bool hasWideColorGamut() const { return mHasWideColorGamut; }
+    // Whether h/w composer has native support for specific HDR type.
+    bool hasHDR10Support() const { return mHasHdr10; }
+    bool hasHLGSupport() const { return mHasHLG; }
+    bool hasDolbyVisionSupport() const { return mHasDolbyVision; }
+
+    // Return true if the HDR dataspace is supported but
+    // there is no corresponding color mode.
+    bool hasLegacyHdrSupport(ui::Dataspace dataspace) const;
+
+    // The returned HdrCapabilities is the combination of HDR capabilities from
+    // hardware composer and RenderEngine. When the DisplayDevice supports wide
+    // color gamut, RenderEngine is able to simulate HDR support in Display P3
+    // color space for both PQ and HLG HDR contents. The minimum and maximum
+    // luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
+    // respectively if hardware composer doesn't return meaningful values.
+    const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; }
+
+    // Return true if intent is supported by the display.
+    bool hasRenderIntent(ui::RenderIntent intent) const;
+
+    void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+                          ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+                          ui::RenderIntent* outIntent) const;
 
     void swapBuffers(HWComposer& hwc) const;
-#ifndef USE_HWC2
-    status_t compositionComplete() const;
-#endif
 
     // called after h/w composer has completed its set() call
-#ifdef USE_HWC2
     void onSwapBuffersCompleted() const;
-#else
-    void onSwapBuffersCompleted(HWComposer& hwc) const;
-#endif
 
     Rect getBounds() const {
         return Rect(mDisplayWidth, mDisplayHeight);
@@ -175,7 +182,7 @@
     void setDisplayName(const String8& displayName);
     const String8& getDisplayName() const { return mDisplayName; }
 
-    EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
+    bool makeCurrent() const;
     void setViewportAndProjection() const;
 
     const sp<Fence>& getClientTargetAcquireFence() const;
@@ -187,11 +194,14 @@
     void setPowerMode(int mode);
     bool isDisplayOn() const;
 
-#ifdef USE_HWC2
-    android_color_mode_t getActiveColorMode() const;
-    void setActiveColorMode(android_color_mode_t mode);
-    void setCompositionDataSpace(android_dataspace dataspace);
-#endif
+    ui::ColorMode getActiveColorMode() const;
+    void setActiveColorMode(ui::ColorMode mode);
+    ui::RenderIntent getActiveRenderIntent() const;
+    void setActiveRenderIntent(ui::RenderIntent renderIntent);
+    android_color_transform_t getColorTransform() const;
+    void setColorTransform(const mat4& transform);
+    void setCompositionDataSpace(ui::Dataspace dataspace);
+    ui::Dataspace getCompositionDataSpace() const;
 
     /* ------------------------------------------------------------------------
      * Display active config management.
@@ -221,15 +231,9 @@
     sp<ANativeWindow> mNativeWindow;
     sp<DisplaySurface> mDisplaySurface;
 
-    EGLConfig       mConfig;
-    EGLDisplay      mDisplay;
-    EGLSurface      mSurface;
+    std::unique_ptr<RE::Surface> mSurface;
     int             mDisplayWidth;
     int             mDisplayHeight;
-#ifndef USE_HWC2
-    PixelFormat     mFormat;
-#endif
-    uint32_t        mFlags;
     mutable uint32_t mPageFlipCount;
     String8         mDisplayName;
     bool            mIsSecure;
@@ -241,6 +245,8 @@
 
     // list of visible layers on that display
     Vector< sp<Layer> > mVisibleLayersSortedByZ;
+    // list of layers needing fences
+    Vector< sp<Layer> > mLayersNeedingFences;
 
     /*
      * Transaction state
@@ -267,15 +273,43 @@
     int mPowerMode;
     // Current active config
     int mActiveConfig;
-#ifdef USE_HWC2
     // current active color mode
-    android_color_mode_t mActiveColorMode;
+    ui::ColorMode mActiveColorMode = ui::ColorMode::NATIVE;
+    // Current active render intent.
+    ui::RenderIntent mActiveRenderIntent = ui::RenderIntent::COLORIMETRIC;
+    ui::Dataspace mCompositionDataSpace = ui::Dataspace::UNKNOWN;
+    // Current color transform
+    android_color_transform_t mColorTransform;
 
     // Need to know if display is wide-color capable or not.
     // Initialized by SurfaceFlinger when the DisplayDevice is created.
     // Fed to RenderEngine during composition.
-    bool mDisplayHasWideColor;
-#endif
+    bool mHasWideColorGamut;
+    bool mHasHdr10;
+    bool mHasHLG;
+    bool mHasDolbyVision;
+    HdrCapabilities mHdrCapabilities;
+    const int32_t mSupportedPerFrameMetadata;
+
+    // Mappings from desired Dataspace/RenderIntent to the supported
+    // Dataspace/ColorMode/RenderIntent.
+    using ColorModeKey = uint64_t;
+    struct ColorModeValue {
+        ui::Dataspace dataspace;
+        ui::ColorMode colorMode;
+        ui::RenderIntent renderIntent;
+    };
+
+    static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
+        return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
+    }
+    void populateColorModes(
+            const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes);
+    void addColorMode(
+            const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes,
+            const ui::ColorMode mode, const ui::RenderIntent intent);
+
+    std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
 };
 
 struct DisplayDeviceState {
@@ -300,6 +334,30 @@
     bool isSecure = false;
 };
 
+class DisplayRenderArea : public RenderArea {
+public:
+    DisplayRenderArea(const sp<const DisplayDevice> device,
+                      ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
+          : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(),
+                              rotation) {}
+    DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
+                      uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+          : RenderArea(reqHeight, reqWidth, CaptureFill::OPAQUE, rotation), mDevice(device),
+                              mSourceCrop(sourceCrop) {}
+
+    const Transform& getTransform() const override { return mDevice->getTransform(); }
+    Rect getBounds() const override { return mDevice->getBounds(); }
+    int getHeight() const override { return mDevice->getHeight(); }
+    int getWidth() const override { return mDevice->getWidth(); }
+    bool isSecure() const override { return mDevice->isSecure(); }
+    bool needsFiltering() const override { return mDevice->needsFiltering(); }
+    Rect getSourceCrop() const override { return mSourceCrop; }
+
+private:
+    const sp<const DisplayDevice> mDevice;
+    const Rect mSourceCrop;
+};
+
 }; // namespace android
 
 #endif // ANDROID_DISPLAY_DEVICE_H
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index cf01ad0..37ba433 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -19,10 +19,14 @@
 
 #include <inttypes.h>
 #include <log/log.h>
-#include <gui/BufferQueue.h>
 
 #include "ComposerHal.h"
 
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <gui/BufferQueue.h>
+#include <hidl/HidlTransportUtils.h>
+
 namespace android {
 
 using hardware::Return;
@@ -31,6 +35,8 @@
 
 namespace Hwc2 {
 
+Composer::~Composer() = default;
+
 namespace {
 
 class BufferHandle {
@@ -103,6 +109,8 @@
 
 } // anonymous namespace
 
+namespace impl {
+
 Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
     : CommandWriterBase(initialMaxSize) {}
 
@@ -113,10 +121,9 @@
 void Composer::CommandWriter::setLayerInfo(uint32_t type, uint32_t appId)
 {
     constexpr uint16_t kSetLayerInfoLength = 2;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_LAYER_INFO),
-        kSetLayerInfoLength);
+    beginCommand(static_cast<V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_LAYER_INFO),
+                 kSetLayerInfoLength);
     write(type);
     write(appId);
     endCommand();
@@ -126,10 +133,9 @@
         const IVrComposerClient::BufferMetadata& metadata)
 {
     constexpr uint16_t kSetClientTargetMetadataLength = 7;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
-        kSetClientTargetMetadataLength);
+    beginCommand(static_cast<V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
+                 kSetClientTargetMetadataLength);
     writeBufferMetadata(metadata);
     endCommand();
 }
@@ -138,10 +144,9 @@
         const IVrComposerClient::BufferMetadata& metadata)
 {
     constexpr uint16_t kSetLayerBufferMetadataLength = 7;
-    beginCommand(
-        static_cast<IComposerClient::Command>(
-            IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
-        kSetLayerBufferMetadataLength);
+    beginCommand(static_cast<V2_1::IComposerClient::Command>(
+                         IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
+                 kSetLayerBufferMetadataLength);
     writeBufferMetadata(metadata);
     endCommand();
 }
@@ -157,15 +162,11 @@
     write64(metadata.usage);
 }
 
-Composer::Composer(bool useVrComposer)
+Composer::Composer(const std::string& serviceName)
     : mWriter(kWriterInitialSize),
-      mIsUsingVrComposer(useVrComposer)
+      mIsUsingVrComposer(serviceName == std::string("vr"))
 {
-    if (mIsUsingVrComposer) {
-        mComposer = IComposer::getService("vr");
-    } else {
-        mComposer = IComposer::getService(); // use default name
-    }
+    mComposer = V2_1::IComposer::getService(serviceName);
 
     if (mComposer == nullptr) {
         LOG_ALWAYS_FATAL("failed to get hwcomposer service");
@@ -182,6 +183,13 @@
         LOG_ALWAYS_FATAL("failed to create composer client");
     }
 
+    // 2.2 support is optional
+    sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer);
+    if (composer_2_2 != nullptr) {
+        mClient_2_2 = IComposerClient::castFrom(mClient);
+        LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2");
+    }
+
     if (mIsUsingVrComposer) {
         sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
         if (vrClient == nullptr) {
@@ -190,6 +198,8 @@
     }
 }
 
+Composer::~Composer() = default;
+
 std::vector<IComposer::Capability> Composer::getCapabilities()
 {
     std::vector<IComposer::Capability> capabilities;
@@ -227,6 +237,10 @@
     mWriter.reset();
 }
 
+Error Composer::executeCommands() {
+    return execute();
+}
+
 uint32_t Composer::getMaxVirtualDisplayCount()
 {
     auto ret = mClient->getMaxVirtualDisplayCount();
@@ -238,17 +252,32 @@
 {
     const uint32_t bufferSlotCount = 1;
     Error error = kDefaultError;
-    mClient->createVirtualDisplay(width, height, *format, bufferSlotCount,
-            [&](const auto& tmpError, const auto& tmpDisplay,
-                const auto& tmpFormat) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
+    if (mClient_2_2) {
+        mClient_2_2->createVirtualDisplay_2_2(width, height, *format, bufferSlotCount,
+                [&](const auto& tmpError, const auto& tmpDisplay,
+                    const auto& tmpFormat) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
 
-                *outDisplay = tmpDisplay;
-                *format = tmpFormat;
+                    *outDisplay = tmpDisplay;
+                    *format = tmpFormat;
+                });
+    } else {
+        mClient->createVirtualDisplay(width, height,
+                static_cast<types::V1_0::PixelFormat>(*format), bufferSlotCount,
+                [&](const auto& tmpError, const auto& tmpDisplay,
+                    const auto& tmpFormat) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
+
+                    *outDisplay = tmpDisplay;
+                    *format = static_cast<PixelFormat>(tmpFormat);
             });
+    }
 
     return error;
 }
@@ -316,15 +345,29 @@
         std::vector<ColorMode>* outModes)
 {
     Error error = kDefaultError;
-    mClient->getColorModes(display,
-            [&](const auto& tmpError, const auto& tmpModes) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
 
-                *outModes = tmpModes;
-            });
+    if (mClient_2_2) {
+        mClient_2_2->getColorModes_2_2(display,
+                [&](const auto& tmpError, const auto& tmpModes) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
+
+                    *outModes = tmpModes;
+                });
+    } else {
+        mClient->getColorModes(display,
+                [&](const auto& tmpError, const auto& tmpModes) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
+                    for (types::V1_0::ColorMode colorMode : tmpModes) {
+                        outModes->push_back(static_cast<ColorMode>(colorMode));
+                    }
+                });
+    }
 
     return error;
 }
@@ -485,7 +528,7 @@
             .height = target->getHeight(),
             .stride = target->getStride(),
             .layerCount = target->getLayerCount(),
-            .format = static_cast<PixelFormat>(target->getPixelFormat()),
+            .format = static_cast<types::V1_0::PixelFormat>(target->getPixelFormat()),
             .usage = target->getUsage(),
         };
         mWriter.setClientTargetMetadata(metadata);
@@ -500,9 +543,16 @@
     return Error::NONE;
 }
 
-Error Composer::setColorMode(Display display, ColorMode mode)
+Error Composer::setColorMode(Display display, ColorMode mode,
+        RenderIntent renderIntent)
 {
-    auto ret = mClient->setColorMode(display, mode);
+    hardware::Return<Error> ret(kDefaultError);
+    if (mClient_2_2) {
+        ret = mClient_2_2->setColorMode_2_2(display, mode, renderIntent);
+    } else {
+        ret = mClient->setColorMode(display,
+                static_cast<types::V1_0::ColorMode>(mode));
+    }
     return unwrapRet(ret);
 }
 
@@ -522,9 +572,14 @@
     return Error::NONE;
 }
 
-Error Composer::setPowerMode(Display display, IComposerClient::PowerMode mode)
-{
-    auto ret = mClient->setPowerMode(display, mode);
+Error Composer::setPowerMode(Display display, IComposerClient::PowerMode mode) {
+    Return<Error> ret(Error::UNSUPPORTED);
+    if (mClient_2_2) {
+        ret = mClient_2_2->setPowerMode_2_2(display, mode);
+    } else if (mode != IComposerClient::PowerMode::ON_SUSPEND) {
+        ret = mClient->setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode));
+    }
+
     return unwrapRet(ret);
 }
 
@@ -600,7 +655,7 @@
             .height = buffer->getHeight(),
             .stride = buffer->getStride(),
             .layerCount = buffer->getLayerCount(),
-            .format = static_cast<PixelFormat>(buffer->getPixelFormat()),
+            .format = static_cast<types::V1_0::PixelFormat>(buffer->getPixelFormat()),
             .usage = buffer->getUsage(),
         };
         mWriter.setLayerBufferMetadata(metadata);
@@ -754,40 +809,50 @@
         }
     }
 
+    if (commandLength == 0) {
+        mWriter.reset();
+        return Error::NONE;
+    }
+
     Error error = kDefaultError;
-    auto ret = mClient->executeCommands(commandLength, commandHandles,
-            [&](const auto& tmpError, const auto& tmpOutChanged,
-                const auto& tmpOutLength, const auto& tmpOutHandles)
-            {
-                error = tmpError;
+    hardware::Return<void> ret;
+    auto hidl_callback = [&](const auto& tmpError, const auto& tmpOutChanged,
+                             const auto& tmpOutLength, const auto& tmpOutHandles)
+                         {
+                             error = tmpError;
 
-                // set up new output command queue if necessary
-                if (error == Error::NONE && tmpOutChanged) {
-                    error = kDefaultError;
-                    mClient->getOutputCommandQueue(
-                            [&](const auto& tmpError,
-                                const auto& tmpDescriptor)
-                            {
-                                error = tmpError;
-                                if (error != Error::NONE) {
-                                    return;
-                                }
+                             // set up new output command queue if necessary
+                             if (error == Error::NONE && tmpOutChanged) {
+                                 error = kDefaultError;
+                                 mClient->getOutputCommandQueue(
+                                     [&](const auto& tmpError,
+                                         const auto& tmpDescriptor)
+                                     {
+                                         error = tmpError;
+                                         if (error != Error::NONE) {
+                                             return;
+                                     }
 
-                                mReader.setMQDescriptor(tmpDescriptor);
-                            });
-                }
+                                     mReader.setMQDescriptor(tmpDescriptor);
+                                 });
+                             }
 
-                if (error != Error::NONE) {
-                    return;
-                }
+                             if (error != Error::NONE) {
+                                 return;
+                             }
 
-                if (mReader.readQueue(tmpOutLength, tmpOutHandles)) {
-                    error = mReader.parse();
-                    mReader.reset();
-                } else {
-                    error = Error::NO_RESOURCES;
-                }
-            });
+                             if (mReader.readQueue(tmpOutLength, tmpOutHandles)) {
+                                 error = mReader.parse();
+                                 mReader.reset();
+                             } else {
+                                 error = Error::NO_RESOURCES;
+                             }
+                         };
+    if (mClient_2_2) {
+        ret = mClient_2_2->executeCommands_2_2(commandLength, commandHandles, hidl_callback);
+    } else {
+        ret = mClient->executeCommands(commandLength, commandHandles, hidl_callback);
+    }
     // executeCommands can fail because of out-of-fd and we do not want to
     // abort() in that case
     if (!ret.isOk()) {
@@ -799,7 +864,8 @@
             mReader.takeErrors();
 
         for (const auto& cmdErr : commandErrors) {
-            auto command = mWriter.getCommand(cmdErr.location);
+            auto command =
+                    static_cast<IComposerClient::Command>(mWriter.getCommand(cmdErr.location));
 
             if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
                 command == IComposerClient::Command::PRESENT_DISPLAY ||
@@ -817,6 +883,80 @@
     return error;
 }
 
+// Composer HAL 2.2
+
+Error Composer::setLayerPerFrameMetadata(Display display, Layer layer,
+        const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
+    if (!mClient_2_2) {
+        return Error::UNSUPPORTED;
+    }
+
+    mWriter.selectDisplay(display);
+    mWriter.selectLayer(layer);
+    mWriter.setLayerPerFrameMetadata(perFrameMetadatas);
+    return Error::NONE;
+}
+
+Error Composer::getPerFrameMetadataKeys(
+        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+    if (!mClient_2_2) {
+        return Error::UNSUPPORTED;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        *outKeys = tmpKeys;
+    });
+
+    return error;
+}
+
+Error Composer::getRenderIntents(Display display, ColorMode colorMode,
+        std::vector<RenderIntent>* outRenderIntents) {
+    if (!mClient_2_2) {
+        outRenderIntents->push_back(RenderIntent::COLORIMETRIC);
+        return Error::NONE;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_2->getRenderIntents(display, colorMode,
+            [&](const auto& tmpError, const auto& tmpKeys) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        *outRenderIntents = tmpKeys;
+    });
+
+    return error;
+}
+
+Error Composer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix)
+{
+    if (!mClient_2_2) {
+        *outMatrix = mat4();
+        return Error::NONE;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_2->getDataspaceSaturationMatrix(dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        *outMatrix = mat4(tmpMatrix.data());
+    });
+
+    return error;
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
@@ -830,7 +970,8 @@
     uint16_t length = 0;
 
     while (!isEmpty()) {
-        if (!beginCommand(&command, &length)) {
+        auto command_2_1 = reinterpret_cast<V2_1::IComposerClient::Command*>(&command);
+        if (!beginCommand(command_2_1, &length)) {
             break;
         }
 
@@ -1113,6 +1254,8 @@
     *state = data.presentOrValidateState;
 }
 
+} // namespace impl
+
 } // namespace Hwc2
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 533509b..beee539 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -24,39 +24,170 @@
 #include <vector>
 
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <gui/HdrMetadata.h>
+#include <math/mat4.h>
+#include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
-#include <IComposerCommandBuffer.h>
 
 namespace android {
 
 namespace Hwc2 {
 
-using android::frameworks::vr::composer::V1_0::IVrComposerClient;
+using frameworks::vr::composer::V1_0::IVrComposerClient;
 
-using android::hardware::graphics::common::V1_0::ColorMode;
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Dataspace;
-using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::common::V1_0::Transform;
+namespace types = hardware::graphics::common;
 
-using android::hardware::graphics::composer::V2_1::IComposer;
-using android::hardware::graphics::composer::V2_1::IComposerCallback;
-using android::hardware::graphics::composer::V2_1::IComposerClient;
-using android::hardware::graphics::composer::V2_1::Error;
-using android::hardware::graphics::composer::V2_1::Display;
-using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_1::Config;
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_2 = hardware::graphics::composer::V2_2;
 
-using android::hardware::graphics::composer::V2_1::CommandWriterBase;
-using android::hardware::graphics::composer::V2_1::CommandReaderBase;
+using types::V1_0::ColorTransform;
+using types::V1_0::Hdr;
+using types::V1_0::Transform;
 
-using android::hardware::kSynchronizedReadWrite;
-using android::hardware::MessageQueue;
-using android::hardware::MQDescriptorSync;
-using android::hardware::hidl_vec;
-using android::hardware::hidl_handle;
+using types::V1_1::ColorMode;
+using types::V1_1::Dataspace;
+using types::V1_1::PixelFormat;
+using types::V1_1::RenderIntent;
+
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::IComposerCallback;
+using V2_1::Layer;
+
+using V2_2::CommandReaderBase;
+using V2_2::CommandWriterBase;
+using V2_2::IComposer;
+using V2_2::IComposerClient;
+
+using PerFrameMetadata = IComposerClient::PerFrameMetadata;
+using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
+
+class Composer {
+public:
+    virtual ~Composer() = 0;
+
+    virtual std::vector<IComposer::Capability> getCapabilities() = 0;
+    virtual std::string dumpDebugInfo() = 0;
+
+    virtual void registerCallback(const sp<IComposerCallback>& callback) = 0;
+
+    // Returns true if the connected composer service is running in a remote
+    // process, false otherwise. This will return false if the service is
+    // configured in passthrough mode, for example.
+    virtual bool isRemote() = 0;
+
+    // Reset all pending commands in the command buffer. Useful if you want to
+    // skip a frame but have already queued some commands.
+    virtual void resetCommands() = 0;
+
+    // Explicitly flush all pending commands in the command buffer.
+    virtual Error executeCommands() = 0;
+
+    virtual uint32_t getMaxVirtualDisplayCount() = 0;
+    virtual bool isUsingVrComposer() const = 0;
+    virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+                                       Display* outDisplay) = 0;
+    virtual Error destroyVirtualDisplay(Display display) = 0;
+
+    virtual Error acceptDisplayChanges(Display display) = 0;
+
+    virtual Error createLayer(Display display, Layer* outLayer) = 0;
+    virtual Error destroyLayer(Display display, Layer layer) = 0;
+
+    virtual Error getActiveConfig(Display display, Config* outConfig) = 0;
+    virtual Error getChangedCompositionTypes(
+            Display display, std::vector<Layer>* outLayers,
+            std::vector<IComposerClient::Composition>* outTypes) = 0;
+    virtual Error getColorModes(Display display, std::vector<ColorMode>* outModes) = 0;
+    virtual Error getDisplayAttribute(Display display, Config config,
+                                      IComposerClient::Attribute attribute, int32_t* outValue) = 0;
+    virtual Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs) = 0;
+    virtual Error getDisplayName(Display display, std::string* outName) = 0;
+
+    virtual Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
+                                     std::vector<Layer>* outLayers,
+                                     std::vector<uint32_t>* outLayerRequestMasks) = 0;
+
+    virtual Error getDisplayType(Display display, IComposerClient::DisplayType* outType) = 0;
+    virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
+    virtual Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
+                                     float* outMaxLuminance, float* outMaxAverageLuminance,
+                                     float* outMinLuminance) = 0;
+
+    virtual Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
+                                   std::vector<int>* outReleaseFences) = 0;
+
+    virtual Error presentDisplay(Display display, int* outPresentFence) = 0;
+
+    virtual Error setActiveConfig(Display display, Config config) = 0;
+
+    /*
+     * The composer caches client targets internally.  When target is nullptr,
+     * the composer uses slot to look up the client target from its cache.
+     * When target is not nullptr, the cache is updated with the new target.
+     */
+    virtual Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+                                  int acquireFence, Dataspace dataspace,
+                                  const std::vector<IComposerClient::Rect>& damage) = 0;
+    virtual Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) = 0;
+    virtual Error setColorTransform(Display display, const float* matrix, ColorTransform hint) = 0;
+    virtual Error setOutputBuffer(Display display, const native_handle_t* buffer,
+                                  int releaseFence) = 0;
+    virtual Error setPowerMode(Display display, IComposerClient::PowerMode mode) = 0;
+    virtual Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) = 0;
+
+    virtual Error setClientTargetSlotCount(Display display) = 0;
+
+    virtual Error validateDisplay(Display display, uint32_t* outNumTypes,
+                                  uint32_t* outNumRequests) = 0;
+
+    virtual Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+                                           uint32_t* outNumRequests, int* outPresentFence,
+                                           uint32_t* state) = 0;
+
+    virtual Error setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) = 0;
+    /* see setClientTarget for the purpose of slot */
+    virtual Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
+                                 const sp<GraphicBuffer>& buffer, int acquireFence) = 0;
+    virtual Error setLayerSurfaceDamage(Display display, Layer layer,
+                                        const std::vector<IComposerClient::Rect>& damage) = 0;
+    virtual Error setLayerBlendMode(Display display, Layer layer,
+                                    IComposerClient::BlendMode mode) = 0;
+    virtual Error setLayerColor(Display display, Layer layer,
+                                const IComposerClient::Color& color) = 0;
+    virtual Error setLayerCompositionType(Display display, Layer layer,
+                                          IComposerClient::Composition type) = 0;
+    virtual Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) = 0;
+    virtual Error setLayerDisplayFrame(Display display, Layer layer,
+                                       const IComposerClient::Rect& frame) = 0;
+    virtual Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) = 0;
+    virtual Error setLayerSidebandStream(Display display, Layer layer,
+                                         const native_handle_t* stream) = 0;
+    virtual Error setLayerSourceCrop(Display display, Layer layer,
+                                     const IComposerClient::FRect& crop) = 0;
+    virtual Error setLayerTransform(Display display, Layer layer, Transform transform) = 0;
+    virtual Error setLayerVisibleRegion(Display display, Layer layer,
+                                        const std::vector<IComposerClient::Rect>& visible) = 0;
+    virtual Error setLayerZOrder(Display display, Layer layer, uint32_t z) = 0;
+    virtual Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) = 0;
+
+    // Composer HAL 2.2
+    virtual Error setLayerPerFrameMetadata(
+            Display display, Layer layer,
+            const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) = 0;
+    virtual Error getPerFrameMetadataKeys(
+            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+    virtual Error getRenderIntents(Display display, ColorMode colorMode,
+            std::vector<RenderIntent>* outRenderIntents) = 0;
+    virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0;
+};
+
+namespace impl {
 
 class CommandReader : public CommandReaderBase {
 public:
@@ -134,120 +265,121 @@
 };
 
 // Composer is a wrapper to IComposer, a proxy to server-side composer.
-class Composer {
+class Composer final : public Hwc2::Composer {
 public:
-    Composer(bool useVrComposer);
+    Composer(const std::string& serviceName);
+    ~Composer() override;
 
-    std::vector<IComposer::Capability> getCapabilities();
-    std::string dumpDebugInfo();
+    std::vector<IComposer::Capability> getCapabilities() override;
+    std::string dumpDebugInfo() override;
 
-    void registerCallback(const sp<IComposerCallback>& callback);
+    void registerCallback(const sp<IComposerCallback>& callback) override;
 
     // Returns true if the connected composer service is running in a remote
     // process, false otherwise. This will return false if the service is
     // configured in passthrough mode, for example.
-    bool isRemote();
+    bool isRemote() override;
 
     // Reset all pending commands in the command buffer. Useful if you want to
     // skip a frame but have already queued some commands.
-    void resetCommands();
+    void resetCommands() override;
 
-    uint32_t getMaxVirtualDisplayCount();
-    bool isUsingVrComposer() const { return mIsUsingVrComposer; }
-    Error createVirtualDisplay(uint32_t width, uint32_t height,
-            PixelFormat* format, Display* outDisplay);
-    Error destroyVirtualDisplay(Display display);
+    // Explicitly flush all pending commands in the command buffer.
+    Error executeCommands() override;
 
-    Error acceptDisplayChanges(Display display);
+    uint32_t getMaxVirtualDisplayCount() override;
+    bool isUsingVrComposer() const override { return mIsUsingVrComposer; }
+    Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+                               Display* outDisplay) override;
+    Error destroyVirtualDisplay(Display display) override;
 
-    Error createLayer(Display display, Layer* outLayer);
-    Error destroyLayer(Display display, Layer layer);
+    Error acceptDisplayChanges(Display display) override;
 
-    Error getActiveConfig(Display display, Config* outConfig);
-    Error getChangedCompositionTypes(Display display,
-            std::vector<Layer>* outLayers,
-            std::vector<IComposerClient::Composition>* outTypes);
-    Error getColorModes(Display display, std::vector<ColorMode>* outModes);
-    Error getDisplayAttribute(Display display, Config config,
-            IComposerClient::Attribute attribute, int32_t* outValue);
+    Error createLayer(Display display, Layer* outLayer) override;
+    Error destroyLayer(Display display, Layer layer) override;
+
+    Error getActiveConfig(Display display, Config* outConfig) override;
+    Error getChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
+                                     std::vector<IComposerClient::Composition>* outTypes) override;
+    Error getColorModes(Display display, std::vector<ColorMode>* outModes) override;
+    Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+                              int32_t* outValue) override;
     Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
-    Error getDisplayName(Display display, std::string* outName);
+    Error getDisplayName(Display display, std::string* outName) override;
 
     Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
-            std::vector<Layer>* outLayers,
-            std::vector<uint32_t>* outLayerRequestMasks);
+                             std::vector<Layer>* outLayers,
+                             std::vector<uint32_t>* outLayerRequestMasks) override;
 
-    Error getDisplayType(Display display,
-            IComposerClient::DisplayType* outType);
-    Error getDozeSupport(Display display, bool* outSupport);
-    Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
-            float* outMaxLuminance, float* outMaxAverageLuminance,
-            float* outMinLuminance);
+    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+    Error getDozeSupport(Display display, bool* outSupport) override;
+    Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
+                             float* outMaxAverageLuminance, float* outMinLuminance) override;
 
     Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
-            std::vector<int>* outReleaseFences);
+                           std::vector<int>* outReleaseFences) override;
 
-    Error presentDisplay(Display display, int* outPresentFence);
+    Error presentDisplay(Display display, int* outPresentFence) override;
 
-    Error setActiveConfig(Display display, Config config);
+    Error setActiveConfig(Display display, Config config) override;
 
     /*
      * The composer caches client targets internally.  When target is nullptr,
      * the composer uses slot to look up the client target from its cache.
      * When target is not nullptr, the cache is updated with the new target.
      */
-    Error setClientTarget(Display display, uint32_t slot,
-            const sp<GraphicBuffer>& target,
-            int acquireFence, Dataspace dataspace,
-            const std::vector<IComposerClient::Rect>& damage);
-    Error setColorMode(Display display, ColorMode mode);
-    Error setColorTransform(Display display, const float* matrix,
-            ColorTransform hint);
+    Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
+                          int acquireFence, Dataspace dataspace,
+                          const std::vector<IComposerClient::Rect>& damage) override;
+    Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
+    Error setColorTransform(Display display, const float* matrix, ColorTransform hint) override;
     Error setOutputBuffer(Display display, const native_handle_t* buffer,
-            int releaseFence);
-    Error setPowerMode(Display display, IComposerClient::PowerMode mode);
-    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled);
+                          int releaseFence) override;
+    Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
 
-    Error setClientTargetSlotCount(Display display);
+    Error setClientTargetSlotCount(Display display) override;
 
     Error validateDisplay(Display display, uint32_t* outNumTypes,
-            uint32_t* outNumRequests);
+                          uint32_t* outNumRequests) override;
 
-    Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
-                                   uint32_t* outNumRequests,
-                                   int* outPresentFence,
-                                   uint32_t* state);
+    Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes, uint32_t* outNumRequests,
+                                   int* outPresentFence, uint32_t* state) override;
 
-    Error setCursorPosition(Display display, Layer layer,
-            int32_t x, int32_t y);
+    Error setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
     /* see setClientTarget for the purpose of slot */
     Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
-            const sp<GraphicBuffer>& buffer, int acquireFence);
+                         const sp<GraphicBuffer>& buffer, int acquireFence) override;
     Error setLayerSurfaceDamage(Display display, Layer layer,
-            const std::vector<IComposerClient::Rect>& damage);
-    Error setLayerBlendMode(Display display, Layer layer,
-            IComposerClient::BlendMode mode);
-    Error setLayerColor(Display display, Layer layer,
-            const IComposerClient::Color& color);
+                                const std::vector<IComposerClient::Rect>& damage) override;
+    Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
+    Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
     Error setLayerCompositionType(Display display, Layer layer,
-            IComposerClient::Composition type);
-    Error setLayerDataspace(Display display, Layer layer,
-            Dataspace dataspace);
+                                  IComposerClient::Composition type) override;
+    Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override;
     Error setLayerDisplayFrame(Display display, Layer layer,
-            const IComposerClient::Rect& frame);
-    Error setLayerPlaneAlpha(Display display, Layer layer,
-            float alpha);
+                               const IComposerClient::Rect& frame) override;
+    Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
     Error setLayerSidebandStream(Display display, Layer layer,
-            const native_handle_t* stream);
+                                 const native_handle_t* stream) override;
     Error setLayerSourceCrop(Display display, Layer layer,
-            const IComposerClient::FRect& crop);
-    Error setLayerTransform(Display display, Layer layer,
-            Transform transform);
+                             const IComposerClient::FRect& crop) override;
+    Error setLayerTransform(Display display, Layer layer, Transform transform) override;
     Error setLayerVisibleRegion(Display display, Layer layer,
-            const std::vector<IComposerClient::Rect>& visible);
-    Error setLayerZOrder(Display display, Layer layer, uint32_t z);
-    Error setLayerInfo(Display display, Layer layer, uint32_t type,
-                       uint32_t appId);
+                                const std::vector<IComposerClient::Rect>& visible) override;
+    Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+    Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) override;
+
+    // Composer HAL 2.2
+    Error setLayerPerFrameMetadata(
+            Display display, Layer layer,
+            const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
+    Error getPerFrameMetadataKeys(
+            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+    Error getRenderIntents(Display display, ColorMode colorMode,
+            std::vector<RenderIntent>* outRenderIntents) override;
+    Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
+
 private:
     class CommandWriter : public CommandWriterBase {
     public:
@@ -270,8 +402,10 @@
     // this function to execute the command queue.
     Error execute();
 
-    sp<IComposer> mComposer;
-    sp<IComposerClient> mClient;
+    sp<V2_1::IComposer> mComposer;
+
+    sp<V2_1::IComposerClient> mClient;
+    sp<IComposerClient> mClient_2_2;
 
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
@@ -284,6 +418,8 @@
     const bool mIsUsingVrComposer;
 };
 
+} // namespace impl
+
 } // namespace Hwc2
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index cb08f08..f744f5c 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -50,14 +50,6 @@
     };
     virtual status_t prepareFrame(CompositionType compositionType) = 0;
 
-#ifndef USE_HWC2
-    // Should be called when composition rendering is complete for a frame (but
-    // eglSwapBuffers hasn't necessarily been called). Required by certain
-    // older drivers for synchronization.
-    // TODO: Remove this when we drop support for HWC 1.0.
-    virtual status_t compositionComplete() = 0;
-#endif
-
     // Inform the surface that GLES composition is complete for this frame, and
     // the surface should make sure that HWComposer has the correct buffer for
     // this frame. Some implementations may only push a new buffer to
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 1ac21c6..e6d7834 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -27,13 +27,12 @@
 #include <utils/String8.h>
 #include <log/log.h>
 
-#include <EGL/egl.h>
-
 #include <hardware/hardware.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 
@@ -45,6 +44,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+using ui::Dataspace;
+
 /*
  * This implements the (main) framebuffer management. This class is used
  * mostly by SurfaceFlinger, but also by command line GL application.
@@ -58,36 +59,29 @@
     mCurrentBufferSlot(-1),
     mCurrentBuffer(),
     mCurrentFence(Fence::NO_FENCE),
-#ifdef USE_HWC2
     mHwc(hwc),
     mHasPendingRelease(false),
     mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
     mPreviousBuffer()
-#else
-    mHwc(hwc)
-#endif
 {
-#ifdef USE_HWC2
     ALOGV("Creating for display %d", disp);
-#endif
 
     mName = "FramebufferSurface";
     mConsumer->setConsumerName(mName);
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-#ifdef USE_HWC2
     const auto& activeConfig = mHwc.getActiveConfig(disp);
     mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
             activeConfig->getHeight());
-#else
-    mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
-    mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
-#endif
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
+void FramebufferSurface::resizeBuffers(const uint32_t width, const uint32_t height) {
+    mConsumer->setDefaultBufferSize(width, height);
+}
+
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
     return NO_ERROR;
 }
@@ -97,43 +91,29 @@
 }
 
 status_t FramebufferSurface::advanceFrame() {
-#ifdef USE_HWC2
     uint32_t slot = 0;
     sp<GraphicBuffer> buf;
     sp<Fence> acquireFence(Fence::NO_FENCE);
-    android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    Dataspace dataspace = Dataspace::UNKNOWN;
     status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
+    mDataSpace = dataspace;
     if (result != NO_ERROR) {
         ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
                 strerror(-result), result);
     }
     return result;
-#else
-    // Once we remove FB HAL support, we can call nextBuffer() from here
-    // instead of using onFrameAvailable(). No real benefit, except it'll be
-    // more like VirtualDisplaySurface.
-    return NO_ERROR;
-#endif
 }
 
-#ifdef USE_HWC2
 status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
         sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
-        android_dataspace_t& outDataspace) {
-#else
-status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
-#endif
+        Dataspace& outDataspace) {
     Mutex::Autolock lock(mMutex);
 
     BufferItem item;
     status_t err = acquireBufferLocked(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-#ifdef USE_HWC2
         mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
                 &outSlot, &outBuffer);
-#else
-        outBuffer = mCurrentBuffer;
-#endif
         return NO_ERROR;
     } else if (err != NO_ERROR) {
         ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -150,60 +130,28 @@
     // had released the old buffer first.
     if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
         item.mSlot != mCurrentBufferSlot) {
-#ifdef USE_HWC2
         mHasPendingRelease = true;
         mPreviousBufferSlot = mCurrentBufferSlot;
         mPreviousBuffer = mCurrentBuffer;
-#else
-        // Release the previous buffer.
-        err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
-        if (err < NO_ERROR) {
-            ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
-            return err;
-        }
-#endif
     }
     mCurrentBufferSlot = item.mSlot;
     mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
     mCurrentFence = item.mFence;
 
     outFence = item.mFence;
-#ifdef USE_HWC2
     mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
             &outSlot, &outBuffer);
-    outDataspace = item.mDataSpace;
+    outDataspace = static_cast<Dataspace>(item.mDataSpace);
     status_t result =
             mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", result);
         return result;
     }
-#else
-    outBuffer = mCurrentBuffer;
-#endif
 
     return NO_ERROR;
 }
 
-#ifndef USE_HWC2
-// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
-void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
-    sp<GraphicBuffer> buf;
-    sp<Fence> acquireFence;
-    status_t err = nextBuffer(buf, acquireFence);
-    if (err != NO_ERROR) {
-        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
-                strerror(-err), err);
-        return;
-    }
-    err = mHwc.fbPost(mDisplayType, acquireFence, buf);
-    if (err != NO_ERROR) {
-        ALOGE("error posting framebuffer: %d", err);
-    }
-}
-#endif
-
 void FramebufferSurface::freeBufferLocked(int slotIndex) {
     ConsumerBase::freeBufferLocked(slotIndex);
     if (slotIndex == mCurrentBufferSlot) {
@@ -212,7 +160,6 @@
 }
 
 void FramebufferSurface::onFrameCommitted() {
-#ifdef USE_HWC2
     if (mHasPendingRelease) {
         sp<Fence> fence = mHwc.getPresentFence(mDisplayType);
         if (fence->isValid()) {
@@ -221,42 +168,25 @@
             ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the"
                     " fence: %s (%d)", strerror(-result), result);
         }
-        status_t result = releaseBufferLocked(mPreviousBufferSlot,
-                mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+        status_t result = releaseBufferLocked(mPreviousBufferSlot, mPreviousBuffer);
         ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:"
                 " %s (%d)", strerror(-result), result);
 
         mPreviousBuffer.clear();
         mHasPendingRelease = false;
     }
-#else
-    sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
-    if (fence->isValid() &&
-            mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
-        status_t err = addReleaseFence(mCurrentBufferSlot,
-                mCurrentBuffer, fence);
-        ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
-                strerror(-err), err);
-    }
-#endif
 }
 
-#ifndef USE_HWC2
-status_t FramebufferSurface::compositionComplete()
-{
-    return mHwc.fbCompositionComplete();
-}
-#endif
-
 void FramebufferSurface::dumpAsString(String8& result) const {
-    ConsumerBase::dumpState(result);
+    Mutex::Autolock lock(mMutex);
+    result.appendFormat("  FramebufferSurface: dataspace: %s(%d)\n",
+                        dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                        mDataSpace);
+    ConsumerBase::dumpLocked(result, "   ");
 }
 
 void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
 {
-#ifndef USE_HWC2
-    mHwc.fbDump(result);
-#endif
     ConsumerBase::dumpLocked(result, prefix);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 69a72d7..0fd8e9e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -42,25 +42,17 @@
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
-#ifndef USE_HWC2
-    virtual status_t compositionComplete();
-#endif
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
 
-    // Cannot resize a buffers in a FramebufferSurface. Only works with virtual
-    // displays.
-    virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
+    virtual void resizeBuffers(const uint32_t width, const uint32_t height);
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
 private:
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
 
-#ifndef USE_HWC2
-    virtual void onFrameAvailable(const BufferItem& item);
-#endif
     virtual void freeBufferLocked(int slotIndex);
 
     virtual void dumpLocked(String8& result, const char* prefix) const;
@@ -68,12 +60,8 @@
     // nextBuffer waits for and then latches the next buffer from the
     // BufferQueue and releases the previously latched buffer to the
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
-#ifdef USE_HWC2
     status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
-            sp<Fence>& outFence, android_dataspace_t& outDataspace);
-#else
-    status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence);
-#endif
+            sp<Fence>& outFence, ui::Dataspace& outDataspace);
 
     // mDisplayType must match one of the HWC display types
     int mDisplayType;
@@ -83,7 +71,14 @@
     // or the buffer is not associated with a slot.
     int mCurrentBufferSlot;
 
-    // mCurrentBuffer is the current buffer or NULL to indicate that there is
+    // mDataSpace is the dataspace of the current composition buffer for
+    // this FramebufferSurface. It will be 0 when HWC is doing the
+    // compositing. Otherwise it will display the dataspace of the buffer
+    // use for compositing which can change as wide-color content is
+    // on/off.
+    ui::Dataspace mDataSpace;
+
+    // mCurrentBuffer is the current buffer or nullptr to indicate that there is
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
 
@@ -93,14 +88,12 @@
     // Hardware composer, owned by SurfaceFlinger.
     HWComposer& mHwc;
 
-#ifdef USE_HWC2
     HWComposerBufferCache mHwcBufferCache;
 
     // Previous buffer to release after getting an updated retire fence
     bool mHasPendingRelease;
     int mPreviousBufferSlot;
     sp<GraphicBuffer> mPreviousBuffer;
-#endif
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index ae44ae0..1a60c83 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -30,13 +30,16 @@
 
 #include <android/configuration.h>
 
-#include <algorithm>
 #include <inttypes.h>
+#include <algorithm>
+#include <iterator>
+#include <set>
 
 using android::Fence;
 using android::FloatRect;
 using android::GraphicBuffer;
 using android::HdrCapabilities;
+using android::HdrMetadata;
 using android::Rect;
 using android::Region;
 using android::sp;
@@ -46,30 +49,28 @@
 namespace HWC2 {
 
 namespace Hwc2 = android::Hwc2;
+using android::ui::ColorMode;
+using android::ui::Dataspace;
+using android::ui::PixelFormat;
+using android::ui::RenderIntent;
 
 namespace {
 
+inline bool hasMetadataKey(const std::set<Hwc2::PerFrameMetadataKey>& keys,
+                           const Hwc2::PerFrameMetadataKey& key) {
+    return keys.find(key) != keys.end();
+}
+
 class ComposerCallbackBridge : public Hwc2::IComposerCallback {
 public:
     ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
-            : mCallback(callback), mSequenceId(sequenceId),
-              mHasPrimaryDisplay(false) {}
+            : mCallback(callback), mSequenceId(sequenceId) {}
 
     Return<void> onHotplug(Hwc2::Display display,
                            IComposerCallback::Connection conn) override
     {
         HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
-        if (!mHasPrimaryDisplay) {
-            LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected,
-                    "Initial onHotplug callback should be "
-                    "primary display connected");
-            mHasPrimaryDisplay = true;
-            mCallback->onHotplugReceived(mSequenceId, display,
-                                         connection, true);
-        } else {
-            mCallback->onHotplugReceived(mSequenceId, display,
-                                         connection, false);
-        }
+        mCallback->onHotplugReceived(mSequenceId, display, connection);
         return Void();
     }
 
@@ -85,12 +86,9 @@
         return Void();
     }
 
-    bool HasPrimaryDisplay() { return mHasPrimaryDisplay; }
-
 private:
     ComposerCallback* mCallback;
     int32_t mSequenceId;
-    bool mHasPrimaryDisplay;
 };
 
 } // namespace anonymous
@@ -98,12 +96,7 @@
 
 // Device methods
 
-Device::Device(bool useVrComposer)
-  : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)),
-    mCapabilities(),
-    mDisplays(),
-    mRegisteredCallback(false)
-{
+Device::Device(std::unique_ptr<android::Hwc2::Composer> composer) : mComposer(std::move(composer)) {
     loadCapabilities();
 }
 
@@ -117,8 +110,6 @@
     sp<ComposerCallbackBridge> callbackBridge(
             new ComposerCallbackBridge(callback, sequenceId));
     mComposer->registerCallback(callbackBridge);
-    LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(),
-            "Registered composer callback but didn't get primary display");
 }
 
 // Required by HWC2 device
@@ -134,23 +125,22 @@
 }
 
 Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
-        android_pixel_format_t* format, Display** outDisplay)
+        PixelFormat* format, Display** outDisplay)
 {
     ALOGI("Creating virtual display");
 
     hwc2_display_t displayId = 0;
-    auto intFormat = static_cast<Hwc2::PixelFormat>(*format);
     auto intError = mComposer->createVirtualDisplay(width, height,
-            &intFormat, &displayId);
+            format, &displayId);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
     }
 
     auto display = std::make_unique<Display>(
-            *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual);
+            *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, DisplayType::Virtual);
+    display->setConnected(true);
     *outDisplay = display.get();
-    *format = static_cast<android_pixel_format_t>(intFormat);
     mDisplays.emplace(displayId, std::move(display));
     ALOGI("Created virtual display");
     return Error::None;
@@ -164,31 +154,32 @@
 
 void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
     if (connection == Connection::Connected) {
-        auto display = getDisplayById(displayId);
-        if (display) {
-            if (display->isConnected()) {
-                ALOGW("Attempt to hotplug connect display %" PRIu64
-                        " , which is already connected.", displayId);
-            } else {
-                display->setConnected(true);
-            }
-        } else {
-            DisplayType displayType;
-            auto intError = mComposer->getDisplayType(displayId,
-                    reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
-                            &displayType));
-            auto error = static_cast<Error>(intError);
-            if (error != Error::None) {
-                ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
-                        "Aborting hotplug attempt.",
-                        displayId, to_string(error).c_str(), intError);
-                return;
-            }
-
-            auto newDisplay = std::make_unique<Display>(
-                    *mComposer.get(), mCapabilities, displayId, displayType);
-            mDisplays.emplace(displayId, std::move(newDisplay));
+        // If we get a hotplug connected event for a display we already have,
+        // destroy the display and recreate it. This will force us to requery
+        // the display params and recreate all layers on that display.
+        auto oldDisplay = getDisplayById(displayId);
+        if (oldDisplay != nullptr && oldDisplay->isConnected()) {
+            ALOGI("Hotplug connecting an already connected display."
+                    " Clearing old display state.");
         }
+        mDisplays.erase(displayId);
+
+        DisplayType displayType;
+        auto intError = mComposer->getDisplayType(displayId,
+                reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
+                        &displayType));
+        auto error = static_cast<Error>(intError);
+        if (error != Error::None) {
+            ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
+                    "Aborting hotplug attempt.",
+                    displayId, to_string(error).c_str(), intError);
+            return;
+        }
+
+        auto newDisplay = std::make_unique<Display>(
+                *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
+        newDisplay->setConnected(true);
+        mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
         // The display will later be destroyed by a call to
         // destroyDisplay(). For now we just mark it disconnected.
@@ -221,19 +212,23 @@
     }
 }
 
+Error Device::flushCommands()
+{
+    return static_cast<Error>(mComposer->executeCommands());
+}
+
 // Display methods
 
-Display::Display(android::Hwc2::Composer& composer,
-                 const std::unordered_set<Capability>& capabilities,
-                 hwc2_display_t id, DisplayType type)
-  : mComposer(composer),
-    mCapabilities(capabilities),
-    mId(id),
-    mIsConnected(false),
-    mType(type)
-{
+Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
+                 const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
+                 DisplayType type)
+      : mComposer(composer),
+        mPowerAdvisor(advisor),
+        mCapabilities(capabilities),
+        mId(id),
+        mIsConnected(false),
+        mType(type) {
     ALOGV("Created display %" PRIu64, id);
-    setConnected(true);
 }
 
 Display::~Display() {
@@ -345,6 +340,31 @@
     return Error::None;
 }
 
+Error Display::getActiveConfigIndex(int* outIndex) const {
+    ALOGV("[%" PRIu64 "] getActiveConfigIndex", mId);
+    hwc2_config_t configId = 0;
+    auto intError = mComposer.getActiveConfig(mId, &configId);
+    auto error = static_cast<Error>(intError);
+
+    if (error != Error::None) {
+        ALOGE("Unable to get active config for mId:[%" PRIu64 "]", mId);
+        *outIndex = -1;
+        return error;
+    }
+
+    auto pos = mConfigs.find(configId);
+    if (pos != mConfigs.end()) {
+        *outIndex = std::distance(mConfigs.begin(), pos);
+    } else {
+        ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId, configId);
+        // Return no error, but the caller needs to check for a negative index
+        // to detect this case
+        *outIndex = -1;
+    }
+
+    return Error::None;
+}
+
 Error Display::getChangedCompositionTypes(
         std::unordered_map<Layer*, Composition>* outTypes)
 {
@@ -377,23 +397,61 @@
     return Error::None;
 }
 
-Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
+Error Display::getColorModes(std::vector<ColorMode>* outModes) const
 {
-    std::vector<Hwc2::ColorMode> modes;
-    auto intError = mComposer.getColorModes(mId, &modes);
-    uint32_t numModes = modes.size();
+    auto intError = mComposer.getColorModes(mId, outModes);
+    return static_cast<Error>(intError);
+}
+
+Error Display::getSupportedPerFrameMetadata(int32_t* outSupportedPerFrameMetadata) const
+{
+    *outSupportedPerFrameMetadata = 0;
+    std::vector<Hwc2::PerFrameMetadataKey> tmpKeys;
+    auto intError = mComposer.getPerFrameMetadataKeys(mId, &tmpKeys);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
     }
 
-    outModes->resize(numModes);
-    for (size_t i = 0; i < numModes; i++) {
-        (*outModes)[i] = static_cast<android_color_mode_t>(modes[i]);
+    // Check whether a specific metadata type is supported. A metadata type is considered
+    // supported if and only if all required fields are supported.
+
+    // SMPTE2086
+    std::set<Hwc2::PerFrameMetadataKey> keys(tmpKeys.begin(), tmpKeys.end());
+    if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::WHITE_POINT_X) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::WHITE_POINT_Y) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_LUMINANCE) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MIN_LUMINANCE)) {
+        *outSupportedPerFrameMetadata |= HdrMetadata::Type::SMPTE2086;
     }
+    // CTA861_3
+    if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL) &&
+        hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL)) {
+        *outSupportedPerFrameMetadata |= HdrMetadata::Type::CTA861_3;
+    }
+
     return Error::None;
 }
 
+Error Display::getRenderIntents(ColorMode colorMode,
+        std::vector<RenderIntent>* outRenderIntents) const
+{
+    auto intError = mComposer.getRenderIntents(mId, colorMode, outRenderIntents);
+    return static_cast<Error>(intError);
+}
+
+Error Display::getDataspaceSaturationMatrix(Dataspace dataspace, android::mat4* outMatrix)
+{
+    auto intError = mComposer.getDataspaceSaturationMatrix(dataspace, outMatrix);
+    return static_cast<Error>(intError);
+}
+
 std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
 {
     std::vector<std::shared_ptr<const Config>> configs;
@@ -459,28 +517,21 @@
     return Error::None;
 }
 
-Error Display::getHdrCapabilities(
-        std::unique_ptr<HdrCapabilities>* outCapabilities) const
+Error Display::getHdrCapabilities(HdrCapabilities* outCapabilities) const
 {
-    uint32_t numTypes = 0;
     float maxLuminance = -1.0f;
     float maxAverageLuminance = -1.0f;
     float minLuminance = -1.0f;
-    std::vector<Hwc2::Hdr> intTypes;
-    auto intError = mComposer.getHdrCapabilities(mId, &intTypes,
+    std::vector<Hwc2::Hdr> types;
+    auto intError = mComposer.getHdrCapabilities(mId, &types,
             &maxLuminance, &maxAverageLuminance, &minLuminance);
     auto error = static_cast<HWC2::Error>(intError);
 
-    std::vector<int32_t> types;
-    for (auto type : intTypes) {
-        types.push_back(static_cast<int32_t>(type));
-    }
-    numTypes = types.size();
     if (error != Error::None) {
         return error;
     }
 
-    *outCapabilities = std::make_unique<HdrCapabilities>(std::move(types),
+    *outCapabilities = HdrCapabilities(std::move(types),
             maxLuminance, maxAverageLuminance, minLuminance);
     return Error::None;
 }
@@ -544,20 +595,24 @@
 }
 
 Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target,
-        const sp<Fence>& acquireFence, android_dataspace_t dataspace)
+        const sp<Fence>& acquireFence, Dataspace dataspace)
 {
     // TODO: Properly encode client target surface damage
     int32_t fenceFd = acquireFence->dup();
     auto intError = mComposer.setClientTarget(mId, slot, target,
-            fenceFd, static_cast<Hwc2::Dataspace>(dataspace),
-            std::vector<Hwc2::IComposerClient::Rect>());
+            fenceFd, dataspace, std::vector<Hwc2::IComposerClient::Rect>());
     return static_cast<Error>(intError);
 }
 
-Error Display::setColorMode(android_color_mode_t mode)
+Error Display::setColorMode(ColorMode mode, RenderIntent renderIntent)
 {
-    auto intError = mComposer.setColorMode(
-            mId, static_cast<Hwc2::ColorMode>(mode));
+    // When the color mode is switched to DISPLAY_P3, we want to boost the GPU frequency
+    // so that GPU composition can finish in time. When color mode is switched from
+    // DISPLAY_P3, we want to reset GPU frequency.
+    const bool expensiveRenderingExpected = (mode == ColorMode::DISPLAY_P3);
+    mPowerAdvisor.setExpensiveRenderingExpected(mId, expensiveRenderingExpected);
+
+    auto intError = mComposer.setColorMode(mId, mode, renderIntent);
     return static_cast<Error>(intError);
 }
 
@@ -632,17 +687,14 @@
     return error;
 }
 
-void Display::discardCommands()
-{
-    mComposer.resetCommands();
-}
-
 // For use by Device
 
 void Display::setConnected(bool connected) {
-    if (!mIsConnected && connected && mType == DisplayType::Physical) {
+    if (!mIsConnected && connected) {
         mComposer.setClientTargetSlotCount(mId);
-        loadConfigs();
+        if (mType == DisplayType::Physical) {
+            loadConfigs();
+        }
     }
     mIsConnected = connected;
 }
@@ -708,8 +760,7 @@
 
 // Layer methods
 
-Layer::Layer(android::Hwc2::Composer& composer,
-             const std::unordered_set<Capability>& capabilities,
+Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
              hwc2_display_t displayId, hwc2_layer_t layerId)
   : mComposer(composer),
     mCapabilities(capabilities),
@@ -798,14 +849,59 @@
     return static_cast<Error>(intError);
 }
 
-Error Layer::setDataspace(android_dataspace_t dataspace)
+Error Layer::setDataspace(Dataspace dataspace)
 {
     if (dataspace == mDataSpace) {
         return Error::None;
     }
     mDataSpace = dataspace;
-    auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
-    auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace);
+    auto intError = mComposer.setLayerDataspace(mDisplayId, mId, mDataSpace);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
+        const android::HdrMetadata& metadata)
+{
+    if (metadata == mHdrMetadata) {
+        return Error::None;
+    }
+
+    mHdrMetadata = metadata;
+    int validTypes = mHdrMetadata.validTypes & supportedPerFrameMetadata;
+    std::vector<Hwc2::PerFrameMetadata> perFrameMetadatas;
+    if (validTypes & HdrMetadata::SMPTE2086) {
+        perFrameMetadatas.insert(perFrameMetadatas.end(),
+                                 {{Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
+                                         mHdrMetadata.smpte2086.displayPrimaryRed.x},
+                                   {Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
+                                         mHdrMetadata.smpte2086.displayPrimaryRed.y},
+                                   {Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
+                                         mHdrMetadata.smpte2086.displayPrimaryGreen.x},
+                                   {Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
+                                         mHdrMetadata.smpte2086.displayPrimaryGreen.y},
+                                   {Hwc2::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
+                                         mHdrMetadata.smpte2086.displayPrimaryBlue.x},
+                                   {Hwc2::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
+                                         mHdrMetadata.smpte2086.displayPrimaryBlue.y},
+                                   {Hwc2::PerFrameMetadataKey::WHITE_POINT_X,
+                                         mHdrMetadata.smpte2086.whitePoint.x},
+                                   {Hwc2::PerFrameMetadataKey::WHITE_POINT_Y,
+                                         mHdrMetadata.smpte2086.whitePoint.y},
+                                   {Hwc2::PerFrameMetadataKey::MAX_LUMINANCE,
+                                         mHdrMetadata.smpte2086.maxLuminance},
+                                   {Hwc2::PerFrameMetadataKey::MIN_LUMINANCE,
+                                         mHdrMetadata.smpte2086.minLuminance}});
+    }
+
+    if (validTypes & HdrMetadata::CTA861_3) {
+        perFrameMetadatas.insert(perFrameMetadatas.end(),
+                                 {{Hwc2::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
+                                         mHdrMetadata.cta8613.maxContentLightLevel},
+                                   {Hwc2::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+                                         mHdrMetadata.cta8613.maxFrameAverageLightLevel}});
+    }
+
+    auto intError = mComposer.setLayerPerFrameMetadata(mDisplayId, mId, perFrameMetadatas);
     return static_cast<Error>(intError);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 949f0e3..e423167 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,9 +23,10 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
-#include <ui/HdrCapabilities.h>
+#include <gui/HdrMetadata.h>
 #include <math/mat4.h>
-
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
@@ -35,7 +36,8 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
-#include <map>
+
+#include "PowerAdvisor.h"
 
 namespace android {
     class Fence;
@@ -46,6 +48,8 @@
     namespace Hwc2 {
         class Composer;
     }
+
+    class TestableSurfaceFlinger;
 }
 
 namespace HWC2 {
@@ -65,8 +69,7 @@
 class ComposerCallback {
  public:
     virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
-                                   Connection connection,
-                                   bool primaryDisplay) = 0;
+                                   Connection connection) = 0;
     virtual void onRefreshReceived(int32_t sequenceId,
                                    hwc2_display_t display) = 0;
     virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
@@ -79,10 +82,7 @@
 class Device
 {
 public:
-    // useVrComposer is passed to the composer HAL. When true, the composer HAL
-    // will use the vr composer service, otherwise it uses the real hardware
-    // composer.
-    Device(bool useVrComposer);
+    explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
 
     void registerCallback(ComposerCallback* callback, int32_t sequenceId);
 
@@ -96,7 +96,7 @@
 
     uint32_t getMaxVirtualDisplayCount() const;
     Error createVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* format, Display** outDisplay);
+            android::ui::PixelFormat* format, Display** outDisplay);
     void destroyDisplay(hwc2_display_t displayId);
 
     void onHotplug(hwc2_display_t displayId, Connection connection);
@@ -107,6 +107,11 @@
 
     android::Hwc2::Composer* getComposer() { return mComposer.get(); }
 
+    // We buffer most state changes and flush them implicitly with
+    // Display::validate, Display::present, and Display::presentOrValidate.
+    // This method provides an explicit way to flush state changes to HWC.
+    Error flushCommands();
+
 private:
     // Initialization methods
 
@@ -116,14 +121,15 @@
     std::unique_ptr<android::Hwc2::Composer> mComposer;
     std::unordered_set<Capability> mCapabilities;
     std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
-    bool mRegisteredCallback;
+    android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
+    bool mRegisteredCallback = false;
 };
 
 // Convenience C++ class to access hwc2_device_t Display functions directly.
 class Display
 {
 public:
-    Display(android::Hwc2::Composer& composer,
+    Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
             const std::unordered_set<Capability>& capabilities,
             hwc2_display_t id, DisplayType type);
     ~Display();
@@ -204,10 +210,20 @@
     [[clang::warn_unused_result]] Error destroyLayer(Layer* layer);
     [[clang::warn_unused_result]] Error getActiveConfig(
             std::shared_ptr<const Config>* outConfig) const;
+    [[clang::warn_unused_result]] Error getActiveConfigIndex(int* outIndex) const;
     [[clang::warn_unused_result]] Error getChangedCompositionTypes(
             std::unordered_map<Layer*, Composition>* outTypes);
     [[clang::warn_unused_result]] Error getColorModes(
-            std::vector<android_color_mode_t>* outModes) const;
+            std::vector<android::ui::ColorMode>* outModes) const;
+    // outSupportedPerFrameMetadata is an opaque bitmask to the callers
+    // but contains HdrMetadata::Type::*.
+    [[clang::warn_unused_result]] Error getSupportedPerFrameMetadata(
+            int32_t* outSupportedPerFrameMetadata) const;
+    [[clang::warn_unused_result]] Error getRenderIntents(
+            android::ui::ColorMode colorMode,
+            std::vector<android::ui::RenderIntent>* outRenderIntents) const;
+    [[clang::warn_unused_result]] Error getDataspaceSaturationMatrix(
+            android::ui::Dataspace dataspace, android::mat4* outMatrix);
 
     // Doesn't call into the HWC2 device, so no errors are possible
     std::vector<std::shared_ptr<const Config>> getConfigs() const;
@@ -219,7 +235,7 @@
     [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
     [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
     [[clang::warn_unused_result]] Error getHdrCapabilities(
-            std::unique_ptr<android::HdrCapabilities>* outCapabilities) const;
+            android::HdrCapabilities* outCapabilities) const;
     [[clang::warn_unused_result]] Error getReleaseFences(
             std::unordered_map<Layer*,
                     android::sp<android::Fence>>* outFences) const;
@@ -230,8 +246,10 @@
     [[clang::warn_unused_result]] Error setClientTarget(
             uint32_t slot, const android::sp<android::GraphicBuffer>& target,
             const android::sp<android::Fence>& acquireFence,
-            android_dataspace_t dataspace);
-    [[clang::warn_unused_result]] Error setColorMode(android_color_mode_t mode);
+            android::ui::Dataspace dataspace);
+    [[clang::warn_unused_result]] Error setColorMode(
+            android::ui::ColorMode mode,
+            android::ui::RenderIntent renderIntent);
     [[clang::warn_unused_result]] Error setColorTransform(
             const android::mat4& matrix, android_color_transform_t hint);
     [[clang::warn_unused_result]] Error setOutputBuffer(
@@ -242,14 +260,8 @@
     [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
             uint32_t* outNumRequests);
     [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes,
-                                                 uint32_t* outNumRequests,
-                                                          android::sp<android::Fence>* outPresentFence, uint32_t* state);
-
-    // Most methods in this class write a command to a command buffer.  The
-    // command buffer is implicitly submitted in validate, present, and
-    // presentOrValidate.  This method provides a way to discard the commands,
-    // which can be used to discard stale commands.
-    void discardCommands();
+            uint32_t* outNumRequests,
+            android::sp<android::Fence>* outPresentFence, uint32_t* state);
 
     // Other Display methods
 
@@ -266,21 +278,22 @@
     // on this display
     Layer* getLayerById(hwc2_layer_t id) const;
 
+    friend android::TestableSurfaceFlinger;
+
     // Member variables
 
     // These are references to data owned by HWC2::Device, which will outlive
     // this HWC2::Display, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
+    android::Hwc2::PowerAdvisor& mPowerAdvisor;
     const std::unordered_set<Capability>& mCapabilities;
 
     hwc2_display_t mId;
     bool mIsConnected;
     DisplayType mType;
     std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
-    // The ordering in this map matters, for getConfigs(), when it is
-    // converted to a vector
-    std::map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+    std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
 };
 
 // Convenience C++ class to access hwc2_device_t Layer functions directly.
@@ -310,7 +323,10 @@
     [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
     [[clang::warn_unused_result]] Error setCompositionType(Composition type);
     [[clang::warn_unused_result]] Error setDataspace(
-            android_dataspace_t dataspace);
+            android::ui::Dataspace dataspace);
+    [[clang::warn_unused_result]] Error setPerFrameMetadata(
+            const int32_t supportedPerFrameMetadata,
+            const android::HdrMetadata& metadata);
     [[clang::warn_unused_result]] Error setDisplayFrame(
             const android::Rect& frame);
     [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
@@ -333,7 +349,8 @@
 
     hwc2_display_t mDisplayId;
     hwc2_layer_t mId;
-    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
+    android::HdrMetadata mHdrMetadata;
     std::function<void(Layer*)> mLayerDestroyedListener;
 };
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 3f3c67b..f5f7a82 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -36,6 +36,7 @@
 #include <utils/Trace.h>
 #include <utils/Vector.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 
 #include <hardware/hardware.h>
@@ -53,31 +54,42 @@
 #include "../Layer.h"           // needed only for debugging
 #include "../SurfaceFlinger.h"
 
+#define LOG_DISPLAY_ERROR(displayId, msg) \
+    ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
+
+#define LOG_HWC_ERROR(what, error, displayId)                                     \
+    ALOGE("%s: %s failed for display %d: %s (%d)", __FUNCTION__, what, displayId, \
+          to_string(error).c_str(), static_cast<int32_t>(error))
+
+#define RETURN_IF_INVALID_DISPLAY(displayId, ...)            \
+    do {                                                     \
+        if (!isValidDisplay(displayId)) {                    \
+            LOG_DISPLAY_ERROR(displayId, "Invalid display"); \
+            return __VA_ARGS__;                              \
+        }                                                    \
+    } while (false)
+
+#define RETURN_IF_HWC_ERROR_FOR(what, error, displayId, ...) \
+    do {                                                     \
+        if (error != HWC2::Error::None) {                    \
+            LOG_HWC_ERROR(what, error, displayId);           \
+            return __VA_ARGS__;                              \
+        }                                                    \
+    } while (false)
+
+#define RETURN_IF_HWC_ERROR(error, displayId, ...) \
+    RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__)
+
 namespace android {
 
 #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
 
 // ---------------------------------------------------------------------------
 
-HWComposer::HWComposer(bool useVrComposer)
-    : mHwcDevice(),
-      mDisplayData(2),
-      mFreeDisplaySlots(),
-      mHwcDisplaySlots(),
-      mCBContext(),
-      mVSyncCounts(),
-      mRemainingHwcVirtualDisplays(0)
-{
-    for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
-        mLastHwVSync[i] = 0;
-        mVSyncCounts[i] = 0;
-    }
+HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
+      : mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
 
-    mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer);
-    mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
-}
-
-HWComposer::~HWComposer() {}
+HWComposer::~HWComposer() = default;
 
 void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
                                   int32_t sequenceId) {
@@ -119,23 +131,22 @@
     }
 }
 
-void HWComposer::onHotplug(hwc2_display_t displayId,
+void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
                            HWC2::Connection connection) {
-    ALOGV("hotplug: %" PRIu64 ", %s", displayId,
+    if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+        ALOGE("Invalid display type of %d", displayType);
+        return;
+    }
+
+    ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
+            displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
             to_string(connection).c_str());
     mHwcDevice->onHotplug(displayId, connection);
-    if (!mDisplayData[0].hwcDisplay) {
-        ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary"
-                " display would be connected");
-        mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-        mHwcDisplaySlots[displayId] = 0;
-    } else {
-        // Disconnect is handled through HWComposer::disconnectDisplay via
-        // SurfaceFlinger's onHotplugReceived callback handling
-        if (connection == HWC2::Connection::Connected) {
-            mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-            mHwcDisplaySlots[displayId] = 1;
-        }
+    // Disconnect is handled through HWComposer::disconnectDisplay via
+    // SurfaceFlinger's onHotplugReceived callback handling
+    if (connection == HWC2::Connection::Connected) {
+        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+        mHwcDisplaySlots[displayId] = displayType;
     }
 }
 
@@ -195,7 +206,7 @@
 }
 
 status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
-        android_pixel_format_t* format, int32_t *outId) {
+        ui::PixelFormat* format, int32_t *outId) {
     if (mRemainingHwcVirtualDisplays == 0) {
         ALOGE("allocateVirtualDisplay: No remaining virtual displays");
         return NO_MEMORY;
@@ -240,32 +251,21 @@
 }
 
 HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("Failed to create layer on invalid display %d", displayId);
-        return nullptr;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
+
     auto display = mDisplayData[displayId].hwcDisplay;
     HWC2::Layer* layer;
     auto error = display->createLayer(&layer);
-    if (error != HWC2::Error::None) {
-        ALOGE("Failed to create layer on display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return nullptr;
-    }
+    RETURN_IF_HWC_ERROR(error, displayId, nullptr);
     return layer;
 }
 
 void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("Failed to destroy layer on invalid display %d", displayId);
-        return;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId);
+
     auto display = mDisplayData[displayId].hwcDisplay;
     auto error = display->destroyLayer(layer);
-    if (error != HWC2::Error::None) {
-        ALOGE("Failed to destroy layer on display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-    }
+    RETURN_IF_HWC_ERROR(error, displayId);
 }
 
 nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
@@ -279,19 +279,14 @@
 }
 
 bool HWComposer::isConnected(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("isConnected: Attempted to access invalid display %d", displayId);
-        return false;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
     return mDisplayData[displayId].hwcDisplay->isConnected();
 }
 
 std::vector<std::shared_ptr<const HWC2::Display::Config>>
         HWComposer::getConfigs(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("getConfigs: Attempted to access invalid display %d", displayId);
-        return {};
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, {});
+
     auto& displayData = mDisplayData[displayId];
     auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
     if (displayData.configMap.empty()) {
@@ -304,62 +299,66 @@
 
 std::shared_ptr<const HWC2::Display::Config>
         HWComposer::getActiveConfig(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGV("getActiveConfigs: Attempted to access invalid display %d",
-                displayId);
-        return nullptr;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
+
     std::shared_ptr<const HWC2::Display::Config> config;
     auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
     if (error == HWC2::Error::BadConfig) {
-        ALOGE("getActiveConfig: No config active, returning null");
+        LOG_DISPLAY_ERROR(displayId, "No active config");
         return nullptr;
-    } else if (error != HWC2::Error::None) {
-        ALOGE("getActiveConfig failed for display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return nullptr;
-    } else if (!config) {
-        ALOGE("getActiveConfig returned an unknown config for display %d",
-                displayId);
+    }
+
+    RETURN_IF_HWC_ERROR(error, displayId, nullptr);
+
+    if (!config) {
+        LOG_DISPLAY_ERROR(displayId, "Unknown config");
         return nullptr;
     }
 
     return config;
 }
 
-std::vector<android_color_mode_t> HWComposer::getColorModes(int32_t displayId) const {
-    std::vector<android_color_mode_t> modes;
-
+int HWComposer::getActiveConfigIndex(int32_t displayId) const {
     if (!isValidDisplay(displayId)) {
-        ALOGE("getColorModes: Attempted to access invalid display %d",
-                displayId);
-        return modes;
+        ALOGV("getActiveConfigIndex: Attempted to access invalid display %d", displayId);
+        return -1;
+    }
+    int index;
+    auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+    if (error == HWC2::Error::BadConfig) {
+        ALOGE("getActiveConfigIndex: No config active, returning -1");
+        return -1;
+    } else if (error != HWC2::Error::None) {
+        ALOGE("getActiveConfigIndex failed for display %d: %s (%d)", displayId,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        return -1;
+    } else if (index < 0) {
+        ALOGE("getActiveConfigIndex returned an unknown config for display %d", displayId);
+        return -1;
     }
 
+    return index;
+}
+
+std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, {});
+
+    std::vector<ui::ColorMode> modes;
     auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
-    if (error != HWC2::Error::None) {
-        ALOGE("getColorModes failed for display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return std::vector<android_color_mode_t>();
-    }
-
+    RETURN_IF_HWC_ERROR(error, displayId, {});
     return modes;
 }
 
-status_t HWComposer::setActiveColorMode(int32_t displayId, android_color_mode_t mode) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setActiveColorMode: Display %d is not valid", displayId);
-        return BAD_INDEX;
-    }
+status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,
+        ui::RenderIntent renderIntent) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
-    auto error = displayData.hwcDisplay->setColorMode(mode);
-    if (error != HWC2::Error::None) {
-        ALOGE("setActiveConfig: Failed to set color mode %d on display %d: "
-                "%s (%d)", mode, displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
+    auto error = displayData.hwcDisplay->setColorMode(mode, renderIntent);
+    RETURN_IF_HWC_ERROR_FOR(("setColorMode(" + decodeColorMode(mode) + ", " +
+                             decodeRenderIntent(renderIntent) + ")")
+                                    .c_str(),
+                            error, displayId, UNKNOWN_ERROR);
 
     return NO_ERROR;
 }
@@ -371,11 +370,7 @@
         return;
     }
 
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setVsyncEnabled: Attempted to access invalid display %d",
-               displayId);
-        return;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId);
 
     // NOTE: we use our own internal lock here because we have to call
     // into the HWC with the lock held, and we want to make sure
@@ -386,37 +381,25 @@
     if (enabled != displayData.vsyncEnabled) {
         ATRACE_CALL();
         auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
-        if (error == HWC2::Error::None) {
-            displayData.vsyncEnabled = enabled;
+        RETURN_IF_HWC_ERROR(error, displayId);
 
-            char tag[16];
-            snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
-            ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
-        } else {
-            ALOGE("setVsyncEnabled: Failed to set vsync to %s on %d/%" PRIu64
-                    ": %s (%d)", to_string(enabled).c_str(), displayId,
-                    mDisplayData[displayId].hwcDisplay->getId(),
-                    to_string(error).c_str(), static_cast<int32_t>(error));
-        }
+        displayData.vsyncEnabled = enabled;
+
+        char tag[16];
+        snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
+        ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
     }
 }
 
 status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
-        android_dataspace_t dataspace) {
-    if (!isValidDisplay(displayId)) {
-        return BAD_INDEX;
-    }
+        ui::Dataspace dataspace) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     ALOGV("setClientTarget for display %d", displayId);
     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
     auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
-    if (error != HWC2::Error::None) {
-        ALOGE("Failed to set client target for display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return BAD_VALUE;
-    }
-
+    RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
     return NO_ERROR;
 }
 
@@ -429,9 +412,8 @@
         ALOGV("Skipping HWComposer prepare for non-HWC display");
         return NO_ERROR;
     }
-    if (!isValidDisplay(displayId)) {
-        return BAD_INDEX;
-    }
+
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
     auto& hwcDisplay = displayData.hwcDisplay;
@@ -444,16 +426,21 @@
 
     HWC2::Error error = HWC2::Error::None;
 
-    // First try to skip validate altogether if the HWC supports it.
+    // First try to skip validate altogether when there is no client
+    // composition.  When there is client composition, since we haven't
+    // rendered to the client target yet, we should not attempt to skip
+    // validate.
+    //
+    // displayData.hasClientComposition hasn't been updated for this frame.
+    // The check below is incorrect.  We actually rely on HWC here to fall
+    // back to validate when there is any client layer.
     displayData.validateWasSkipped = false;
-    if (hasCapability(HWC2::Capability::SkipValidate) &&
-            !displayData.hasClientComposition) {
+    if (!displayData.hasClientComposition) {
         sp<android::Fence> outPresentFence;
         uint32_t state = UINT32_MAX;
         error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
-        if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
-            ALOGV("skipValidate: Failed to Present or Validate");
-            return UNKNOWN_ERROR;
+        if (error != HWC2::Error::HasChanges) {
+            RETURN_IF_HWC_ERROR_FOR("presentOrValidate", error, displayId, UNKNOWN_ERROR);
         }
         if (state == 1) { //Present Succeeded.
             std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
@@ -469,33 +456,21 @@
         error = hwcDisplay->validate(&numTypes, &numRequests);
     }
     ALOGV("SkipValidate failed, Falling back to SLOW validate/present");
-    if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
-        ALOGE("prepare: validate failed for display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return BAD_INDEX;
+    if (error != HWC2::Error::HasChanges) {
+        RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX);
     }
 
     std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
     changedTypes.reserve(numTypes);
     error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
-    if (error != HWC2::Error::None) {
-        ALOGE("prepare: getChangedCompositionTypes failed on display %d: "
-                "%s (%d)", displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return BAD_INDEX;
-    }
-
+    RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX);
 
     displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
     std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
     layerRequests.reserve(numRequests);
     error = hwcDisplay->getRequests(&displayData.displayRequests,
             &layerRequests);
-    if (error != HWC2::Error::None) {
-        ALOGE("prepare: getRequests failed on display %d: %s (%d)", displayId,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        return BAD_INDEX;
-    }
+    RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
     displayData.hasClientComposition = false;
     displayData.hasDeviceComposition = false;
@@ -530,18 +505,16 @@
             layer->setClearClientTarget(displayId, true);
         } else {
             if (layerRequests.count(hwcLayer) != 0) {
-                ALOGE("prepare: Unknown layer request: %s",
-                        to_string(layerRequests[hwcLayer]).c_str());
+                LOG_DISPLAY_ERROR(displayId,
+                                  ("Unknown layer request " + to_string(layerRequests[hwcLayer]))
+                                          .c_str());
             }
             layer->setClearClientTarget(displayId, false);
         }
     }
 
     error = hwcDisplay->acceptChanges();
-    if (error != HWC2::Error::None) {
-        ALOGE("prepare: acceptChanges failed: %s", to_string(error).c_str());
-        return BAD_INDEX;
-    }
+    RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
 
     return NO_ERROR;
 }
@@ -552,11 +525,21 @@
         // the device
         return false;
     }
-    if (!isValidDisplay(displayId)) {
-        ALOGE("hasDeviceComposition: Invalid display %d", displayId);
+
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
+    return mDisplayData[displayId].hasDeviceComposition;
+}
+
+bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
+    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+        // Displays without a corresponding HWC display are never composed by
+        // the device
         return false;
     }
-    return mDisplayData[displayId].hasDeviceComposition;
+
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
+    return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+             static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
 }
 
 bool HWComposer::hasClientComposition(int32_t displayId) const {
@@ -565,27 +548,19 @@
         // the client
         return true;
     }
-    if (!isValidDisplay(displayId)) {
-        ALOGE("hasClientComposition: Invalid display %d", displayId);
-        return true;
-    }
+
+    RETURN_IF_INVALID_DISPLAY(displayId, true);
     return mDisplayData[displayId].hasClientComposition;
 }
 
 sp<Fence> HWComposer::getPresentFence(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("getPresentFence failed for invalid display %d", displayId);
-        return Fence::NO_FENCE;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
     return mDisplayData[displayId].lastPresentFence;
 }
 
 sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
         HWC2::Layer* layer) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("getLayerReleaseFence: Invalid display");
-        return Fence::NO_FENCE;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
     auto displayFences = mDisplayData[displayId].releaseFences;
     if (displayFences.count(layer) == 0) {
         ALOGV("getLayerReleaseFence: Release fence not found");
@@ -597,40 +572,25 @@
 status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) {
     ATRACE_CALL();
 
-    if (!isValidDisplay(displayId)) {
-        return BAD_INDEX;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
     auto& hwcDisplay = displayData.hwcDisplay;
 
     if (displayData.validateWasSkipped) {
-        hwcDisplay->discardCommands();
-        auto error = displayData.presentError;
-        if (error != HWC2::Error::None) {
-            ALOGE("skipValidate: failed for display %d: %s (%d)",
-                  displayId, to_string(error).c_str(), static_cast<int32_t>(error));
-            return UNKNOWN_ERROR;
-        }
+        // explicitly flush all pending commands
+        auto error = mHwcDevice->flushCommands();
+        RETURN_IF_HWC_ERROR_FOR("flushCommands", error, displayId, UNKNOWN_ERROR);
+        RETURN_IF_HWC_ERROR_FOR("present", displayData.presentError, displayId, UNKNOWN_ERROR);
         return NO_ERROR;
     }
 
     auto error = hwcDisplay->present(&displayData.lastPresentFence);
-    if (error != HWC2::Error::None) {
-        ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)",
-              displayId, to_string(error).c_str(), static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
+    RETURN_IF_HWC_ERROR_FOR("present", error, displayId, UNKNOWN_ERROR);
 
     std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
     error = hwcDisplay->getReleaseFences(&releaseFences);
-    if (error != HWC2::Error::None) {
-        ALOGE("presentAndGetReleaseFences: Failed to get release fences "
-              "for display %d: %s (%d)",
-                displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
+    RETURN_IF_HWC_ERROR_FOR("getReleaseFences", error, displayId, UNKNOWN_ERROR);
 
     displayData.releaseFences = std::move(releaseFences);
 
@@ -639,14 +599,11 @@
 
 status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
     ALOGV("setPowerMode(%d, %d)", displayId, intMode);
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setPowerMode: Bad display");
-        return BAD_INDEX;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+
     if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
-        ALOGE("setPowerMode: Virtual display %d passed in, returning",
-                displayId);
-        return BAD_INDEX;
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
+        return INVALID_OPERATION;
     }
 
     auto mode = static_cast<HWC2::PowerMode>(intMode);
@@ -662,10 +619,8 @@
             {
                 auto error = hwcDisplay->setPowerMode(mode);
                 if (error != HWC2::Error::None) {
-                    ALOGE("setPowerMode: Unable to set power mode %s for "
-                            "display %d: %s (%d)", to_string(mode).c_str(),
-                            displayId, to_string(error).c_str(),
-                            static_cast<int32_t>(error));
+                    LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(),
+                                  error, displayId);
                 }
             }
             break;
@@ -676,21 +631,17 @@
                 bool supportsDoze = false;
                 auto error = hwcDisplay->supportsDoze(&supportsDoze);
                 if (error != HWC2::Error::None) {
-                    ALOGE("setPowerMode: Unable to query doze support for "
-                            "display %d: %s (%d)", displayId,
-                            to_string(error).c_str(),
-                            static_cast<int32_t>(error));
+                    LOG_HWC_ERROR("supportsDoze", error, displayId);
                 }
+
                 if (!supportsDoze) {
                     mode = HWC2::PowerMode::On;
                 }
 
                 error = hwcDisplay->setPowerMode(mode);
                 if (error != HWC2::Error::None) {
-                    ALOGE("setPowerMode: Unable to set power mode %s for "
-                            "display %d: %s (%d)", to_string(mode).c_str(),
-                            displayId, to_string(error).c_str(),
-                            static_cast<int32_t>(error));
+                    LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(),
+                                  error, displayId);
                 }
             }
             break;
@@ -703,48 +654,29 @@
 }
 
 status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setActiveConfig: Display %d is not valid", displayId);
-        return BAD_INDEX;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
     if (displayData.configMap.count(configId) == 0) {
-        ALOGE("setActiveConfig: Invalid config %zd", configId);
+        LOG_DISPLAY_ERROR(displayId, ("Invalid config " + std::to_string(configId)).c_str());
         return BAD_INDEX;
     }
 
-    auto error = displayData.hwcDisplay->setActiveConfig(
-            displayData.configMap[configId]);
-    if (error != HWC2::Error::None) {
-        ALOGE("setActiveConfig: Failed to set config %zu on display %d: "
-                "%s (%d)", configId, displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
-
+    auto error = displayData.hwcDisplay->setActiveConfig(displayData.configMap[configId]);
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
 
 status_t HWComposer::setColorTransform(int32_t displayId,
         const mat4& transform) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setColorTransform: Display %d is not valid", displayId);
-        return BAD_INDEX;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
     bool isIdentity = transform == mat4();
     auto error = displayData.hwcDisplay->setColorTransform(transform,
             isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY :
             HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX);
-    if (error != HWC2::Error::None) {
-        ALOGE("setColorTransform: Failed to set transform on display %d: "
-                "%s (%d)", displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
-
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
 
@@ -754,11 +686,7 @@
 
     auto displayType = HWC2::DisplayType::Invalid;
     auto error = displayData.hwcDisplay->getType(&displayType);
-    if (error != HWC2::Error::None) {
-        ALOGE("disconnectDisplay: Failed to determine type of display %d",
-                displayId);
-        return;
-    }
+    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId);
 
     // If this was a virtual display, add its slot back for reuse by future
     // virtual displays
@@ -776,62 +704,66 @@
 
 status_t HWComposer::setOutputBuffer(int32_t displayId,
         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("setOutputBuffer: Display %d is not valid", displayId);
-        return BAD_INDEX;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
     auto displayType = HWC2::DisplayType::Invalid;
     auto error = hwcDisplay->getType(&displayType);
-    if (error != HWC2::Error::None) {
-        ALOGE("setOutputBuffer: Failed to determine type of display %d",
-                displayId);
-        return NAME_NOT_FOUND;
-    }
+    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId, NAME_NOT_FOUND);
 
     if (displayType != HWC2::DisplayType::Virtual) {
-        ALOGE("setOutputBuffer: Display %d is not virtual", displayId);
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display");
         return INVALID_OPERATION;
     }
 
     error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
-    if (error != HWC2::Error::None) {
-        ALOGE("setOutputBuffer: Failed to set buffer on display %d: %s (%d)",
-                displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return UNKNOWN_ERROR;
-    }
-
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
 
 void HWComposer::clearReleaseFences(int32_t displayId) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("clearReleaseFences: Display %d is not valid", displayId);
-        return;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId);
     mDisplayData[displayId].releaseFences.clear();
 }
 
-std::unique_ptr<HdrCapabilities> HWComposer::getHdrCapabilities(
-        int32_t displayId) {
-    if (!isValidDisplay(displayId)) {
-        ALOGE("getHdrCapabilities: Display %d is not valid", displayId);
-        return nullptr;
-    }
+status_t HWComposer::getHdrCapabilities(
+        int32_t displayId, HdrCapabilities* outCapabilities) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
-    std::unique_ptr<HdrCapabilities> capabilities;
-    auto error = hwcDisplay->getHdrCapabilities(&capabilities);
-    if (error != HWC2::Error::None) {
-        ALOGE("getOutputCapabilities: Failed to get capabilities on display %d:"
-                " %s (%d)", displayId, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-        return nullptr;
-    }
+    auto error = hwcDisplay->getHdrCapabilities(outCapabilities);
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+    return NO_ERROR;
+}
 
-    return capabilities;
+int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, 0);
+
+    int32_t supportedMetadata;
+    auto error = mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata(
+            &supportedMetadata);
+    RETURN_IF_HWC_ERROR(error, displayId, 0);
+    return supportedMetadata;
+}
+
+std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
+        ui::ColorMode colorMode) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, {});
+
+    std::vector<ui::RenderIntent> renderIntents;
+    auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents);
+    RETURN_IF_HWC_ERROR(error, displayId, {});
+    return renderIntents;
+}
+
+mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) {
+    RETURN_IF_INVALID_DISPLAY(displayId, {});
+
+    mat4 matrix;
+    auto error = mDisplayData[displayId].hwcDisplay->getDataspaceSaturationMatrix(dataspace,
+            &matrix);
+    RETURN_IF_HWC_ERROR(error, displayId, {});
+    return matrix;
 }
 
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
@@ -865,6 +797,14 @@
     result.append(mHwcDevice->dump().c_str());
 }
 
+std::optional<hwc2_display_t>
+HWComposer::getHwcDisplayId(int32_t displayId) const {
+    if (!isValidDisplay(displayId)) {
+        return {};
+    }
+    return mDisplayData[displayId].hwcDisplay->getId();
+}
+
 // ---------------------------------------------------------------------------
 
 HWComposer::DisplayData::DisplayData()
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index e25dee1..f968948 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-#ifndef USE_HWC2
-#include "HWComposer_hwc1.h"
-#else
-
 #ifndef ANDROID_SF_HWCOMPOSER_H
 #define ANDROID_SF_HWCOMPOSER_H
 
@@ -27,7 +23,7 @@
 #include <sys/types.h>
 
 #include <ui/Fence.h>
-
+#include <ui/GraphicTypes.h>
 #include <utils/BitSet.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
@@ -37,6 +33,7 @@
 #include <utils/Vector.h>
 
 #include <memory>
+#include <optional>
 #include <set>
 #include <vector>
 
@@ -61,14 +58,16 @@
 class NativeHandle;
 class Region;
 class String8;
+class TestableSurfaceFlinger;
+
+namespace Hwc2 {
+class Composer;
+} // namespace Hwc2
 
 class HWComposer
 {
 public:
-    // useVrComposer is passed to the composer HAL. When true, the composer HAL
-    // will use the vr composer service, otherwise it uses the real hardware
-    // composer.
-    HWComposer(bool useVrComposer);
+    explicit HWComposer(std::unique_ptr<android::Hwc2::Composer> composer);
 
     ~HWComposer();
 
@@ -80,7 +79,7 @@
     // Attempts to allocate a virtual display. If the virtual display is created
     // on the HWC device, outId will contain its HWC ID.
     status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* format, int32_t* outId);
+            ui::PixelFormat* format, int32_t* outId);
 
     // Attempts to create a new layer on this display
     HWC2::Layer* createLayer(int32_t displayId);
@@ -92,7 +91,7 @@
 
     status_t setClientTarget(int32_t displayId, uint32_t slot,
             const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& target, android_dataspace_t dataspace);
+            const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
 
     // Present layers to the display and read releaseFences.
     status_t presentAndGetReleaseFences(int32_t displayId);
@@ -112,6 +111,9 @@
     // does this display have layers handled by HWC
     bool hasDeviceComposition(int32_t displayId) const;
 
+    // does this display have pending request to flip client target
+    bool hasFlipClientTargetRequest(int32_t displayId) const;
+
     // does this display have layers handled by GLES
     bool hasClientComposition(int32_t displayId) const;
 
@@ -131,8 +133,15 @@
     // it can call this to clear the shared pointers in the release fence map
     void clearReleaseFences(int32_t displayId);
 
-    // Returns the HDR capabilities of the given display
-    std::unique_ptr<HdrCapabilities> getHdrCapabilities(int32_t displayId);
+    // Fetches the HDR capabilities of the given display
+    status_t getHdrCapabilities(int32_t displayId, HdrCapabilities* outCapabilities);
+
+    int32_t getSupportedPerFrameMetadata(int32_t displayId) const;
+
+    // Returns the available RenderIntent of the given display.
+    std::vector<ui::RenderIntent> getRenderIntents(int32_t displayId, ui::ColorMode colorMode) const;
+
+    mat4 getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace);
 
     // Events handling ---------------------------------------------------------
 
@@ -140,7 +149,7 @@
     // DisplayDevice::DisplayType of the display is returned as an output param.
     bool onVsync(hwc2_display_t displayId, int64_t timestamp,
                  int32_t* outDisplay);
-    void onHotplug(hwc2_display_t displayId, HWC2::Connection connection);
+    void onHotplug(hwc2_display_t displayId, int32_t displayType, HWC2::Connection connection);
 
     void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
 
@@ -155,10 +164,12 @@
 
     std::shared_ptr<const HWC2::Display::Config>
             getActiveConfig(int32_t displayId) const;
+    int getActiveConfigIndex(int32_t displayId) const;
 
-    std::vector<android_color_mode_t> getColorModes(int32_t displayId) const;
+    std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
 
-    status_t setActiveColorMode(int32_t displayId, android_color_mode_t mode);
+    status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode,
+            ui::RenderIntent renderIntent);
 
     bool isUsingVrComposer() const;
 
@@ -166,7 +177,12 @@
     void dump(String8& out) const;
 
     android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
+
+    std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
 private:
+    // For unit tests
+    friend TestableSurfaceFlinger;
+
     static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
 
     bool isValidDisplay(int32_t displayId) const;
@@ -198,19 +214,20 @@
     };
 
     std::unique_ptr<HWC2::Device>   mHwcDevice;
-    std::vector<DisplayData>        mDisplayData;
+    std::vector<DisplayData> mDisplayData{HWC_NUM_PHYSICAL_DISPLAY_TYPES};
     std::set<size_t>                mFreeDisplaySlots;
     std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
     // protect mDisplayData from races between prepare and dump
     mutable Mutex mDisplayLock;
 
-    cb_context*                     mCBContext;
-    size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-    uint32_t                        mRemainingHwcVirtualDisplays;
+    cb_context* mCBContext = nullptr;
+    size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]{0, 0};
+    uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
 
     // protected by mLock
     mutable Mutex mLock;
-    mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync;
+    mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync{
+            {{HWC_DISPLAY_PRIMARY, 0}, {HWC_DISPLAY_EXTERNAL, 0}}};
 
     // thread-safe
     mutable Mutex mVsyncLock;
@@ -220,5 +237,3 @@
 }; // namespace android
 
 #endif // ANDROID_SF_HWCOMPOSER_H
-
-#endif // #ifdef USE_HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
deleted file mode 100644
index dcb2913..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/misc.h>
-#include <utils/NativeHandle.h>
-#include <utils/String8.h>
-#include <utils/Thread.h>
-#include <utils/Trace.h>
-#include <utils/Vector.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <android/configuration.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-
-#include <system/graphics.h>
-
-#include "HWComposer.h"
-
-#include "../Layer.h"           // needed only for debugging
-#include "../SurfaceFlinger.h"
-
-namespace android {
-
-#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
-
-static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) {
-    uint32_t hwcVersion = hwc->common.version;
-    return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
-}
-
-static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) {
-    uint32_t hwcVersion = hwc->common.version;
-    return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK;
-}
-
-static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc,
-        uint32_t version) {
-    return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK);
-}
-
-// ---------------------------------------------------------------------------
-
-struct HWComposer::cb_context {
-    struct callbacks : public hwc_procs_t {
-        // these are here to facilitate the transition when adding
-        // new callbacks (an implementation can check for NULL before
-        // calling a new callback).
-        void (*zero[4])(void);
-    };
-    callbacks procs;
-    HWComposer* hwc;
-};
-
-// ---------------------------------------------------------------------------
-
-HWComposer::HWComposer(
-        const sp<SurfaceFlinger>& flinger,
-        EventHandler& handler)
-    : mFlinger(flinger),
-      mFbDev(0), mHwc(0), mNumDisplays(1),
-      mCBContext(new cb_context),
-      mEventHandler(handler),
-      mDebugForceFakeVSync(false)
-{
-    for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) {
-        mLists[i] = 0;
-    }
-
-    for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
-        mLastHwVSync[i] = 0;
-        mVSyncCounts[i] = 0;
-    }
-
-    char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.no_hw_vsync", value, "0");
-    mDebugForceFakeVSync = atoi(value);
-
-    bool needVSyncThread = true;
-
-    // Note: some devices may insist that the FB HAL be opened before HWC.
-    int fberr = loadFbHalModule();
-    loadHwcModule();
-
-    if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-        // close FB HAL if we don't needed it.
-        // FIXME: this is temporary until we're not forced to open FB HAL
-        // before HWC.
-        framebuffer_close(mFbDev);
-        mFbDev = NULL;
-    }
-
-    // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
-    if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
-            && !mFbDev) {
-        ALOGE("ERROR: failed to open framebuffer (%s), aborting",
-                strerror(-fberr));
-        abort();
-    }
-
-    // these display IDs are always reserved
-    for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
-        mAllocatedDisplayIDs.markBit(i);
-    }
-
-    if (mHwc) {
-        ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
-              (hwcApiVersion(mHwc) >> 24) & 0xff,
-              (hwcApiVersion(mHwc) >> 16) & 0xff);
-        if (mHwc->registerProcs) {
-            mCBContext->hwc = this;
-            mCBContext->procs.invalidate = &hook_invalidate;
-            mCBContext->procs.vsync = &hook_vsync;
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
-                mCBContext->procs.hotplug = &hook_hotplug;
-            else
-                mCBContext->procs.hotplug = NULL;
-            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
-            mHwc->registerProcs(mHwc, &mCBContext->procs);
-        }
-
-        // don't need a vsync thread if we have a hardware composer
-        needVSyncThread = false;
-        // always turn vsync off when we start
-        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
-
-        // the number of displays we actually have depends on the
-        // hw composer version
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
-            // 1.3 adds support for virtual displays
-            mNumDisplays = MAX_HWC_DISPLAYS;
-        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-            // 1.1 adds support for multiple displays
-            mNumDisplays = NUM_BUILTIN_DISPLAYS;
-        } else {
-            mNumDisplays = 1;
-        }
-    }
-
-    if (mFbDev) {
-        ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
-                "should only have fbdev if no hwc or hwc is 1.0");
-
-        DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
-        disp.connected = true;
-        disp.format = mFbDev->format;
-        DisplayConfig config = DisplayConfig();
-        config.width = mFbDev->width;
-        config.height = mFbDev->height;
-        config.xdpi = mFbDev->xdpi;
-        config.ydpi = mFbDev->ydpi;
-        config.refresh = nsecs_t(1e9 / mFbDev->fps);
-        disp.configs.push_back(config);
-        disp.currentConfig = 0;
-    } else if (mHwc) {
-        // here we're guaranteed to have at least HWC 1.1
-        for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
-            queryDisplayProperties(i);
-        }
-    }
-
-    if (needVSyncThread) {
-        // we don't have VSYNC support, we need to fake it
-        mVSyncThread = new VSyncThread(*this);
-    }
-}
-
-HWComposer::~HWComposer() {
-    if (mHwc) {
-        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
-    }
-    if (mVSyncThread != NULL) {
-        mVSyncThread->requestExitAndWait();
-    }
-    if (mHwc) {
-        hwc_close_1(mHwc);
-    }
-    if (mFbDev) {
-        framebuffer_close(mFbDev);
-    }
-    delete mCBContext;
-}
-
-// Load and prepare the hardware composer module.  Sets mHwc.
-void HWComposer::loadHwcModule()
-{
-    hw_module_t const* module;
-
-    if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
-        ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
-        return;
-    }
-
-    int err = hwc_open_1(module, &mHwc);
-    if (err) {
-        ALOGE("%s device failed to initialize (%s)",
-              HWC_HARDWARE_COMPOSER, strerror(-err));
-        return;
-    }
-
-    if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
-            hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
-            hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
-        ALOGE("%s device version %#x unsupported, will not be used",
-              HWC_HARDWARE_COMPOSER, mHwc->common.version);
-        hwc_close_1(mHwc);
-        mHwc = NULL;
-        return;
-    }
-}
-
-// Load and prepare the FB HAL, which uses the gralloc module.  Sets mFbDev.
-int HWComposer::loadFbHalModule()
-{
-    hw_module_t const* module;
-
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    if (err != 0) {
-        ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
-        return err;
-    }
-
-    return framebuffer_open(module, &mFbDev);
-}
-
-status_t HWComposer::initCheck() const {
-    return mHwc ? NO_ERROR : NO_INIT;
-}
-
-void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
-    cb_context* ctx = reinterpret_cast<cb_context*>(
-            const_cast<hwc_procs_t*>(procs));
-    ctx->hwc->invalidate();
-}
-
-void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
-        int64_t timestamp) {
-    cb_context* ctx = reinterpret_cast<cb_context*>(
-            const_cast<hwc_procs_t*>(procs));
-    ctx->hwc->vsync(disp, timestamp);
-}
-
-void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp,
-        int connected) {
-    cb_context* ctx = reinterpret_cast<cb_context*>(
-            const_cast<hwc_procs_t*>(procs));
-    ctx->hwc->hotplug(disp, connected);
-}
-
-void HWComposer::invalidate() {
-    mEventHandler.onInvalidateReceived(this);
-}
-
-void HWComposer::vsync(int disp, int64_t timestamp) {
-    if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-        {
-            Mutex::Autolock _l(mLock);
-
-            // There have been reports of HWCs that signal several vsync events
-            // with the same timestamp when turning the display off and on. This
-            // is a bug in the HWC implementation, but filter the extra events
-            // out here so they don't cause havoc downstream.
-            if (timestamp == mLastHwVSync[disp]) {
-                ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
-                        timestamp);
-                return;
-            }
-
-            mLastHwVSync[disp] = timestamp;
-        }
-
-        char tag[16];
-        snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
-        ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
-
-        mEventHandler.onVSyncReceived(this, disp, timestamp);
-    }
-}
-
-void HWComposer::hotplug(int disp, int connected) {
-    if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
-        ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
-                disp, connected);
-        return;
-    }
-    queryDisplayProperties(disp);
-    // Do not teardown or recreate the primary display
-    if (disp != HWC_DISPLAY_PRIMARY) {
-        mEventHandler.onHotplugReceived(this, disp, bool(connected));
-    }
-}
-
-static float getDefaultDensity(uint32_t width, uint32_t height) {
-    // Default density is based on TVs: 1080p displays get XHIGH density,
-    // lower-resolution displays get TV density. Maybe eventually we'll need
-    // to update it for 4K displays, though hopefully those just report
-    // accurate DPI information to begin with. This is also used for virtual
-    // displays and even primary displays with older hwcomposers, so be
-    // careful about orientation.
-
-    uint32_t h = width < height ? width : height;
-    if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
-    else           return ACONFIGURATION_DENSITY_TV;
-}
-
-static const uint32_t DISPLAY_ATTRIBUTES[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_COLOR_TRANSFORM,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
-
-static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = {
-    HWC_DISPLAY_VSYNC_PERIOD,
-    HWC_DISPLAY_WIDTH,
-    HWC_DISPLAY_HEIGHT,
-    HWC_DISPLAY_DPI_X,
-    HWC_DISPLAY_DPI_Y,
-    HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-status_t HWComposer::queryDisplayProperties(int disp) {
-
-    LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
-
-    // use zero as default value for unspecified attributes
-    int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
-    memset(values, 0, sizeof(values));
-
-    const size_t MAX_NUM_CONFIGS = 128;
-    uint32_t configs[MAX_NUM_CONFIGS] = {0};
-    size_t numConfigs = MAX_NUM_CONFIGS;
-    status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs);
-    if (err != NO_ERROR) {
-        // this can happen if an unpluggable display is not connected
-        mDisplayData[disp].connected = false;
-        return err;
-    }
-
-    mDisplayData[disp].currentConfig = 0;
-    for (size_t c = 0; c < numConfigs; ++c) {
-        err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
-                DISPLAY_ATTRIBUTES, values);
-        // If this is a pre-1.5 HWC, it may not know about color transform, so
-        // try again with a smaller set of attributes
-        if (err != NO_ERROR) {
-            err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
-                    PRE_HWC15_DISPLAY_ATTRIBUTES, values);
-        }
-        if (err != NO_ERROR) {
-            // we can't get this display's info. turn it off.
-            mDisplayData[disp].connected = false;
-            return err;
-        }
-
-        DisplayConfig config = DisplayConfig();
-        for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
-            switch (DISPLAY_ATTRIBUTES[i]) {
-                case HWC_DISPLAY_VSYNC_PERIOD:
-                    config.refresh = nsecs_t(values[i]);
-                    break;
-                case HWC_DISPLAY_WIDTH:
-                    config.width = values[i];
-                    break;
-                case HWC_DISPLAY_HEIGHT:
-                    config.height = values[i];
-                    break;
-                case HWC_DISPLAY_DPI_X:
-                    config.xdpi = values[i] / 1000.0f;
-                    break;
-                case HWC_DISPLAY_DPI_Y:
-                    config.ydpi = values[i] / 1000.0f;
-                    break;
-                case HWC_DISPLAY_COLOR_TRANSFORM:
-                    config.colorMode = static_cast<android_color_mode_t>(values[i]);
-                    break;
-                default:
-                    ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
-                            i, DISPLAY_ATTRIBUTES[i]);
-                    break;
-            }
-        }
-
-        if (config.xdpi == 0.0f || config.ydpi == 0.0f) {
-            float dpi = getDefaultDensity(config.width, config.height);
-            config.xdpi = dpi;
-            config.ydpi = dpi;
-        }
-
-        mDisplayData[disp].configs.push_back(config);
-    }
-
-    // FIXME: what should we set the format to?
-    mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
-    mDisplayData[disp].connected = true;
-    return NO_ERROR;
-}
-
-status_t HWComposer::setVirtualDisplayProperties(int32_t id,
-        uint32_t w, uint32_t h, uint32_t format) {
-    if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) ||
-            !mAllocatedDisplayIDs.hasBit(id)) {
-        return BAD_INDEX;
-    }
-    size_t configId = mDisplayData[id].currentConfig;
-    mDisplayData[id].format = format;
-    DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId);
-    config.width = w;
-    config.height = h;
-    config.xdpi = config.ydpi = getDefaultDensity(w, h);
-    return NO_ERROR;
-}
-
-int32_t HWComposer::allocateDisplayId() {
-    if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
-        return NO_MEMORY;
-    }
-    int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
-    mAllocatedDisplayIDs.markBit(id);
-    mDisplayData[id].connected = true;
-    mDisplayData[id].configs.resize(1);
-    mDisplayData[id].currentConfig = 0;
-    return id;
-}
-
-status_t HWComposer::freeDisplayId(int32_t id) {
-    if (id < NUM_BUILTIN_DISPLAYS) {
-        // cannot free the reserved IDs
-        return BAD_VALUE;
-    }
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return BAD_INDEX;
-    }
-    mAllocatedDisplayIDs.clearBit(id);
-    mDisplayData[id].connected = false;
-    return NO_ERROR;
-}
-
-nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
-    // this returns the last refresh timestamp.
-    // if the last one is not available, we estimate it based on
-    // the refresh period and whatever closest timestamp we have.
-    Mutex::Autolock _l(mLock);
-    nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    size_t configId = mDisplayData[disp].currentConfig;
-    return now - ((now - mLastHwVSync[disp]) %
-            mDisplayData[disp].configs[configId].refresh);
-}
-
-sp<Fence> HWComposer::getDisplayFence(int disp) const {
-    return mDisplayData[disp].lastDisplayFence;
-}
-
-uint32_t HWComposer::getFormat(int disp) const {
-    if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
-        return HAL_PIXEL_FORMAT_RGBA_8888;
-    } else {
-        return mDisplayData[disp].format;
-    }
-}
-
-bool HWComposer::isConnected(int disp) const {
-    return mDisplayData[disp].connected;
-}
-
-uint32_t HWComposer::getWidth(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].width;
-}
-
-uint32_t HWComposer::getHeight(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].height;
-}
-
-float HWComposer::getDpiX(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].xdpi;
-}
-
-float HWComposer::getDpiY(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].ydpi;
-}
-
-nsecs_t HWComposer::getRefreshPeriod(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].refresh;
-}
-
-android_color_mode_t HWComposer::getColorMode(int disp) const {
-    size_t currentConfig = mDisplayData[disp].currentConfig;
-    return mDisplayData[disp].configs[currentConfig].colorMode;
-}
-
-const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const {
-    return mDisplayData[disp].configs;
-}
-
-size_t HWComposer::getCurrentConfig(int disp) const {
-    return mDisplayData[disp].currentConfig;
-}
-
-void HWComposer::eventControl(int disp, int event, int enabled) {
-    if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
-        ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)",
-              event, disp, enabled);
-        return;
-    }
-    if (event != EVENT_VSYNC) {
-        ALOGW("eventControl got unexpected event %d (disp=%d en=%d)",
-              event, disp, enabled);
-        return;
-    }
-    status_t err = NO_ERROR;
-    if (mHwc && !mDebugForceFakeVSync) {
-        // NOTE: we use our own internal lock here because we have to call
-        // into the HWC with the lock held, and we want to make sure
-        // that even if HWC blocks (which it shouldn't), it won't
-        // affect other threads.
-        Mutex::Autolock _l(mEventControlLock);
-        const int32_t eventBit = 1UL << event;
-        const int32_t newValue = enabled ? eventBit : 0;
-        const int32_t oldValue = mDisplayData[disp].events & eventBit;
-        if (newValue != oldValue) {
-            ATRACE_CALL();
-            err = mHwc->eventControl(mHwc, disp, event, enabled);
-            if (!err) {
-                int32_t& events(mDisplayData[disp].events);
-                events = (events & ~eventBit) | newValue;
-
-                char tag[16];
-                snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
-                ATRACE_INT(tag, enabled);
-            }
-        }
-        // error here should not happen -- not sure what we should
-        // do if it does.
-        ALOGE_IF(err, "eventControl(%d, %d) failed %s",
-                event, enabled, strerror(-err));
-    }
-
-    if (err == NO_ERROR && mVSyncThread != NULL) {
-        mVSyncThread->setEnabled(enabled);
-    }
-}
-
-status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return BAD_INDEX;
-    }
-
-    if (mHwc) {
-        DisplayData& disp(mDisplayData[id]);
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-            // we need space for the HWC_FRAMEBUFFER_TARGET
-            numLayers++;
-        }
-        if (disp.capacity < numLayers || disp.list == NULL) {
-            size_t size = sizeof(hwc_display_contents_1_t)
-                    + numLayers * sizeof(hwc_layer_1_t);
-            free(disp.list);
-            disp.list = (hwc_display_contents_1_t*)malloc(size);
-            disp.capacity = numLayers;
-        }
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-            disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
-            memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
-            const DisplayConfig& currentConfig =
-                    disp.configs[disp.currentConfig];
-            const hwc_rect_t r = { 0, 0,
-                    (int) currentConfig.width, (int) currentConfig.height };
-            disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
-            disp.framebufferTarget->hints = 0;
-            disp.framebufferTarget->flags = 0;
-            disp.framebufferTarget->handle = disp.fbTargetHandle;
-            disp.framebufferTarget->transform = 0;
-            disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
-                disp.framebufferTarget->sourceCropf.left = 0;
-                disp.framebufferTarget->sourceCropf.top = 0;
-                disp.framebufferTarget->sourceCropf.right =
-                        currentConfig.width;
-                disp.framebufferTarget->sourceCropf.bottom =
-                        currentConfig.height;
-            } else {
-                disp.framebufferTarget->sourceCrop = r;
-            }
-            disp.framebufferTarget->displayFrame = r;
-            disp.framebufferTarget->visibleRegionScreen.numRects = 1;
-            disp.framebufferTarget->visibleRegionScreen.rects =
-                &disp.framebufferTarget->displayFrame;
-            disp.framebufferTarget->acquireFenceFd = -1;
-            disp.framebufferTarget->releaseFenceFd = -1;
-            disp.framebufferTarget->planeAlpha = 0xFF;
-        }
-        disp.list->retireFenceFd = -1;
-        disp.list->flags = HWC_GEOMETRY_CHANGED;
-        disp.list->numHwLayers = numLayers;
-    }
-    return NO_ERROR;
-}
-
-status_t HWComposer::setFramebufferTarget(int32_t id,
-        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return BAD_INDEX;
-    }
-    DisplayData& disp(mDisplayData[id]);
-    if (!disp.framebufferTarget) {
-        // this should never happen, but apparently eglCreateWindowSurface()
-        // triggers a Surface::queueBuffer()  on some
-        // devices (!?) -- log and ignore.
-        ALOGE("HWComposer: framebufferTarget is null");
-        return NO_ERROR;
-    }
-
-    int acquireFenceFd = -1;
-    if (acquireFence->isValid()) {
-        acquireFenceFd = acquireFence->dup();
-    }
-
-    // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
-    disp.fbTargetHandle = buf->handle;
-    disp.framebufferTarget->handle = disp.fbTargetHandle;
-    disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
-    return NO_ERROR;
-}
-
-status_t HWComposer::prepare() {
-    Mutex::Autolock _l(mDisplayLock);
-    for (size_t i=0 ; i<mNumDisplays ; i++) {
-        DisplayData& disp(mDisplayData[i]);
-        if (disp.framebufferTarget) {
-            // make sure to reset the type to HWC_FRAMEBUFFER_TARGET
-            // DO NOT reset the handle field to NULL, because it's possible
-            // that we have nothing to redraw (eg: eglSwapBuffers() not called)
-            // in which case, we should continue to use the same buffer.
-            LOG_FATAL_IF(disp.list == NULL);
-            disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
-        }
-        if (!disp.connected && disp.list != NULL) {
-            ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
-                  i, disp.list->numHwLayers);
-        }
-        mLists[i] = disp.list;
-        if (mLists[i]) {
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
-                mLists[i]->outbuf = disp.outbufHandle;
-                mLists[i]->outbufAcquireFenceFd = -1;
-            } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-                // garbage data to catch improper use
-                mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
-                mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
-            } else {
-                mLists[i]->dpy = EGL_NO_DISPLAY;
-                mLists[i]->sur = EGL_NO_SURFACE;
-            }
-        }
-    }
-
-    int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
-    ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
-
-    if (err == NO_ERROR) {
-        // here we're just making sure that "skip" layers are set
-        // to HWC_FRAMEBUFFER and we're also counting how many layers
-        // we have of each type.
-        //
-        // If there are no window layers, we treat the display has having FB
-        // composition, because SurfaceFlinger will use GLES to draw the
-        // wormhole region.
-        for (size_t i=0 ; i<mNumDisplays ; i++) {
-            DisplayData& disp(mDisplayData[i]);
-            disp.hasFbComp = false;
-            disp.hasOvComp = false;
-            if (disp.list) {
-                for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
-                    hwc_layer_1_t& l = disp.list->hwLayers[i];
-
-                    //ALOGD("prepare: %d, type=%d, handle=%p",
-                    //        i, l.compositionType, l.handle);
-
-                    if (l.flags & HWC_SKIP_LAYER) {
-                        l.compositionType = HWC_FRAMEBUFFER;
-                    }
-                    if (l.compositionType == HWC_FRAMEBUFFER) {
-                        disp.hasFbComp = true;
-                    }
-                    if (l.compositionType == HWC_OVERLAY) {
-                        disp.hasOvComp = true;
-                    }
-                    if (l.compositionType == HWC_CURSOR_OVERLAY) {
-                        disp.hasOvComp = true;
-                    }
-                }
-                if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
-                    disp.hasFbComp = true;
-                }
-            } else {
-                disp.hasFbComp = true;
-            }
-        }
-    }
-    return (status_t)err;
-}
-
-bool HWComposer::hasHwcComposition(int32_t id) const {
-    if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
-        return false;
-    return mDisplayData[id].hasOvComp;
-}
-
-bool HWComposer::hasGlesComposition(int32_t id) const {
-    if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
-        return true;
-    return mDisplayData[id].hasFbComp;
-}
-
-sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
-        return Fence::NO_FENCE;
-
-    int fd = INVALID_OPERATION;
-    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-        const DisplayData& disp(mDisplayData[id]);
-        if (disp.framebufferTarget) {
-            fd = disp.framebufferTarget->releaseFenceFd;
-            disp.framebufferTarget->acquireFenceFd = -1;
-            disp.framebufferTarget->releaseFenceFd = -1;
-        }
-    }
-    return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
-}
-
-status_t HWComposer::commit() {
-    int err = NO_ERROR;
-    if (mHwc) {
-        if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-            // On version 1.0, the OpenGL ES target surface is communicated
-            // by the (dpy, sur) fields and we are guaranteed to have only
-            // a single display.
-            mLists[0]->dpy = eglGetCurrentDisplay();
-            mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
-        }
-
-        for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
-            DisplayData& disp(mDisplayData[i]);
-            if (disp.outbufHandle) {
-                mLists[i]->outbuf = disp.outbufHandle;
-                mLists[i]->outbufAcquireFenceFd =
-                        disp.outbufAcquireFence->dup();
-            }
-        }
-
-        err = mHwc->set(mHwc, mNumDisplays, mLists);
-
-        for (size_t i=0 ; i<mNumDisplays ; i++) {
-            DisplayData& disp(mDisplayData[i]);
-            disp.lastDisplayFence = disp.lastRetireFence;
-            disp.lastRetireFence = Fence::NO_FENCE;
-            if (disp.list) {
-                if (disp.list->retireFenceFd != -1) {
-                    disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
-                    disp.list->retireFenceFd = -1;
-                }
-                disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
-            }
-        }
-    }
-    return (status_t)err;
-}
-
-status_t HWComposer::setPowerMode(int disp, int mode) {
-    LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
-    if (mHwc) {
-        if (mode == HWC_POWER_MODE_OFF) {
-            eventControl(disp, HWC_EVENT_VSYNC, 0);
-        }
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
-            return (status_t)mHwc->setPowerMode(mHwc, disp, mode);
-        } else {
-            return (status_t)mHwc->blank(mHwc, disp,
-                    mode == HWC_POWER_MODE_OFF ? 1 : 0);
-        }
-    }
-    return NO_ERROR;
-}
-
-status_t HWComposer::setActiveConfig(int disp, int mode) {
-    LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
-    DisplayData& dd(mDisplayData[disp]);
-    dd.currentConfig = mode;
-    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
-        return (status_t)mHwc->setActiveConfig(mHwc, disp, mode);
-    } else {
-        LOG_FATAL_IF(mode != 0);
-    }
-    return NO_ERROR;
-}
-
-void HWComposer::disconnectDisplay(int disp) {
-    LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY);
-    DisplayData& dd(mDisplayData[disp]);
-    free(dd.list);
-    dd.list = NULL;
-    dd.framebufferTarget = NULL;    // points into dd.list
-    dd.fbTargetHandle = NULL;
-    dd.outbufHandle = NULL;
-    dd.lastRetireFence = Fence::NO_FENCE;
-    dd.lastDisplayFence = Fence::NO_FENCE;
-    dd.outbufAcquireFence = Fence::NO_FENCE;
-    // clear all the previous configs and repopulate when a new
-    // device is added
-    dd.configs.clear();
-}
-
-int HWComposer::getVisualID() const {
-    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-        // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
-        // is supported by the implementation. we can only be in this case
-        // if we have HWC 1.1
-        return HAL_PIXEL_FORMAT_RGBA_8888;
-        //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-    } else {
-        return mFbDev->format;
-    }
-}
-
-bool HWComposer::supportsFramebufferTarget() const {
-    return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
-}
-
-int HWComposer::fbPost(int32_t id,
-        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
-    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-        return setFramebufferTarget(id, acquireFence, buffer);
-    } else {
-        acquireFence->waitForever("HWComposer::fbPost");
-        return mFbDev->post(mFbDev, buffer->handle);
-    }
-}
-
-int HWComposer::fbCompositionComplete() {
-    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
-        return NO_ERROR;
-
-    if (mFbDev->compositionComplete) {
-        return mFbDev->compositionComplete(mFbDev);
-    } else {
-        return INVALID_OPERATION;
-    }
-}
-
-void HWComposer::fbDump(String8& result) {
-    if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
-        const size_t SIZE = 4096;
-        char buffer[SIZE];
-        mFbDev->dump(mFbDev, buffer, SIZE);
-        result.append(buffer);
-    }
-}
-
-status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
-        const sp<GraphicBuffer>& buf) {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
-        return BAD_INDEX;
-    if (id < VIRTUAL_DISPLAY_ID_BASE)
-        return INVALID_OPERATION;
-
-    DisplayData& disp(mDisplayData[id]);
-    disp.outbufHandle = buf->handle;
-    disp.outbufAcquireFence = acquireFence;
-    return NO_ERROR;
-}
-
-sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
-        return Fence::NO_FENCE;
-    return mDisplayData[id].lastRetireFence;
-}
-
-status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
-{
-    if (mHwc->setCursorPositionAsync) {
-        return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
-    }
-    else {
-        return NO_ERROR;
-    }
-}
-
-/*
- * Helper template to implement a concrete HWCLayer
- * This holds the pointer to the concrete hwc layer type
- * and implements the "iterable" side of HWCLayer.
- */
-template<typename CONCRETE, typename HWCTYPE>
-class Iterable : public HWComposer::HWCLayer {
-protected:
-    HWCTYPE* const mLayerList;
-    HWCTYPE* mCurrentLayer;
-    explicit Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
-            mIndex(0) { }
-    inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
-    inline HWCTYPE* getLayer() { return mCurrentLayer; }
-    virtual ~Iterable() { }
-    size_t mIndex;
-private:
-    // returns a copy of ourselves
-    virtual HWComposer::HWCLayer* dup() {
-        return new CONCRETE( static_cast<const CONCRETE&>(*this) );
-    }
-    virtual status_t setLayer(size_t index) {
-        mIndex = index;
-        mCurrentLayer = &mLayerList[index];
-        return NO_ERROR;
-    }
-};
-
-/*
- * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
- * This implements the HWCLayer side of HWCIterableLayer.
- */
-class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
-    struct hwc_composer_device_1* mHwc;
-public:
-    HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer,
-            Vector<Region>* visibleRegions,
-            Vector<Region>* surfaceDamageRegions)
-        : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc),
-          mVisibleRegions(visibleRegions),
-          mSurfaceDamageRegions(surfaceDamageRegions) {}
-
-    virtual int32_t getCompositionType() const {
-        return getLayer()->compositionType;
-    }
-    virtual uint32_t getHints() const {
-        return getLayer()->hints;
-    }
-    virtual sp<Fence> getAndResetReleaseFence() {
-        int fd = getLayer()->releaseFenceFd;
-        getLayer()->releaseFenceFd = -1;
-        return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
-    }
-    virtual void setAcquireFenceFd(int fenceFd) {
-        getLayer()->acquireFenceFd = fenceFd;
-    }
-    virtual void setPerFrameDefaultState() {
-        //getLayer()->compositionType = HWC_FRAMEBUFFER;
-    }
-    virtual void setPlaneAlpha(uint8_t alpha) {
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
-            getLayer()->planeAlpha = alpha;
-        } else {
-            if (alpha < 0xFF) {
-                getLayer()->flags |= HWC_SKIP_LAYER;
-            }
-        }
-    }
-    virtual void setDefaultState() {
-        hwc_layer_1_t* const l = getLayer();
-        l->compositionType = HWC_FRAMEBUFFER;
-        l->hints = 0;
-        l->flags = HWC_SKIP_LAYER;
-        l->handle = 0;
-        l->transform = 0;
-        l->blending = HWC_BLENDING_NONE;
-        l->visibleRegionScreen.numRects = 0;
-        l->visibleRegionScreen.rects = NULL;
-        l->acquireFenceFd = -1;
-        l->releaseFenceFd = -1;
-        l->planeAlpha = 0xFF;
-    }
-    virtual void setSkip(bool skip) {
-        if (skip) {
-            getLayer()->flags |= HWC_SKIP_LAYER;
-        } else {
-            getLayer()->flags &= ~HWC_SKIP_LAYER;
-        }
-    }
-    virtual void setIsCursorLayerHint(bool isCursor) {
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
-            if (isCursor) {
-                getLayer()->flags |= HWC_IS_CURSOR_LAYER;
-            }
-            else {
-                getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
-            }
-        }
-    }
-    virtual void setBlending(uint32_t blending) {
-        getLayer()->blending = blending;
-    }
-    virtual void setTransform(uint32_t transform) {
-        getLayer()->transform = transform;
-    }
-    virtual void setFrame(const Rect& frame) {
-        getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame);
-    }
-    virtual void setCrop(const FloatRect& crop) {
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
-            getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop);
-        } else {
-            /*
-             * Since h/w composer didn't support a flot crop rect before version 1.3,
-             * using integer coordinates instead produces a different output from the GL code in
-             * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to
-             * window size ratio is large and a window crop is defined
-             * (i.e.: if we scale the buffer a lot and we also crop it with a window crop).
-             */
-            hwc_rect_t& r = getLayer()->sourceCrop;
-            r.left  = int(ceilf(crop.left));
-            r.top   = int(ceilf(crop.top));
-            r.right = int(floorf(crop.right));
-            r.bottom= int(floorf(crop.bottom));
-        }
-    }
-    virtual void setVisibleRegionScreen(const Region& reg) {
-        hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
-        mVisibleRegions->editItemAt(mIndex) = reg;
-        visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
-                mVisibleRegions->itemAt(mIndex).getArray(
-                &visibleRegion.numRects));
-    }
-    virtual void setSurfaceDamage(const Region& reg) {
-        if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
-            return;
-        }
-        hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
-        // We encode default full-screen damage as INVALID_RECT upstream, but as
-        // 0 rects for HWComposer
-        if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) {
-            surfaceDamage.numRects = 0;
-            surfaceDamage.rects = NULL;
-            return;
-        }
-        mSurfaceDamageRegions->editItemAt(mIndex) = reg;
-        surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
-                mSurfaceDamageRegions->itemAt(mIndex).getArray(
-                &surfaceDamage.numRects));
-    }
-    virtual void setSidebandStream(const sp<NativeHandle>& stream) {
-        ALOG_ASSERT(stream->handle() != NULL);
-        getLayer()->compositionType = HWC_SIDEBAND;
-        getLayer()->sidebandStream = stream->handle();
-    }
-    virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
-        if (buffer == 0 || buffer->handle == 0) {
-            getLayer()->compositionType = HWC_FRAMEBUFFER;
-            getLayer()->flags |= HWC_SKIP_LAYER;
-            getLayer()->handle = 0;
-        } else {
-            if (getLayer()->compositionType == HWC_SIDEBAND) {
-                // If this was a sideband layer but the stream was removed, reset
-                // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
-                getLayer()->compositionType = HWC_FRAMEBUFFER;
-            }
-            getLayer()->handle = buffer->handle;
-        }
-    }
-    virtual void onDisplayed() {
-        getLayer()->acquireFenceFd = -1;
-    }
-
-protected:
-    // Pointers to the vectors of Region backing-memory held in DisplayData.
-    // Only the Region at mIndex corresponds to this Layer.
-    Vector<Region>* mVisibleRegions;
-    Vector<Region>* mSurfaceDamageRegions;
-};
-
-/*
- * returns an iterator initialized at a given index in the layer list
- */
-HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return LayerListIterator();
-    }
-    DisplayData& disp(mDisplayData[id]);
-    if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
-        return LayerListIterator();
-    }
-    if (disp.visibleRegions.size() < disp.list->numHwLayers) {
-        disp.visibleRegions.resize(disp.list->numHwLayers);
-    }
-    if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) {
-        disp.surfaceDamageRegions.resize(disp.list->numHwLayers);
-    }
-    return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers,
-            &disp.visibleRegions, &disp.surfaceDamageRegions), index);
-}
-
-/*
- * returns an iterator on the beginning of the layer list
- */
-HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
-    return getLayerIterator(id, 0);
-}
-
-/*
- * returns an iterator on the end of the layer list
- */
-HWComposer::LayerListIterator HWComposer::end(int32_t id) {
-    size_t numLayers = 0;
-    if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
-        const DisplayData& disp(mDisplayData[id]);
-        if (mHwc && disp.list) {
-            numLayers = disp.list->numHwLayers;
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-                // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
-                // which we ignore when iterating through the layer list.
-                ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
-                if (numLayers) {
-                    numLayers--;
-                }
-            }
-        }
-    }
-    return getLayerIterator(id, numLayers);
-}
-
-// Converts a PixelFormat to a human-readable string.  Max 11 chars.
-// (Could use a table of prefab String8 objects.)
-static String8 getFormatStr(PixelFormat format) {
-    switch (format) {
-    case PIXEL_FORMAT_RGBA_8888:    return String8("RGBA_8888");
-    case PIXEL_FORMAT_RGBX_8888:    return String8("RGBx_8888");
-    case PIXEL_FORMAT_RGBA_FP16:    return String8("RGBA_FP16");
-    case PIXEL_FORMAT_RGBA_1010102: return String8("RGBA_1010102");
-    case PIXEL_FORMAT_RGB_888:      return String8("RGB_888");
-    case PIXEL_FORMAT_RGB_565:      return String8("RGB_565");
-    case PIXEL_FORMAT_BGRA_8888:    return String8("BGRA_8888");
-    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-                                    return String8("ImplDef");
-    default:
-        String8 result;
-        result.appendFormat("? %08x", format);
-        return result;
-    }
-}
-
-void HWComposer::dump(String8& result) const {
-    Mutex::Autolock _l(mDisplayLock);
-    if (mHwc) {
-        result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
-        result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
-        for (size_t i=0 ; i<mNumDisplays ; i++) {
-            const DisplayData& disp(mDisplayData[i]);
-            if (!disp.connected)
-                continue;
-
-            const Vector< sp<Layer> >& visibleLayersSortedByZ =
-                    mFlinger->getLayerSortedByZForHwcDisplay(i);
-
-
-            result.appendFormat("  Display[%zd] configurations (* current):\n", i);
-            for (size_t c = 0; c < disp.configs.size(); ++c) {
-                const DisplayConfig& config(disp.configs[c]);
-                result.appendFormat("    %s%zd: %ux%u, xdpi=%f, ydpi=%f"
-                        ", refresh=%" PRId64 ", colorMode=%d\n",
-                        c == disp.currentConfig ? "* " : "", c,
-                        config.width, config.height, config.xdpi, config.ydpi,
-                        config.refresh, config.colorMode);
-            }
-
-            if (disp.list) {
-                result.appendFormat(
-                        "  numHwLayers=%zu, flags=%08x\n",
-                        disp.list->numHwLayers, disp.list->flags);
-
-                result.append(
-                        "    type   |  handle  | hint | flag | tr | blnd |   format    |     source crop (l,t,r,b)      |          frame         | name \n"
-                        "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n");
-                //      " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___...
-                for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
-                    const hwc_layer_1_t&l = disp.list->hwLayers[i];
-                    int32_t format = -1;
-                    String8 name("unknown");
-
-                    if (i < visibleLayersSortedByZ.size()) {
-                        const sp<Layer>& layer(visibleLayersSortedByZ[i]);
-                        const sp<GraphicBuffer>& buffer(
-                                layer->getActiveBuffer());
-                        if (buffer != NULL) {
-                            format = buffer->getPixelFormat();
-                        }
-                        name = layer->getName();
-                    }
-
-                    int type = l.compositionType;
-                    if (type == HWC_FRAMEBUFFER_TARGET) {
-                        name = "HWC_FRAMEBUFFER_TARGET";
-                        format = disp.format;
-                    }
-
-                    static char const* compositionTypeName[] = {
-                            "GLES",
-                            "HWC",
-                            "BKGND",
-                            "FB TARGET",
-                            "SIDEBAND",
-                            "HWC_CURSOR",
-                            "UNKNOWN"};
-                    if (type >= NELEM(compositionTypeName))
-                        type = NELEM(compositionTypeName) - 1;
-
-                    String8 formatStr = getFormatStr(format);
-                    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
-                        result.appendFormat(
-                                " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n",
-                                        compositionTypeName[type],
-                                        intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
-                                        l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
-                                        l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
-                                        name.string());
-                    } else {
-                        result.appendFormat(
-                                " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n",
-                                        compositionTypeName[type],
-                                        intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
-                                        l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
-                                        l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
-                                        name.string());
-                    }
-                }
-            }
-        }
-    }
-
-    if (mHwc && mHwc->dump) {
-        const size_t SIZE = 4096;
-        char buffer[SIZE];
-        mHwc->dump(mHwc, buffer, SIZE);
-        result.append(buffer);
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
-    : mHwc(hwc), mEnabled(false),
-      mNextFakeVSync(0),
-      mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
-{
-}
-
-void HWComposer::VSyncThread::setEnabled(bool enabled) {
-    Mutex::Autolock _l(mLock);
-    if (mEnabled != enabled) {
-        mEnabled = enabled;
-        mCondition.signal();
-    }
-}
-
-void HWComposer::VSyncThread::onFirstRef() {
-    run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
-bool HWComposer::VSyncThread::threadLoop() {
-    { // scope for lock
-        Mutex::Autolock _l(mLock);
-        while (!mEnabled) {
-            mCondition.wait(mLock);
-        }
-    }
-
-    const nsecs_t period = mRefreshPeriod;
-    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    nsecs_t next_vsync = mNextFakeVSync;
-    nsecs_t sleep = next_vsync - now;
-    if (sleep < 0) {
-        // we missed, find where the next vsync should be
-        sleep = (period - ((now - next_vsync) % period));
-        next_vsync = now + sleep;
-    }
-    mNextFakeVSync = next_vsync + period;
-
-    struct timespec spec;
-    spec.tv_sec  = next_vsync / 1000000000;
-    spec.tv_nsec = next_vsync % 1000000000;
-
-    int err;
-    do {
-        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
-    } while (err<0 && errno == EINTR);
-
-    if (err == 0) {
-        mHwc.mEventHandler.onVSyncReceived(&mHwc, 0, next_vsync);
-    }
-
-    return true;
-}
-
-HWComposer::DisplayData::DisplayData()
-:   configs(),
-    currentConfig(0),
-    format(HAL_PIXEL_FORMAT_RGBA_8888),
-    connected(false),
-    hasFbComp(false), hasOvComp(false),
-    capacity(0), list(NULL),
-    framebufferTarget(NULL), fbTargetHandle(0),
-    lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE),
-    outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE),
-    events(0)
-{}
-
-HWComposer::DisplayData::~DisplayData() {
-    free(list);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index 4bc63bb..fe7944f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -190,7 +190,7 @@
         virtual status_t setLayer(size_t index) = 0;
         virtual HWCLayer* dup() = 0;
         static HWCLayer* copy(HWCLayer *rhs) {
-            return rhs ? rhs->dup() : NULL;
+            return rhs ? rhs->dup() : nullptr;
         }
     protected:
         virtual ~HWCLayer() { }
@@ -205,7 +205,7 @@
         HWCLayer* const mLayerList;
         size_t mIndex;
 
-        LayerListIterator() : mLayerList(NULL), mIndex(0) { }
+        LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
 
         LayerListIterator(HWCLayer* layer, size_t index)
             : mLayerList(layer), mIndex(index) { }
@@ -371,8 +371,8 @@
     sp<SurfaceFlinger>              mFlinger;
     framebuffer_device_t*           mFbDev;
     struct hwc_composer_device_1*   mHwc;
-    // invariant: mLists[0] != NULL iff mHwc != NULL
-    // mLists[i>0] can be NULL. that display is to be ignored
+    // invariant: mLists[0] != nullptr iff mHwc != nullptr
+    // mLists[i>0] can be nullptr. that display is to be ignored
     struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
     DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
     // protect mDisplayData from races between prepare and dump
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
new file mode 100644
index 0000000..12bbae2
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "PowerAdvisor"
+
+#include <cinttypes>
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+
+#include "PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace impl {
+
+namespace V1_0 = android::hardware::power::V1_0;
+using V1_3::PowerHint;
+
+PowerAdvisor::~PowerAdvisor() = default;
+
+PowerAdvisor::PowerAdvisor() = default;
+
+void PowerAdvisor::setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) {
+    if (expected) {
+        mExpensiveDisplays.insert(displayId);
+    } else {
+        mExpensiveDisplays.erase(displayId);
+    }
+
+    const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
+    if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
+        const sp<V1_3::IPower> powerHal = getPowerHal();
+        if (powerHal == nullptr) {
+            return;
+        }
+        auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING,
+                                                expectsExpensiveRendering);
+        // If Power HAL 1.3 was available previously but now fails,
+        // it may restart, so attempt to reconnect next time
+        if (!ret.isOk()) {
+            mReconnectPowerHal = true;
+            return;
+        }
+        mNotifiedExpensiveRendering = expectsExpensiveRendering;
+    }
+}
+
+sp<V1_3::IPower> PowerAdvisor::getPowerHal() {
+    static sp<V1_3::IPower> sPowerHal_1_3 = nullptr;
+    static bool sHasPowerHal_1_3 = true;
+
+    if (mReconnectPowerHal) {
+        sPowerHal_1_3 = nullptr;
+        mReconnectPowerHal = false;
+    }
+
+    // Power HAL 1.3 is not guaranteed to be available, thus we need to query
+    // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
+    // Power HAL 1.0 is always available, thus if we fail to query it, it means
+    // Power HAL is not available temporarily and we should retry later. However,
+    // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
+    // it means Power HAL 1.3 is not available at all, so we should stop trying.
+    if (sHasPowerHal_1_3 && sPowerHal_1_3 == nullptr) {
+        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
+        if (powerHal_1_0 != nullptr) {
+            // Try to cast to Power HAL 1.3
+            sPowerHal_1_3 =  V1_3::IPower::castFrom(powerHal_1_0);
+            if (sPowerHal_1_3 == nullptr) {
+                ALOGW("No Power HAL 1.3 service in system");
+                sHasPowerHal_1_3 = false;
+            } else {
+                ALOGI("Loaded Power HAL 1.3 service");
+            }
+        }
+    }
+    return sPowerHal_1_3;
+}
+
+} // namespace impl
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
new file mode 100644
index 0000000..573a1a9
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include <android/hardware/power/1.3/IPower.h>
+#include <utils/StrongPointer.h>
+
+#include <unordered_set>
+
+namespace android {
+namespace Hwc2 {
+
+class PowerAdvisor {
+public:
+    virtual ~PowerAdvisor();
+
+    virtual void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) = 0;
+};
+
+namespace impl {
+
+namespace V1_3 = android::hardware::power::V1_3;
+
+// PowerAdvisor is a wrapper around IPower HAL which takes into account the
+// full state of the system when sending out power hints to things like the GPU.
+class PowerAdvisor final : public Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) override;
+
+private:
+    sp<V1_3::IPower> getPowerHal();
+
+    std::unordered_set<hwc2_display_t> mExpensiveDisplays;
+    bool mNotifiedExpensiveRendering = false;
+    bool mReconnectPowerHal = false;
+};
+
+} // namespace impl
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
deleted file mode 100644
index a6f076e..0000000
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/power/1.0/IPower.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <utils/Errors.h>
-
-#include <binder/IServiceManager.h>
-#include <powermanager/IPowerManager.h>
-#include <powermanager/PowerManager.h>
-
-#include "PowerHAL.h"
-
-using android::hardware::power::V1_0::PowerHint;
-namespace android {
-// ---------------------------------------------------------------------------
-
-status_t PowerHAL::vsyncHint(bool enabled) {
-    Mutex::Autolock _l(mlock);
-    if (mPowerManager == NULL) {
-        const String16 serviceName("power");
-        sp<IBinder> bs = defaultServiceManager()->checkService(serviceName);
-        if (bs == NULL) {
-            return NAME_NOT_FOUND;
-        }
-        mPowerManager = interface_cast<IPowerManager>(bs);
-    }
-    status_t status;
-    status = mPowerManager->powerHint(static_cast<int>(PowerHint::VSYNC),
-            enabled ? 1 : 0);
-    if(status == DEAD_OBJECT) {
-        mPowerManager = NULL;
-    }
-    return status;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.h b/services/surfaceflinger/DisplayHardware/PowerHAL.h
deleted file mode 100644
index e5f82a9..0000000
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 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 ANDROID_SF_POWER_HAL_H
-#define ANDROID_SF_POWER_HAL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Mutex.h>
-
-#include <powermanager/IPowerManager.h>
-#include <hardware/power.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class PowerHAL
-{
-public:
-    status_t vsyncHint(bool enabled);
-
-private:
-    sp<IPowerManager> mPowerManager;
-    Mutex mlock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_POWER_HAL_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1de5e48..9a2817d 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -108,7 +108,7 @@
     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
     sink->setAsyncMode(true);
     IGraphicBufferProducer::QueueBufferOutput output;
-    mSource[SOURCE_SCRATCH]->connect(NULL, NATIVE_WINDOW_API_EGL, false, &output);
+    mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
 }
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
@@ -176,12 +176,6 @@
     return NO_ERROR;
 }
 
-#ifndef USE_HWC2
-status_t VirtualDisplaySurface::compositionComplete() {
-    return NO_ERROR;
-}
-#endif
-
 status_t VirtualDisplaySurface::advanceFrame() {
     if (mDisplayId < 0)
         return NO_ERROR;
@@ -209,7 +203,7 @@
     }
 
     sp<GraphicBuffer> fbBuffer = mFbProducerSlot >= 0 ?
-            mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(NULL);
+            mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(nullptr);
     sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
     VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
             mFbProducerSlot, fbBuffer.get(),
@@ -220,8 +214,7 @@
     mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
 
     status_t result = NO_ERROR;
-    if (fbBuffer != NULL) {
-#ifdef USE_HWC2
+    if (fbBuffer != nullptr) {
         uint32_t hwcSlot = 0;
         sp<GraphicBuffer> hwcBuffer;
         mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
@@ -229,10 +222,7 @@
 
         // TODO: Correctly propagate the dataspace from GL composition
         result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
-                hwcBuffer, HAL_DATASPACE_UNKNOWN);
-#else
-        result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
-#endif
+                hwcBuffer, ui::Dataspace::UNKNOWN);
     }
 
     return result;
@@ -246,32 +236,20 @@
             "Unexpected onFrameCommitted() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_IDLE;
 
-#ifdef USE_HWC2
     sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId);
-#else
-    sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
-#endif
     if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
         // release the scratch buffer back to the pool
         Mutex::Autolock lock(mMutex);
         int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
         VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
-#ifdef USE_HWC2
         addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
                 retireFence);
-#else
-        addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
-#endif
-        releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+        releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]);
     }
 
     if (mOutputProducerSlot >= 0) {
         int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
         QueueBufferOutput qbo;
-#ifndef USE_HWC2
-        sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
-#endif
         VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
         if (mMustRecompose) {
             status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
@@ -280,11 +258,7 @@
                         HAL_DATASPACE_UNKNOWN,
                         Rect(mSinkBufferWidth, mSinkBufferHeight),
                         NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
-#ifdef USE_HWC2
                         retireFence),
-#else
-                        outFence),
-#endif
                     &qbo);
             if (result == NO_ERROR) {
                 updateQueueBufferOutput(std::move(qbo));
@@ -294,11 +268,7 @@
             // through the motions of updating the display to keep our state
             // machine happy. We cancel the buffer to avoid triggering another
             // re-composition and causing an infinite loop.
-#ifdef USE_HWC2
             mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence);
-#else
-            mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
-#endif
         }
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 1671aba..5c8acea 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -84,9 +84,6 @@
     //
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
-#ifndef USE_HWC2
-    virtual status_t compositionComplete();
-#endif
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
@@ -253,10 +250,7 @@
 
     bool mMustRecompose;
 
-#ifdef USE_HWC2
     HWComposerBufferCache mHwcBufferCache;
-#endif
-
 
     bool mForceHwcCopy;
 };
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index c953c68..01c9c0f 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -133,8 +133,6 @@
                         0.7, 0.7, 1.0, 0,
                           0,   0,   0, 1);
 
-    const mat4 identity;
-
     // And the magic happens here...
     // We construct the matrix that will perform the whole correction.
 
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index 052a959..fb6cff5 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -14,55 +14,62 @@
  * limitations under the License.
  */
 
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <cutils/sched_policy.h>
+#include <log/log.h>
+#include <system/thread_defs.h>
+
 #include "EventControlThread.h"
-#include "SurfaceFlinger.h"
 
 namespace android {
 
-EventControlThread::EventControlThread(const sp<SurfaceFlinger>& flinger):
-        mFlinger(flinger),
-        mVsyncEnabled(false) {
+EventControlThread::~EventControlThread() = default;
+
+namespace impl {
+
+EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
+      : mSetVSyncEnabled(function) {
+    pthread_setname_np(mThread.native_handle(), "EventControlThread");
+
+    pid_t tid = pthread_gettid_np(mThread.native_handle());
+    setpriority(PRIO_PROCESS, tid, ANDROID_PRIORITY_URGENT_DISPLAY);
+    set_sched_policy(tid, SP_FOREGROUND);
+}
+
+EventControlThread::~EventControlThread() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mKeepRunning = false;
+        mCondition.notify_all();
+    }
+    mThread.join();
 }
 
 void EventControlThread::setVsyncEnabled(bool enabled) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVsyncEnabled = enabled;
-    mCond.signal();
+    mCondition.notify_all();
 }
 
-bool EventControlThread::threadLoop() {
-    enum class VsyncState {Unset, On, Off};
-    auto currentVsyncState = VsyncState::Unset;
+// Unfortunately std::unique_lock gives warnings with -Wthread-safety
+void EventControlThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+    auto keepRunning = true;
+    auto currentVsyncEnabled = false;
 
-    while (true) {
-        auto requestedVsyncState = VsyncState::On;
-        {
-            Mutex::Autolock lock(mMutex);
-            requestedVsyncState =
-                    mVsyncEnabled ? VsyncState::On : VsyncState::Off;
-            while (currentVsyncState == requestedVsyncState) {
-                status_t err = mCond.wait(mMutex);
-                if (err != NO_ERROR) {
-                    ALOGE("error waiting for new events: %s (%d)",
-                          strerror(-err), err);
-                    return false;
-                }
-                requestedVsyncState =
-                        mVsyncEnabled ? VsyncState::On : VsyncState::Off;
-            }
-        }
+    while (keepRunning) {
+        mSetVSyncEnabled(currentVsyncEnabled);
 
-        bool enable = requestedVsyncState == VsyncState::On;
-#ifdef USE_HWC2
-        mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, enable);
-#else
-        mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
-                SurfaceFlinger::EVENT_VSYNC, enable);
-#endif
-        currentVsyncState = requestedVsyncState;
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondition.wait(lock, [this, currentVsyncEnabled, keepRunning]() NO_THREAD_SAFETY_ANALYSIS {
+            return currentVsyncEnabled != mVsyncEnabled || keepRunning != mKeepRunning;
+        });
+        currentVsyncEnabled = mVsyncEnabled;
+        keepRunning = mKeepRunning;
     }
-
-    return false;
 }
 
+} // namespace impl
 } // namespace android
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index 1b1ef75..cafae53 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -14,35 +14,50 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EVENTCONTROLTHREAD_H
-#define ANDROID_EVENTCONTROLTHREAD_H
+#pragma once
 
-#include <stddef.h>
+#include <condition_variable>
+#include <cstddef>
+#include <functional>
+#include <mutex>
+#include <thread>
 
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
+#include <android-base/thread_annotations.h>
 
 namespace android {
 
-class SurfaceFlinger;
-
-class EventControlThread: public Thread {
+class EventControlThread {
 public:
+    virtual ~EventControlThread();
 
-    explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
-    virtual ~EventControlThread() {}
-
-    void setVsyncEnabled(bool enabled);
-    virtual bool threadLoop();
-
-private:
-    sp<SurfaceFlinger> mFlinger;
-    bool mVsyncEnabled;
-
-    Mutex mMutex;
-    Condition mCond;
+    virtual void setVsyncEnabled(bool enabled) = 0;
 };
 
-}
+namespace impl {
 
-#endif // ANDROID_EVENTCONTROLTHREAD_H
+class EventControlThread final : public android::EventControlThread {
+public:
+    using SetVSyncEnabledFunction = std::function<void(bool)>;
+
+    explicit EventControlThread(SetVSyncEnabledFunction function);
+    ~EventControlThread();
+
+    // EventControlThread implementation
+    void setVsyncEnabled(bool enabled) override;
+
+private:
+    void threadMain();
+
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+
+    const SetVSyncEnabledFunction mSetVSyncEnabled;
+    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+    bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+    // Must be last so that everything is initialized before the thread starts.
+    std::thread mThread{&EventControlThread::threadMain, this};
+};
+
+} // namespace impl
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index a9bb2ba..bc271c8 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -16,12 +16,15 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
 #include <sys/types.h>
+#include <chrono>
+#include <cstdint>
 
 #include <cutils/compiler.h>
+#include <cutils/sched_policy.h>
 
-#include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
 
 #include <utils/Errors.h>
@@ -29,145 +32,134 @@
 #include <utils/Trace.h>
 
 #include "EventThread.h"
-#include "SurfaceFlinger.h"
+
+using namespace std::chrono_literals;
 
 // ---------------------------------------------------------------------------
+
 namespace android {
+
 // ---------------------------------------------------------------------------
-// time to wait between VSYNC requests before sending a VSYNC OFF power hint: 40msec.
-const long vsyncHintOffDelay = 40000000;
 
-static void vsyncOffCallback(union sigval val) {
-    EventThread *ev = (EventThread *)val.sival_ptr;
-    ev->sendVsyncHintOff();
-    return;
-}
+EventThread::~EventThread() = default;
 
-EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs)
-    : mVSyncSource(src),
-      mFlinger(flinger),
-      mUseSoftwareVSync(false),
-      mVsyncEnabled(false),
-      mDebugVsyncEnabled(false),
-      mVsyncHintSent(false),
-      mInterceptVSyncs(interceptVSyncs) {
+namespace impl {
 
-    for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
-        mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-        mVSyncEvent[i].header.id = 0;
-        mVSyncEvent[i].header.timestamp = 0;
-        mVSyncEvent[i].vsync.count =  0;
+EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+      : mVSyncSource(src),
+        mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
+        mInterceptVSyncsCallback(interceptVSyncsCallback) {
+    for (auto& event : mVSyncEvent) {
+        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        event.header.id = 0;
+        event.header.timestamp = 0;
+        event.vsync.count = 0;
     }
-    struct sigevent se;
-    se.sigev_notify = SIGEV_THREAD;
-    se.sigev_value.sival_ptr = this;
-    se.sigev_notify_function = vsyncOffCallback;
-    se.sigev_notify_attributes = NULL;
-    timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
+
+    mThread = std::thread(&EventThread::threadMain, this);
+
+    pthread_setname_np(mThread.native_handle(), threadName);
+
+    pid_t tid = pthread_gettid_np(mThread.native_handle());
+
+    // Use SCHED_FIFO to minimize jitter
+    constexpr int EVENT_THREAD_PRIORITY = 2;
+    struct sched_param param = {0};
+    param.sched_priority = EVENT_THREAD_PRIORITY;
+    if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for EventThread");
+    }
+
+    set_sched_policy(tid, SP_FOREGROUND);
 }
 
-void EventThread::sendVsyncHintOff() {
-    Mutex::Autolock _l(mLock);
-    mPowerHAL.vsyncHint(false);
-    mVsyncHintSent = false;
+EventThread::~EventThread() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mKeepRunning = false;
+        mCondition.notify_all();
+    }
+    mThread.join();
 }
 
 void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-void EventThread::sendVsyncHintOnLocked() {
-    struct itimerspec ts;
-    if(!mVsyncHintSent) {
-        mPowerHAL.vsyncHint(true);
-        mVsyncHintSent = true;
-    }
-    ts.it_value.tv_sec = 0;
-    ts.it_value.tv_nsec = vsyncHintOffDelay;
-    ts.it_interval.tv_sec = 0;
-    ts.it_interval.tv_nsec = 0;
-    timer_settime(mTimerId, 0, &ts, NULL);
-}
-
-void EventThread::onFirstRef() {
-    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
-sp<EventThread::Connection> EventThread::createEventConnection() const {
+sp<BnDisplayEventConnection> EventThread::createEventConnection() const {
     return new Connection(const_cast<EventThread*>(this));
 }
 
 status_t EventThread::registerDisplayEventConnection(
         const sp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mDisplayEventConnections.add(connection);
-    mCondition.broadcast();
+    mCondition.notify_all();
     return NO_ERROR;
 }
 
-void EventThread::removeDisplayEventConnection(
-        const wp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+void EventThread::removeDisplayEventConnectionLocked(const wp<EventThread::Connection>& connection) {
     mDisplayEventConnections.remove(connection);
 }
 
-void EventThread::setVsyncRate(uint32_t count,
-        const sp<EventThread::Connection>& connection) {
+void EventThread::setVsyncRate(uint32_t count, const sp<EventThread::Connection>& connection) {
     if (int32_t(count) >= 0) { // server must protect against bad params
-        Mutex::Autolock _l(mLock);
+        std::lock_guard<std::mutex> lock(mMutex);
         const int32_t new_count = (count == 0) ? -1 : count;
         if (connection->count != new_count) {
             connection->count = new_count;
-            mCondition.broadcast();
+            mCondition.notify_all();
         }
     }
 }
 
-void EventThread::requestNextVsync(
-        const sp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
+void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
+    std::lock_guard<std::mutex> lock(mMutex);
 
-    mFlinger.resyncWithRateLimit();
+    if (mResyncWithRateLimitCallback) {
+        mResyncWithRateLimitCallback();
+    }
 
     if (connection->count < 0) {
         connection->count = 0;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onScreenReleased() {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (!mUseSoftwareVSync) {
         // disable reliance on h/w vsync
         mUseSoftwareVSync = true;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onScreenAcquired() {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (mUseSoftwareVSync) {
         // resume use of h/w vsync
         mUseSoftwareVSync = false;
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
 void EventThread::onVSyncEvent(nsecs_t timestamp) {
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     mVSyncEvent[0].header.id = 0;
     mVSyncEvent[0].header.timestamp = timestamp;
     mVSyncEvent[0].vsync.count++;
-    mCondition.broadcast();
+    mCondition.notify_all();
 }
 
 void EventThread::onHotplugReceived(int type, bool connected) {
     ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-            "received hotplug event for an invalid display (id=%d)", type);
+             "received hotplug event for an invalid display (id=%d)", type);
 
-    Mutex::Autolock _l(mLock);
+    std::lock_guard<std::mutex> lock(mMutex);
     if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
         DisplayEventReceiver::Event event;
         event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
@@ -175,59 +167,59 @@
         event.header.timestamp = systemTime();
         event.hotplug.connected = connected;
         mPendingEvents.add(event);
-        mCondition.broadcast();
+        mCondition.notify_all();
     }
 }
 
-bool EventThread::threadLoop() {
-    DisplayEventReceiver::Event event;
-    Vector< sp<EventThread::Connection> > signalConnections;
-    signalConnections = waitForEvent(&event);
+void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
+    std::unique_lock<std::mutex> lock(mMutex);
+    while (mKeepRunning) {
+        DisplayEventReceiver::Event event;
+        Vector<sp<EventThread::Connection> > signalConnections;
+        signalConnections = waitForEventLocked(&lock, &event);
 
-    // dispatch events to listeners...
-    const size_t count = signalConnections.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const sp<Connection>& conn(signalConnections[i]);
-        // now see if we still need to report this event
-        status_t err = conn->postEvent(event);
-        if (err == -EAGAIN || err == -EWOULDBLOCK) {
-            // The destination doesn't accept events anymore, it's probably
-            // full. For now, we just drop the events on the floor.
-            // FIXME: Note that some events cannot be dropped and would have
-            // to be re-sent later.
-            // Right-now we don't have the ability to do this.
-            ALOGW("EventThread: dropping event (%08x) for connection %p",
-                    event.header.type, conn.get());
-        } else if (err < 0) {
-            // handle any other error on the pipe as fatal. the only
-            // reasonable thing to do is to clean-up this connection.
-            // The most common error we'll get here is -EPIPE.
-            removeDisplayEventConnection(signalConnections[i]);
+        // dispatch events to listeners...
+        const size_t count = signalConnections.size();
+        for (size_t i = 0; i < count; i++) {
+            const sp<Connection>& conn(signalConnections[i]);
+            // now see if we still need to report this event
+            status_t err = conn->postEvent(event);
+            if (err == -EAGAIN || err == -EWOULDBLOCK) {
+                // The destination doesn't accept events anymore, it's probably
+                // full. For now, we just drop the events on the floor.
+                // FIXME: Note that some events cannot be dropped and would have
+                // to be re-sent later.
+                // Right-now we don't have the ability to do this.
+                ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
+                      conn.get());
+            } else if (err < 0) {
+                // handle any other error on the pipe as fatal. the only
+                // reasonable thing to do is to clean-up this connection.
+                // The most common error we'll get here is -EPIPE.
+                removeDisplayEventConnectionLocked(signalConnections[i]);
+            }
         }
     }
-    return true;
 }
 
 // This will return when (1) a vsync event has been received, and (2) there was
 // at least one connection interested in receiving it when we started waiting.
-Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
-        DisplayEventReceiver::Event* event)
-{
-    Mutex::Autolock _l(mLock);
-    Vector< sp<EventThread::Connection> > signalConnections;
+Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
+        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+    Vector<sp<EventThread::Connection> > signalConnections;
 
-    do {
+    while (signalConnections.isEmpty() && mKeepRunning) {
         bool eventPending = false;
         bool waitForVSync = false;
 
         size_t vsyncCount = 0;
         nsecs_t timestamp = 0;
-        for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+        for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
             timestamp = mVSyncEvent[i].header.timestamp;
             if (timestamp) {
                 // we have a vsync event to dispatch
-                if (mInterceptVSyncs) {
-                    mFlinger.mInterceptor.saveVSyncEvent(timestamp);
+                if (mInterceptVSyncsCallback) {
+                    mInterceptVSyncsCallback(timestamp);
                 }
                 *event = mVSyncEvent[i];
                 mVSyncEvent[i].header.timestamp = 0;
@@ -248,9 +240,9 @@
 
         // find out connections waiting for events
         size_t count = mDisplayEventConnections.size();
-        for (size_t i=0 ; i<count ; i++) {
+        for (size_t i = 0; i < count;) {
             sp<Connection> connection(mDisplayEventConnections[i].promote());
-            if (connection != NULL) {
+            if (connection != nullptr) {
                 bool added = false;
                 if (connection->count >= 0) {
                     // we need vsync events because at least
@@ -265,7 +257,7 @@
                             signalConnections.add(connection);
                             added = true;
                         } else if (connection->count == 1 ||
-                                (vsyncCount % connection->count) == 0) {
+                                   (vsyncCount % connection->count) == 0) {
                             // continuous event, and time to report it
                             signalConnections.add(connection);
                             added = true;
@@ -279,11 +271,12 @@
                     // messages.
                     signalConnections.add(connection);
                 }
+                ++i;
             } else {
                 // we couldn't promote this reference, the connection has
                 // died, so clean-up!
                 mDisplayEventConnections.removeAt(i);
-                --i; --count;
+                --count;
             }
         }
 
@@ -318,8 +311,8 @@
                 // use a (long) timeout when waiting for h/w vsync, and
                 // generate fake events when necessary.
                 bool softwareSync = mUseSoftwareVSync;
-                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
-                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
+                auto timeout = softwareSync ? 16ms : 1000ms;
+                if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
                     if (!softwareSync) {
                         ALOGW("Timed out waiting for hw vsync; faking it");
                     }
@@ -335,10 +328,10 @@
                 // h/w vsync should be disabled, so this will wait until we
                 // get a new connection, or an existing connection becomes
                 // interested in receiving vsync again.
-                mCondition.wait(mLock);
+                mCondition.wait(*lock);
             }
         }
-    } while (signalConnections.isEmpty());
+    }
 
     // here we're guaranteed to have a timestamp and some connections to signal
     // (The connections might have dropped out of mDisplayEventConnections
@@ -351,12 +344,11 @@
         // never enable h/w VSYNC when screen is off
         if (!mVsyncEnabled) {
             mVsyncEnabled = true;
-            mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
+            mVSyncSource->setCallback(this);
             mVSyncSource->setVSyncEnabled(true);
         }
     }
     mDebugVsyncEnabled = true;
-    sendVsyncHintOnLocked();
 }
 
 void EventThread::disableVSyncLocked() {
@@ -368,29 +360,23 @@
 }
 
 void EventThread::dump(String8& result) const {
-    Mutex::Autolock _l(mLock);
-    result.appendFormat("VSYNC state: %s\n",
-            mDebugVsyncEnabled?"enabled":"disabled");
-    result.appendFormat("  soft-vsync: %s\n",
-            mUseSoftwareVSync?"enabled":"disabled");
+    std::lock_guard<std::mutex> lock(mMutex);
+    result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
+    result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
     result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
-            mDisplayEventConnections.size(),
-            mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
-    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
-        sp<Connection> connection =
-                mDisplayEventConnections.itemAt(i).promote();
-        result.appendFormat("    %p: count=%d\n",
-                connection.get(), connection!=NULL ? connection->count : 0);
+                        mDisplayEventConnections.size(),
+                        mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+    for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
+        sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
+        result.appendFormat("    %p: count=%d\n", connection.get(),
+                            connection != nullptr ? connection->count : 0);
     }
 }
 
 // ---------------------------------------------------------------------------
 
-EventThread::Connection::Connection(
-        const sp<EventThread>& eventThread)
-    : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize)
-{
-}
+EventThread::Connection::Connection(EventThread* eventThread)
+      : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
 
 EventThread::Connection::~Connection() {
     // do nothing here -- clean-up will happen automatically
@@ -416,12 +402,12 @@
     mEventThread->requestNextVsync(this);
 }
 
-status_t EventThread::Connection::postEvent(
-        const DisplayEventReceiver::Event& event) {
+status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {
     ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace impl
+} // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 6a59fbb..9c13ed2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -14,36 +14,38 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
-#define ANDROID_SURFACE_FLINGER_EVENT_THREAD_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
 
-#include <private/gui/BitTube.h>
+#include <android-base/thread_annotations.h>
+
 #include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
 
 #include <utils/Errors.h>
-#include <utils/threads.h>
 #include <utils/SortedVector.h>
 
 #include "DisplayDevice.h"
-#include "DisplayHardware/PowerHAL.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
 
+class EventThreadTest;
 class SurfaceFlinger;
 class String8;
 
 // ---------------------------------------------------------------------------
 
-
-class VSyncSource : public virtual RefBase {
+class VSyncSource {
 public:
-    class Callback: public virtual RefBase {
+    class Callback {
     public:
         virtual ~Callback() {}
         virtual void onVSyncEvent(nsecs_t when) = 0;
@@ -51,15 +53,39 @@
 
     virtual ~VSyncSource() {}
     virtual void setVSyncEnabled(bool enable) = 0;
-    virtual void setCallback(const sp<Callback>& callback) = 0;
+    virtual void setCallback(Callback* callback) = 0;
     virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
 };
 
-class EventThread : public Thread, private VSyncSource::Callback {
+class EventThread {
+public:
+    virtual ~EventThread();
+
+    virtual sp<BnDisplayEventConnection> createEventConnection() const = 0;
+
+    // called before the screen is turned off from main thread
+    virtual void onScreenReleased() = 0;
+
+    // called after the screen is turned on from main thread
+    virtual void onScreenAcquired() = 0;
+
+    // called when receiving a hotplug event
+    virtual void onHotplugReceived(int type, bool connected) = 0;
+
+    virtual void dump(String8& result) const = 0;
+
+    virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+};
+
+namespace impl {
+
+class EventThread : public android::EventThread, private VSyncSource::Callback {
     class Connection : public BnDisplayEventConnection {
     public:
-        explicit Connection(const sp<EventThread>& eventThread);
-        status_t postEvent(const DisplayEventReceiver::Event& event);
+        explicit Connection(EventThread* eventThread);
+        virtual ~Connection();
+
+        virtual status_t postEvent(const DisplayEventReceiver::Event& event);
 
         // count >= 1 : continuous event. count is the vsync rate
         // count == 0 : one-shot event that has not fired
@@ -67,80 +93,79 @@
         int32_t count;
 
     private:
-        virtual ~Connection();
         virtual void onFirstRef();
         status_t stealReceiveChannel(gui::BitTube* outChannel) override;
         status_t setVsyncRate(uint32_t count) override;
-        void requestNextVsync() override;    // asynchronous
-        sp<EventThread> const mEventThread;
+        void requestNextVsync() override; // asynchronous
+        EventThread* const mEventThread;
         gui::BitTube mChannel;
     };
 
 public:
+    using ResyncWithRateLimitCallback = std::function<void()>;
+    using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
 
-    EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs);
+    EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
+                InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+    ~EventThread();
 
-    sp<Connection> createEventConnection() const;
+    sp<BnDisplayEventConnection> createEventConnection() const override;
     status_t registerDisplayEventConnection(const sp<Connection>& connection);
 
     void setVsyncRate(uint32_t count, const sp<Connection>& connection);
     void requestNextVsync(const sp<Connection>& connection);
 
     // called before the screen is turned off from main thread
-    void onScreenReleased();
+    void onScreenReleased() override;
 
     // called after the screen is turned on from main thread
-    void onScreenAcquired();
+    void onScreenAcquired() override;
 
     // called when receiving a hotplug event
-    void onHotplugReceived(int type, bool connected);
+    void onHotplugReceived(int type, bool connected) override;
 
-    Vector< sp<EventThread::Connection> > waitForEvent(
-            DisplayEventReceiver::Event* event);
+    void dump(String8& result) const override;
 
-    void dump(String8& result) const;
-    void sendVsyncHintOff();
-
-    void setPhaseOffset(nsecs_t phaseOffset);
+    void setPhaseOffset(nsecs_t phaseOffset) override;
 
 private:
-    virtual bool        threadLoop();
-    virtual void        onFirstRef();
+    friend EventThreadTest;
 
-    virtual void onVSyncEvent(nsecs_t timestamp);
+    void threadMain();
+    Vector<sp<EventThread::Connection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
+                                                           DisplayEventReceiver::Event* event)
+            REQUIRES(mMutex);
 
-    void removeDisplayEventConnection(const wp<Connection>& connection);
-    void enableVSyncLocked();
-    void disableVSyncLocked();
-    void sendVsyncHintOnLocked();
+    void removeDisplayEventConnectionLocked(const wp<Connection>& connection) REQUIRES(mMutex);
+    void enableVSyncLocked() REQUIRES(mMutex);
+    void disableVSyncLocked() REQUIRES(mMutex);
+
+    // Implements VSyncSource::Callback
+    void onVSyncEvent(nsecs_t timestamp) override;
 
     // constants
-    sp<VSyncSource> mVSyncSource;
-    PowerHAL mPowerHAL;
-    SurfaceFlinger& mFlinger;
+    VSyncSource* const mVSyncSource GUARDED_BY(mMutex) = nullptr;
+    const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
+    const InterceptVSyncsCallback mInterceptVSyncsCallback;
 
-    mutable Mutex mLock;
-    mutable Condition mCondition;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
 
     // protected by mLock
-    SortedVector< wp<Connection> > mDisplayEventConnections;
-    Vector< DisplayEventReceiver::Event > mPendingEvents;
-    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
-    bool mUseSoftwareVSync;
-    bool mVsyncEnabled;
+    SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
+    Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
+            mMutex);
+    bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
+    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+    bool mKeepRunning GUARDED_BY(mMutex) = true;
 
     // for debugging
-    bool mDebugVsyncEnabled;
-
-    bool mVsyncHintSent;
-    const bool mInterceptVSyncs;
-    timer_t mTimerId;
+    bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
 };
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_EVENT_THREAD_H */
+} // namespace impl
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 99c4daa..1539873 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -82,17 +82,17 @@
     mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
     mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
 
-    if (mFrameRecords[mOffset].frameReadyFence != NULL) {
+    if (mFrameRecords[mOffset].frameReadyFence != nullptr) {
         // We're clobbering an unsignaled fence, so we need to decrement the
         // fence count.
-        mFrameRecords[mOffset].frameReadyFence = NULL;
+        mFrameRecords[mOffset].frameReadyFence = nullptr;
         mNumFences--;
     }
 
-    if (mFrameRecords[mOffset].actualPresentFence != NULL) {
+    if (mFrameRecords[mOffset].actualPresentFence != nullptr) {
         // We're clobbering an unsignaled fence, so we need to decrement the
         // fence count.
-        mFrameRecords[mOffset].actualPresentFence = NULL;
+        mFrameRecords[mOffset].actualPresentFence = nullptr;
         mNumFences--;
     }
 }
@@ -153,10 +153,10 @@
         bool updated = false;
 
         const std::shared_ptr<FenceTime>& rfence = records[idx].frameReadyFence;
-        if (rfence != NULL) {
+        if (rfence != nullptr) {
             records[idx].frameReadyTime = rfence->getSignalTime();
             if (records[idx].frameReadyTime < INT64_MAX) {
-                records[idx].frameReadyFence = NULL;
+                records[idx].frameReadyFence = nullptr;
                 numFences--;
                 updated = true;
             }
@@ -164,10 +164,10 @@
 
         const std::shared_ptr<FenceTime>& pfence =
                 records[idx].actualPresentFence;
-        if (pfence != NULL) {
+        if (pfence != nullptr) {
             records[idx].actualPresentTime = pfence->getSignalTime();
             if (records[idx].actualPresentTime < INT64_MAX) {
-                records[idx].actualPresentFence = NULL;
+                records[idx].actualPresentFence = nullptr;
                 numFences--;
                 updated = true;
             }
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index adcdfb5..b4a9fd6 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -35,7 +35,7 @@
 // possible.
 //
 // Some of the time values tracked may be set either as a specific timestamp
-// or a fence.  When a non-NULL fence is set for a given time value, the
+// or a fence.  When a non-nullptr fence is set for a given time value, the
 // signal time of that fence is used instead of the timestamp.
 class FrameTracker {
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100755
new mode 100644
index 038ece2..a14bb98
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -19,10 +19,11 @@
 #define LOG_TAG "Layer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
 #include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <algorithm>
 
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
@@ -39,40 +40,43 @@
 #include <ui/PixelFormat.h>
 
 #include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
-#include "clz.h"
+#include "BufferLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "Layer.h"
 #include "LayerRejecter.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
+#include "clz.h"
 
 #include "DisplayHardware/HWComposer.h"
 
 #include "RenderEngine/RenderEngine.h"
 
 #include <mutex>
+#include "LayerProtoHelper.h"
 
-#define DEBUG_RESIZE    0
+#define DEBUG_RESIZE 0
 
 namespace android {
 
-// ---------------------------------------------------------------------------
+LayerBE::LayerBE()
+      : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+}
+
 
 int32_t Layer::sSequence = 1;
 
-Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
-        const String8& name, uint32_t w, uint32_t h, uint32_t flags)
-    :   contentDirty(false),
+Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+             uint32_t h, uint32_t flags)
+      : contentDirty(false),
         sequence(uint32_t(android_atomic_inc(&sSequence))),
         mFlinger(flinger),
-        mTextureName(-1U),
         mPremultipliedAlpha(true),
-        mName("unnamed"),
-        mFormat(PIXEL_FORMAT_NONE),
+        mName(name),
         mTransactionFlags(0),
         mPendingStateMutex(),
         mPendingStates(),
@@ -80,114 +84,75 @@
         mSidebandStreamChanged(false),
         mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
         mCurrentTransform(0),
-        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mOverrideScalingMode(-1),
         mCurrentOpacity(true),
-        mBufferLatched(false),
         mCurrentFrameNumber(0),
-        mPreviousFrameNumber(0),
-        mRefreshPending(false),
         mFrameLatencyNeeded(false),
         mFiltering(false),
         mNeedsFiltering(false),
-        mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
-#ifndef USE_HWC2
-        mIsGlesComposition(false),
-#endif
         mProtectedByApp(false),
-        mHasSurface(false),
         mClientRef(client),
         mPotentialCursor(false),
         mQueueItemLock(),
         mQueueItemCondition(),
         mQueueItems(),
         mLastFrameNumberReceived(0),
-        mUpdateTexImageFailed(false),
         mAutoRefresh(false),
-        mFreezeGeometryUpdates(false)
-{
-#ifdef USE_HWC2
-    ALOGV("Creating Layer %s", name.string());
-#endif
-
+        mFreezeGeometryUpdates(false),
+        mCurrentChildren(LayerVector::StateSet::Current),
+        mDrawingChildren(LayerVector::StateSet::Drawing) {
     mCurrentCrop.makeInvalid();
-    mFlinger->getRenderEngine().genTextures(1, &mTextureName);
-    mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
 
     uint32_t layerFlags = 0;
-    if (flags & ISurfaceComposerClient::eHidden)
-        layerFlags |= layer_state_t::eLayerHidden;
-    if (flags & ISurfaceComposerClient::eOpaque)
-        layerFlags |= layer_state_t::eLayerOpaque;
-    if (flags & ISurfaceComposerClient::eSecure)
-        layerFlags |= layer_state_t::eLayerSecure;
-
-    if (flags & ISurfaceComposerClient::eNonPremultiplied)
-        mPremultipliedAlpha = false;
+    if (flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
+    if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
+    if (flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
 
     mName = name;
     mTransactionName = String8("TX - ") + mName;
 
     mCurrentState.active.w = w;
     mCurrentState.active.h = h;
+    mCurrentState.flags = layerFlags;
     mCurrentState.active.transform.set(0, 0);
     mCurrentState.crop.makeInvalid();
     mCurrentState.finalCrop.makeInvalid();
     mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
     mCurrentState.requestedCrop = mCurrentState.crop;
     mCurrentState.z = 0;
-#ifdef USE_HWC2
-    mCurrentState.alpha = 1.0f;
-#else
-    mCurrentState.alpha = 0xFF;
-#endif
+    mCurrentState.color.a = 1.0f;
     mCurrentState.layerStack = 0;
-    mCurrentState.flags = layerFlags;
     mCurrentState.sequence = 0;
     mCurrentState.requested = mCurrentState.active;
-    mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN;
     mCurrentState.appId = 0;
     mCurrentState.type = 0;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
 
-#ifdef USE_HWC2
-    const auto& hwc = flinger->getHwComposer();
-    const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
-    nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
-#else
-    nsecs_t displayPeriod =
-            flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-#endif
-    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
-
     CompositorTiming compositorTiming;
     flinger->getCompositorTiming(&compositorTiming);
     mFrameEventHistory.initializeCompositorTiming(compositorTiming);
 }
 
-void Layer::onFirstRef() {
-    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, true);
-    mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
-    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceFlingerConsumer->setContentsChangedListener(this);
-    mSurfaceFlingerConsumer->setName(mName);
-
-    if (mFlinger->isLayerTripleBufferingDisabled()) {
-        mProducer->setMaxDequeuedBufferCount(2);
+void Layer::onFirstRef() NO_THREAD_SAFETY_ANALYSIS {
+    if (!isCreatedFromMainThread()) {
+        // Grab the SF state lock during this since it's the only way to safely access HWC
+        mFlinger->mStateLock.lock();
     }
 
-    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
-    updateTransformHint(hw);
+    const auto& hwc = mFlinger->getHwComposer();
+    const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
+    nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
+    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
+
+    if (!isCreatedFromMainThread()) {
+        mFlinger->mStateLock.unlock();
+    }
 }
 
 Layer::~Layer() {
-  sp<Client> c(mClientRef.promote());
+    sp<Client> c(mClientRef.promote());
     if (c != 0) {
         c->detachLayer(this);
     }
@@ -198,106 +163,25 @@
     for (auto& point : mLocalSyncPoints) {
         point->setFrameAvailable();
     }
-    mFlinger->deleteTextureAsync(mTextureName);
     mFrameTracker.logAndResetStats(mName);
-
-#ifdef USE_HWC2
-    if (!mHwcLayers.empty()) {
-        ALOGE("Found stale hardware composer layers when destroying "
-                "surface flinger layer %s", mName.string());
-        destroyAllHwcLayers();
-    }
-#endif
 }
 
 // ---------------------------------------------------------------------------
 // callbacks
 // ---------------------------------------------------------------------------
 
-#ifdef USE_HWC2
-void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    if (mHwcLayers.empty()) {
-        return;
-    }
-    mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
-}
-#else
-void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */,
-        HWComposer::HWCLayerInterface* layer) {
-    if (layer) {
-        layer->onDisplayed();
-        mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
-    }
-}
-#endif
-
-void Layer::onFrameAvailable(const BufferItem& item) {
-    // Add this buffer from our internal queue tracker
-    { // Autolock scope
-        Mutex::Autolock lock(mQueueItemLock);
-        mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
-                item.mGraphicBuffer->getHeight(), item.mFrameNumber);
-        // Reset the frame number tracker when we receive the first buffer after
-        // a frame number reset
-        if (item.mFrameNumber == 1) {
-            mLastFrameNumberReceived = 0;
-        }
-
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                    ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
-            }
-        }
-
-        mQueueItems.push_back(item);
-        android_atomic_inc(&mQueuedFrames);
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
-    }
-
-    mFlinger->signalLayerUpdate();
-}
-
-void Layer::onFrameReplaced(const BufferItem& item) {
-    { // Autolock scope
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                    ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
-            }
-        }
-
-        if (mQueueItems.empty()) {
-            ALOGE("Can't replace a frame on an empty queue");
-            return;
-        }
-        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
-    }
-}
-
-void Layer::onSidebandStreamChanged() {
-    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
-        // mSidebandStreamChanged was false
-        mFlinger->signalLayerUpdate();
-    }
-}
+/*
+ * onLayerDisplayed is only meaningful for BufferLayer, but, is called through
+ * Layer.  So, the implementation is done in BufferLayer.  When called on a
+ * ColorLayer object, it's essentially a NOP.
+ */
+void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
 
 void Layer::onRemovedFromCurrentState() {
     // the layer is removed from SF mCurrentState to mLayersPendingRemoval
 
+    mPendingRemoval = true;
+
     if (mCurrentState.zOrderRelativeOf != nullptr) {
         sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
         if (strongRelative != nullptr) {
@@ -314,11 +198,9 @@
 
 void Layer::onRemoved() {
     // the layer is removed from SF mLayersPendingRemoval
+    abandon();
 
-    mSurfaceFlingerConsumer->abandon();
-#ifdef USE_HWC2
     destroyAllHwcLayers();
-#endif
 
     for (const auto& child : mCurrentChildren) {
         child->onRemoved();
@@ -333,92 +215,58 @@
     return mName;
 }
 
-status_t Layer::setBuffers( uint32_t w, uint32_t h,
-                            PixelFormat format, uint32_t flags)
-{
-    uint32_t const maxSurfaceDims = min(
-            mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
-    // never allow a surface larger than what our underlying GL implementation
-    // can handle.
-    if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) {
-        ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
-        return BAD_VALUE;
-    }
-
-    mFormat = format;
-
-    mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
-    mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
-    mCurrentOpacity = getOpacityForFormat(format);
-
-    mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
-    mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
-    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
-    return NO_ERROR;
+bool Layer::getPremultipledAlpha() const {
+    return mPremultipliedAlpha;
 }
 
 sp<IBinder> Layer::getHandle() {
     Mutex::Autolock _l(mLock);
-
-    LOG_ALWAYS_FATAL_IF(mHasSurface,
-            "Layer::getHandle() has already been called");
-
-    mHasSurface = true;
-
     return new Handle(mFlinger, this);
 }
 
-sp<IGraphicBufferProducer> Layer::getProducer() const {
-    return mProducer;
-}
-
 // ---------------------------------------------------------------------------
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-#ifdef USE_HWC2
 bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) {
-    LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0,
-                "Already have a layer for hwcId %d", hwcId);
+    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
+                        "Already have a layer for hwcId %d", hwcId);
     HWC2::Layer* layer = hwc->createLayer(hwcId);
     if (!layer) {
         return false;
     }
-    HWCInfo& hwcInfo = mHwcLayers[hwcId];
+    LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[hwcId];
     hwcInfo.hwc = hwc;
     hwcInfo.layer = layer;
     layer->setLayerDestroyedListener(
-            [this, hwcId] (HWC2::Layer* /*layer*/){mHwcLayers.erase(hwcId);});
+            [this, hwcId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(hwcId); });
     return true;
 }
 
-void Layer::destroyHwcLayer(int32_t hwcId) {
-    if (mHwcLayers.count(hwcId) == 0) {
-        return;
+bool Layer::destroyHwcLayer(int32_t hwcId) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
+        return false;
     }
-    auto& hwcInfo = mHwcLayers[hwcId];
-    LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr,
-            "Attempt to destroy null layer");
+    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
     LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
     hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer);
     // The layer destroyed listener should have cleared the entry from
     // mHwcLayers. Verify that.
-    LOG_ALWAYS_FATAL_IF(mHwcLayers.count(hwcId) != 0,
-            "Stale layer entry in mHwcLayers");
+    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
+                        "Stale layer entry in getBE().mHwcLayers");
+    return true;
 }
 
 void Layer::destroyAllHwcLayers() {
-    size_t numLayers = mHwcLayers.size();
+    size_t numLayers = getBE().mHwcLayers.size();
     for (size_t i = 0; i < numLayers; ++i) {
-        LOG_ALWAYS_FATAL_IF(mHwcLayers.empty(), "destroyAllHwcLayers failed");
-        destroyHwcLayer(mHwcLayers.begin()->first);
+        LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.empty(), "destroyAllHwcLayers failed");
+        destroyHwcLayer(getBE().mHwcLayers.begin()->first);
     }
-    LOG_ALWAYS_FATAL_IF(!mHwcLayers.empty(),
-            "All hardware composer layers should have been destroyed");
+    LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
+                        "All hardware composer layers should have been destroyed");
 }
-#endif
 
 Rect Layer::getContentCrop() const {
     // this is the crop rectangle that applies to the buffer
@@ -427,9 +275,9 @@
     if (!mCurrentCrop.isEmpty()) {
         // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else if (mActiveBuffer != NULL) {
+    } else if (getBE().compositionInfo.mBuffer != nullptr) {
         // otherwise we use the whole buffer
-        crop = mActiveBuffer->getBounds();
+        crop = getBE().compositionInfo.mBuffer->getBounds();
     } else {
         // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
@@ -447,6 +295,14 @@
     return Region(win).subtract(exclude).getBounds();
 }
 
+static FloatRect reduce(const FloatRect& win, const Region& exclude) {
+    if (CC_LIKELY(exclude.isEmpty())) {
+        return win;
+    }
+    // Convert through Rect (by rounding) for lack of FloatRegion
+    return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
+}
+
 Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
     const Layer::State& s(getDrawingState());
     Rect win(s.active.w, s.active.h);
@@ -485,12 +341,12 @@
     return win;
 }
 
-Rect Layer::computeBounds() const {
+FloatRect Layer::computeBounds() const {
     const Layer::State& s(getDrawingState());
     return computeBounds(s.activeTransparentRegion);
 }
 
-Rect Layer::computeBounds(const Region& activeTransparentRegion) const {
+FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
     const Layer::State& s(getDrawingState());
     Rect win(s.active.w, s.active.h);
 
@@ -498,23 +354,30 @@
         win.intersect(s.crop, &win);
     }
 
-    Rect bounds = win;
     const auto& p = mDrawingParent.promote();
+    FloatRect floatWin = win.toFloatRect();
+    FloatRect parentBounds = floatWin;
     if (p != nullptr) {
-        // Look in computeScreenBounds recursive call for explanation of
-        // why we pass false here.
-        bounds = p->computeScreenBounds(false /* reduceTransparentRegion */);
+        // We pass an empty Region here for reasons mirroring that of the case described in
+        // the computeScreenBounds reduceTransparentRegion=false case.
+        parentBounds = p->computeBounds(Region());
     }
 
-    Transform t = getTransform();
-    if (p != nullptr) {
-        win = t.transform(win);
-        win.intersect(bounds, &win);
-        win = t.inverse().transform(win);
+    Transform t = s.active.transform;
+
+
+    if (p != nullptr || !s.finalCrop.isEmpty()) {
+        floatWin = t.transform(floatWin);
+        floatWin = floatWin.intersect(parentBounds);
+
+        if (!s.finalCrop.isEmpty()) {
+            floatWin = floatWin.intersect(s.finalCrop.toFloatRect());
+        }
+        floatWin = t.inverse().transform(floatWin);
     }
 
     // subtract the transparent region and snap to the bounds
-    return reduce(win, activeTransparentRegion);
+    return reduce(floatWin, activeTransparentRegion);
 }
 
 Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
@@ -540,10 +403,17 @@
         activeCrop.clear();
     }
     if (!s.finalCrop.isEmpty()) {
-        if(!activeCrop.intersect(s.finalCrop, &activeCrop)) {
+        if (!activeCrop.intersect(s.finalCrop, &activeCrop)) {
             activeCrop.clear();
         }
     }
+
+    const auto& p = mDrawingParent.promote();
+    if (p != nullptr) {
+        auto parentCrop = p->computeInitialCrop(hw);
+        activeCrop.intersect(parentCrop, &activeCrop);
+    }
+
     return activeCrop;
 }
 
@@ -557,11 +427,6 @@
 
     // Screen space to make reduction to parent crop clearer.
     Rect activeCrop = computeInitialCrop(hw);
-    const auto& p = mDrawingParent.promote();
-    if (p != nullptr) {
-        auto parentCrop = p->computeInitialCrop(hw);
-        activeCrop.intersect(parentCrop, &activeCrop);
-    }
     Transform t = getTransform();
     // Back to layer space to work with the content crop.
     activeCrop = t.inverse().transform(activeCrop);
@@ -588,16 +453,13 @@
          * the code below applies the primary display's inverse transform to the
          * buffer
          */
-        uint32_t invTransformOrient =
-                DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransformOrient = DisplayDevice::getPrimaryDisplayOrientationTransform();
         // calculate the inverse transform
         if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-            invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+            invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
         // and apply to the current transform
-        invTransform = (Transform(invTransformOrient) * Transform(invTransform))
-                .getOrientation();
+        invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation();
     }
 
     int winWidth = s.active.w;
@@ -611,49 +473,36 @@
         bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
         bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
         if (is_h_flipped == is_v_flipped) {
-            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
         winWidth = s.active.h;
         winHeight = s.active.w;
     }
-    const Rect winCrop = activeCrop.transform(
-            invTransform, s.active.w, s.active.h);
+    const Rect winCrop = activeCrop.transform(invTransform, s.active.w, s.active.h);
 
     // below, crop is intersected with winCrop expressed in crop's coordinate space
-    float xScale = crop.getWidth()  / float(winWidth);
+    float xScale = crop.getWidth() / float(winWidth);
     float yScale = crop.getHeight() / float(winHeight);
 
-    float insetL = winCrop.left                 * xScale;
-    float insetT = winCrop.top                  * yScale;
-    float insetR = (winWidth - winCrop.right )  * xScale;
+    float insetL = winCrop.left * xScale;
+    float insetT = winCrop.top * yScale;
+    float insetR = (winWidth - winCrop.right) * xScale;
     float insetB = (winHeight - winCrop.bottom) * yScale;
 
-    crop.left   += insetL;
-    crop.top    += insetT;
-    crop.right  -= insetR;
+    crop.left += insetL;
+    crop.top += insetT;
+    crop.right -= insetR;
     crop.bottom -= insetB;
 
     return crop;
 }
 
-#ifdef USE_HWC2
 void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z)
-#else
-void Layer::setGeometry(
-    const sp<const DisplayDevice>& hw,
-        HWComposer::HWCLayerInterface& layer)
-#endif
 {
-#ifdef USE_HWC2
     const auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcInfo = mHwcLayers[hwcId];
-#else
-    layer.setDefaultState();
-#endif
+    auto& hwcInfo = getBE().mHwcLayers[hwcId];
 
     // enable this layer
-#ifdef USE_HWC2
     hwcInfo.forceClientComposition = false;
 
     if (isSecure() && !displayDevice->isSecure()) {
@@ -661,33 +510,20 @@
     }
 
     auto& hwcLayer = hwcInfo.layer;
-#else
-    layer.setSkip(false);
-
-    if (isSecure() && !hw->isSecure()) {
-        layer.setSkip(true);
-    }
-#endif
 
     // this gives us only the "orientation" component of the transform
     const State& s(getDrawingState());
-#ifdef USE_HWC2
     auto blendMode = HWC2::BlendMode::None;
     if (!isOpaque(s) || getAlpha() != 1.0f) {
-        blendMode = mPremultipliedAlpha ?
-                HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
+        blendMode =
+                mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
     }
     auto error = hwcLayer->setBlendMode(blendMode);
-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
-             " %s (%d)", mName.string(), to_string(blendMode).c_str(),
-             to_string(error).c_str(), static_cast<int32_t>(error));
-#else
-    if (!isOpaque(s) || getAlpha() != 0xFF) {
-        layer.setBlending(mPremultipliedAlpha ?
-                HWC_BLENDING_PREMULT :
-                HWC_BLENDING_COVERAGE);
-    }
-#endif
+    ALOGE_IF(error != HWC2::Error::None,
+             "[%s] Failed to set blend mode %s:"
+             " %s (%d)",
+             mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
+             static_cast<int32_t>(error));
 
     // apply the layer's transform, followed by the display's global transform
     // here we're guaranteed that the layer's transform preserves rects
@@ -696,11 +532,7 @@
     if (!s.crop.isEmpty()) {
         Rect activeCrop(s.crop);
         activeCrop = t.transform(activeCrop);
-#ifdef USE_HWC2
-        if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
-#else
-        if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
-#endif
+        if (!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
             activeCrop.clear();
         }
         activeCrop = t.inverse().transform(activeCrop, true);
@@ -710,26 +542,25 @@
         // transform.inverse().transform(transform.transform(Rect)) != Rect
         // in which case we need to make sure the final rect is clipped to the
         // display bounds.
-        if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+        if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
             activeCrop.clear();
         }
         // mark regions outside the crop as transparent
         activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
-        activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom,
-                s.active.w, s.active.h));
-        activeTransparentRegion.orSelf(Rect(0, activeCrop.top,
-                activeCrop.left, activeCrop.bottom));
-        activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top,
-                s.active.w, activeCrop.bottom));
+        activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h));
+        activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
+        activeTransparentRegion.orSelf(
+                Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
     }
 
-    Rect frame(t.transform(computeBounds(activeTransparentRegion)));
+    // computeBounds returns a FloatRect to provide more accuracy during the
+    // transformation. We then round upon constructing 'frame'.
+    Rect frame{t.transform(computeBounds(activeTransparentRegion))};
     if (!s.finalCrop.isEmpty()) {
-        if(!frame.intersect(s.finalCrop, &frame)) {
+        if (!frame.intersect(s.finalCrop, &frame)) {
             frame.clear();
         }
     }
-#ifdef USE_HWC2
     if (!frame.intersect(displayDevice->getViewport(), &frame)) {
         frame.clear();
     }
@@ -737,10 +568,9 @@
     Rect transformedFrame = tr.transform(frame);
     error = hwcLayer->setDisplayFrame(transformedFrame);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
-                mName.string(), transformedFrame.left, transformedFrame.top,
-                transformedFrame.right, transformedFrame.bottom,
-                to_string(error).c_str(), static_cast<int32_t>(error));
+        ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
+              transformedFrame.left, transformedFrame.top, transformedFrame.right,
+              transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
         hwcInfo.displayFrame = transformedFrame;
     }
@@ -749,45 +579,38 @@
     error = hwcLayer->setSourceCrop(sourceCrop);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
-                "%s (%d)", mName.string(), sourceCrop.left, sourceCrop.top,
-                sourceCrop.right, sourceCrop.bottom, to_string(error).c_str(),
-                static_cast<int32_t>(error));
+              "%s (%d)",
+              mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
+              to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
         hwcInfo.sourceCrop = sourceCrop;
     }
 
-    float alpha = getAlpha();
+    float alpha = static_cast<float>(getAlpha());
     error = hwcLayer->setPlaneAlpha(alpha);
-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
-            "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
-            static_cast<int32_t>(error));
+    ALOGE_IF(error != HWC2::Error::None,
+             "[%s] Failed to set plane alpha %.3f: "
+             "%s (%d)",
+             mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
 
     error = hwcLayer->setZOrder(z);
-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)",
-            mName.string(), z, to_string(error).c_str(),
-            static_cast<int32_t>(error));
+    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
+             to_string(error).c_str(), static_cast<int32_t>(error));
 
     int type = s.type;
     int appId = s.appId;
     sp<Layer> parent = mDrawingParent.promote();
     if (parent.get()) {
         auto& parentState = parent->getDrawingState();
-        type = parentState.type;
-        appId = parentState.appId;
+        if (parentState.type >= 0 || parentState.appId >= 0) {
+            type = parentState.type;
+            appId = parentState.appId;
+        }
     }
 
     error = hwcLayer->setInfo(type, appId);
-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)",
-             mName.string(), static_cast<int32_t>(error));
-#else
-    if (!frame.intersect(hw->getViewport(), &frame)) {
-        frame.clear();
-    }
-    const Transform& tr(hw->getTransform());
-    layer.setFrame(tr.transform(frame));
-    layer.setCrop(computeCrop(hw));
-    layer.setPlaneAlpha(getAlpha());
-#endif
+    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
+             static_cast<int32_t>(error));
 
     /*
      * Transformations are applied in this order:
@@ -805,12 +628,10 @@
          * the code below applies the primary display's inverse transform to the
          * buffer
          */
-        uint32_t invTransform =
-                DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
         // calculate the inverse transform
         if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
 
         /*
@@ -824,163 +645,43 @@
 
     // this gives us only the "orientation" component of the transform
     const uint32_t orientation = transform.getOrientation();
-#ifdef USE_HWC2
     if (orientation & Transform::ROT_INVALID) {
         // we can only handle simple transformation
         hwcInfo.forceClientComposition = true;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
+        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
-        ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: "
-                "%s (%d)", mName.string(), to_string(transform).c_str(),
-                to_string(error).c_str(), static_cast<int32_t>(error));
+        ALOGE_IF(error != HWC2::Error::None,
+                 "[%s] Failed to set transform %s: "
+                 "%s (%d)",
+                 mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
+                 static_cast<int32_t>(error));
     }
-#else
-    if (orientation & Transform::ROT_INVALID) {
-        // we can only handle simple transformation
-        layer.setSkip(true);
-    } else {
-        layer.setTransform(orientation);
-    }
-#endif
 }
 
-#ifdef USE_HWC2
 void Layer::forceClientComposition(int32_t hwcId) {
-    if (mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId);
         return;
     }
 
-    mHwcLayers[hwcId].forceClientComposition = true;
+    getBE().mHwcLayers[hwcId].forceClientComposition = true;
 }
 
-void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
-    // Apply this display's projection's viewport to the visible region
-    // before giving it to the HWC HAL.
-    const Transform& tr = displayDevice->getTransform();
-    const auto& viewport = displayDevice->getViewport();
-    Region visible = tr.transform(visibleRegion.intersect(viewport));
-    auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcInfo = mHwcLayers[hwcId];
-    auto& hwcLayer = hwcInfo.layer;
-    auto error = hwcLayer->setVisibleRegion(visible);
-    if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        visible.dump(LOG_TAG);
+bool Layer::getForceClientComposition(int32_t hwcId) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
+        ALOGE("getForceClientComposition: no HWC layer found (%d)", hwcId);
+        return false;
     }
 
-    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
-    if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
-                to_string(error).c_str(), static_cast<int32_t>(error));
-        surfaceDamageRegion.dump(LOG_TAG);
-    }
-
-    // Sideband layers
-    if (mSidebandStream.get()) {
-        setCompositionType(hwcId, HWC2::Composition::Sideband);
-        ALOGV("[%s] Requesting Sideband composition", mName.string());
-        error = hwcLayer->setSidebandStream(mSidebandStream->handle());
-        if (error != HWC2::Error::None) {
-            ALOGE("[%s] Failed to set sideband stream %p: %s (%d)",
-                    mName.string(), mSidebandStream->handle(),
-                    to_string(error).c_str(), static_cast<int32_t>(error));
-        }
-        return;
-    }
-
-    // Client layers
-    if (hwcInfo.forceClientComposition ||
-            (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
-        ALOGV("[%s] Requesting Client composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Client);
-        return;
-    }
-
-    // SolidColor layers
-    if (mActiveBuffer == nullptr) {
-        setCompositionType(hwcId, HWC2::Composition::SolidColor);
-
-        // For now, we only support black for DimLayer
-        error = hwcLayer->setColor({0, 0, 0, 255});
-        if (error != HWC2::Error::None) {
-            ALOGE("[%s] Failed to set color: %s (%d)", mName.string(),
-                    to_string(error).c_str(), static_cast<int32_t>(error));
-        }
-
-        // Clear out the transform, because it doesn't make sense absent a
-        // source buffer
-        error = hwcLayer->setTransform(HWC2::Transform::None);
-        if (error != HWC2::Error::None) {
-            ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(),
-                    to_string(error).c_str(), static_cast<int32_t>(error));
-        }
-
-        return;
-    }
-
-    // Device or Cursor layers
-    if (mPotentialCursor) {
-        ALOGV("[%s] Requesting Cursor composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Cursor);
-    } else {
-        ALOGV("[%s] Requesting Device composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Device);
-    }
-
-    ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace);
-    error = hwcLayer->setDataspace(mCurrentState.dataSpace);
-    if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(),
-              mCurrentState.dataSpace, to_string(error).c_str(),
-              static_cast<int32_t>(error));
-    }
-
-    uint32_t hwcSlot = 0;
-    sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
-            &hwcSlot, &hwcBuffer);
-
-    auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
-    error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
-    if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
-                mActiveBuffer->handle, to_string(error).c_str(),
-                static_cast<int32_t>(error));
-    }
+    return getBE().mHwcLayers[hwcId].forceClientComposition;
 }
 
-#else
-void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
-        HWComposer::HWCLayerInterface& layer) {
-    // we have to set the visible region on every frame because
-    // we currently free it during onLayerDisplayed(), which is called
-    // after HWComposer::commit() -- every frame.
-    // Apply this display's projection's viewport to the visible region
-    // before giving it to the HWC HAL.
-    const Transform& tr = hw->getTransform();
-    Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
-    layer.setVisibleRegionScreen(visible);
-    layer.setSurfaceDamage(surfaceDamageRegion);
-    mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER);
-
-    if (mSidebandStream.get()) {
-        layer.setSidebandStream(mSidebandStream);
-    } else {
-        // NOTE: buffer can be NULL if the client never drew into this
-        // layer yet, or if we ran out of memory
-        layer.setBuffer(mActiveBuffer);
-    }
-}
-#endif
-
-#ifdef USE_HWC2
 void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
     auto hwcId = displayDevice->getHwcDisplayId();
-    if (mHwcLayers.count(hwcId) == 0 ||
-            getCompositionType(hwcId) != HWC2::Composition::Cursor) {
+    if (getBE().mHwcLayers.count(hwcId) == 0 ||
+        getCompositionType(hwcId) != HWC2::Composition::Cursor) {
         return;
     }
 
@@ -1003,284 +704,62 @@
     auto& displayTransform(displayDevice->getTransform());
     auto position = displayTransform.transform(frame);
 
-    auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left,
-            position.top);
-    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set cursor position "
-            "to (%d, %d): %s (%d)", mName.string(), position.left,
-            position.top, to_string(error).c_str(),
-            static_cast<int32_t>(error));
+    auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left,
+                                                                              position.top);
+    ALOGE_IF(error != HWC2::Error::None,
+             "[%s] Failed to set cursor position "
+             "to (%d, %d): %s (%d)",
+             mName.string(), position.left, position.top, to_string(error).c_str(),
+             static_cast<int32_t>(error));
 }
-#else
-void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
-        HWComposer::HWCLayerInterface& layer) {
-    int fenceFd = -1;
-
-    // TODO: there is a possible optimization here: we only need to set the
-    // acquire fence the first time a new buffer is acquired on EACH display.
-
-    if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) {
-        sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
-        if (fence->isValid()) {
-            fenceFd = fence->dup();
-            if (fenceFd == -1) {
-                ALOGW("failed to dup layer fence, skipping sync: %d", errno);
-            }
-        }
-    }
-    layer.setAcquireFenceFd(fenceFd);
-}
-
-Rect Layer::getPosition(
-    const sp<const DisplayDevice>& hw)
-{
-    // this gives us only the "orientation" component of the transform
-    const State& s(getCurrentState());
-
-    // apply the layer's transform, followed by the display's global transform
-    // here we're guaranteed that the layer's transform preserves rects
-    Rect win(s.active.w, s.active.h);
-    if (!s.crop.isEmpty()) {
-        win.intersect(s.crop, &win);
-    }
-    // subtract the transparent region and snap to the bounds
-    Rect bounds = reduce(win, s.activeTransparentRegion);
-    Rect frame(getTransform().transform(bounds));
-    frame.intersect(hw->getViewport(), &frame);
-    if (!s.finalCrop.isEmpty()) {
-        frame.intersect(s.finalCrop, &frame);
-    }
-    const Transform& tr(hw->getTransform());
-    return Rect(tr.transform(frame));
-}
-#endif
 
 // ---------------------------------------------------------------------------
 // drawing...
 // ---------------------------------------------------------------------------
 
-void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
-    onDraw(hw, clip, false);
+void Layer::draw(const RenderArea& renderArea, const Region& clip) const {
+    onDraw(renderArea, clip, false);
 }
 
-void Layer::draw(const sp<const DisplayDevice>& hw,
-        bool useIdentityTransform) const {
-    onDraw(hw, Region(hw->bounds()), useIdentityTransform);
+void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const {
+    onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
 }
 
-void Layer::draw(const sp<const DisplayDevice>& hw) const {
-    onDraw(hw, Region(hw->bounds()), false);
+void Layer::draw(const RenderArea& renderArea) const {
+    onDraw(renderArea, Region(renderArea.getBounds()), false);
 }
 
-static constexpr mat4 inverseOrientation(uint32_t transform) {
-    const mat4 flipH(-1,0,0,0,  0,1,0,0, 0,0,1,0, 1,0,0,1);
-    const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
-    const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
-    mat4 tr;
-
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        tr = tr * rot90;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        tr = tr * flipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        tr = tr * flipV;
-    }
-    return inverse(tr);
-}
-
-/*
- * onDraw will draw the current layer onto the presentable buffer
- */
-void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-        bool useIdentityTransform) const
-{
-    ATRACE_CALL();
-
-    if (CC_UNLIKELY(mActiveBuffer == 0)) {
-        // the texture has not been created yet, this Layer has
-        // in fact never been drawn into. This happens frequently with
-        // SurfaceView because the WindowManager can't know when the client
-        // has drawn the first time.
-
-        // If there is nothing under us, we paint the screen in black, otherwise
-        // we just skip this update.
-
-        // figure out if there is something below us
-        Region under;
-        bool finished = false;
-        mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
-            if (finished || layer == static_cast<Layer const*>(this)) {
-                finished = true;
-                return;
-            }
-            under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
-        });
-        // if not everything below us is covered, we plug the holes!
-        Region holes(clip.subtract(under));
-        if (!holes.isEmpty()) {
-            clearWithOpenGL(hw, 0, 0, 0, 1);
-        }
-        return;
-    }
-
-    // Bind the current buffer to the GL texture, and wait for it to be
-    // ready for us to draw into.
-    status_t err = mSurfaceFlingerConsumer->bindTextureImage();
-    if (err != NO_ERROR) {
-        ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
-        // Go ahead and draw the buffer anyway; no matter what we do the screen
-        // is probably going to have something visibly wrong.
-    }
-
-    bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure());
-
-    RenderEngine& engine(mFlinger->getRenderEngine());
-
-    if (!blackOutLayer) {
-        // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize();
-
-        // Query the texture matrix given our current filtering mode.
-        float textureMatrix[16];
-        mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
-        mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
-
-        if (getTransformToDisplayInverse()) {
-
-            /*
-             * the code below applies the primary display's inverse transform to
-             * the texture transform
-             */
-            uint32_t transform =
-                    DisplayDevice::getPrimaryDisplayOrientationTransform();
-            mat4 tr = inverseOrientation(transform);
-
-            /**
-             * TODO(b/36727915): This is basically a hack.
-             *
-             * Ensure that regardless of the parent transformation,
-             * this buffer is always transformed from native display
-             * orientation to display orientation. For example, in the case
-             * of a camera where the buffer remains in native orientation,
-             * we want the pixels to always be upright.
-             */
-            sp<Layer> p = mDrawingParent.promote();
-            if (p != nullptr) {
-                const auto parentTransform = p->getTransform();
-                tr = tr * inverseOrientation(parentTransform.getOrientation());
-            }
-
-            // and finally apply it to the original texture matrix
-            const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
-            memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
-        }
-
-        // Set things up for texturing.
-        mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
-        mTexture.setFiltering(useFiltering);
-        mTexture.setMatrix(textureMatrix);
-
-        engine.setupLayerTexturing(mTexture);
-    } else {
-        engine.setupLayerBlackedOut();
-    }
-    drawWithOpenGL(hw, useIdentityTransform);
-    engine.disableTexturing();
-}
-
-
-void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw,
-        float red, float green, float blue,
-        float alpha) const
-{
-    RenderEngine& engine(mFlinger->getRenderEngine());
-    computeGeometry(hw, mMesh, false);
+void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
+                            float alpha) const {
+    auto& engine(mFlinger->getRenderEngine());
+    computeGeometry(renderArea, getBE().mMesh, false);
     engine.setupFillWithColor(red, green, blue, alpha);
-    engine.drawMesh(mMesh);
+    engine.drawMesh(getBE().mMesh);
 }
 
-void Layer::clearWithOpenGL(
-        const sp<const DisplayDevice>& hw) const {
-    clearWithOpenGL(hw, 0,0,0,0);
+void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
+    clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw,
-        bool useIdentityTransform) const {
-    const State& s(getDrawingState());
-
-    computeGeometry(hw, mMesh, useIdentityTransform);
-
-    /*
-     * NOTE: the way we compute the texture coordinates here produces
-     * different results than when we take the HWC path -- in the later case
-     * the "source crop" is rounded to texel boundaries.
-     * This can produce significantly different results when the texture
-     * is scaled by a large amount.
-     *
-     * The GL code below is more logical (imho), and the difference with
-     * HWC is due to a limitation of the HWC API to integers -- a question
-     * is suspend is whether we should ignore this problem or revert to
-     * GL composition when a buffer scaling is applied (maybe with some
-     * minimal value)? Or, we could make GL behave like HWC -- but this feel
-     * like more of a hack.
-     */
-    Rect win(computeBounds());
-
-    Transform t = getTransform();
-    if (!s.finalCrop.isEmpty()) {
-        win = t.transform(win);
-        if (!win.intersect(s.finalCrop, &win)) {
-            win.clear();
-        }
-        win = t.inverse().transform(win);
-        if (!win.intersect(computeBounds(), &win)) {
-            win.clear();
-        }
-    }
-
-    float left   = float(win.left)   / float(s.active.w);
-    float top    = float(win.top)    / float(s.active.h);
-    float right  = float(win.right)  / float(s.active.w);
-    float bottom = float(win.bottom) / float(s.active.h);
-
-    // TODO: we probably want to generate the texture coords with the mesh
-    // here we assume that we only have 4 vertices
-    Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
-    texCoords[0] = vec2(left, 1.0f - top);
-    texCoords[1] = vec2(left, 1.0f - bottom);
-    texCoords[2] = vec2(right, 1.0f - bottom);
-    texCoords[3] = vec2(right, 1.0f - top);
-
-    RenderEngine& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
-#ifdef USE_HWC2
-    engine.setSourceDataSpace(mCurrentState.dataSpace);
-#endif
-    engine.drawMesh(mMesh);
-    engine.disableBlending();
-}
-
-#ifdef USE_HWC2
-void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type,
-        bool callIntoHwc) {
-    if (mHwcLayers.count(hwcId) == 0) {
+void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         ALOGE("setCompositionType called without a valid HWC layer");
         return;
     }
-    auto& hwcInfo = mHwcLayers[hwcId];
+    auto& hwcInfo = getBE().mHwcLayers[hwcId];
     auto& hwcLayer = hwcInfo.layer;
-    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(),
-            to_string(type).c_str(), static_cast<int>(callIntoHwc));
+    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(),
+          static_cast<int>(callIntoHwc));
     if (hwcInfo.compositionType != type) {
         ALOGV("    actually setting");
         hwcInfo.compositionType = type;
         if (callIntoHwc) {
             auto error = hwcLayer->setCompositionType(type);
-            ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set "
-                    "composition type %s: %s (%d)", mName.string(),
-                    to_string(type).c_str(), to_string(error).c_str(),
-                    static_cast<int32_t>(error));
+            ALOGE_IF(error != HWC2::Error::None,
+                     "[%s] Failed to set "
+                     "composition type %s: %s (%d)",
+                     mName.string(), to_string(type).c_str(), to_string(error).c_str(),
+                     static_cast<int32_t>(error));
         }
     }
 }
@@ -1291,86 +770,27 @@
         // have a HWC counterpart, then it will always be Client
         return HWC2::Composition::Client;
     }
-    if (mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         ALOGE("getCompositionType called with an invalid HWC layer");
         return HWC2::Composition::Invalid;
     }
-    return mHwcLayers.at(hwcId).compositionType;
+    return getBE().mHwcLayers.at(hwcId).compositionType;
 }
 
 void Layer::setClearClientTarget(int32_t hwcId, bool clear) {
-    if (mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         ALOGE("setClearClientTarget called without a valid HWC layer");
         return;
     }
-    mHwcLayers[hwcId].clearClientTarget = clear;
+    getBE().mHwcLayers[hwcId].clearClientTarget = clear;
 }
 
 bool Layer::getClearClientTarget(int32_t hwcId) const {
-    if (mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         ALOGE("getClearClientTarget called without a valid HWC layer");
         return false;
     }
-    return mHwcLayers.at(hwcId).clearClientTarget;
-}
-#endif
-
-uint32_t Layer::getProducerStickyTransform() const {
-    int producerStickyTransform = 0;
-    int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
-    if (ret != OK) {
-        ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
-                strerror(-ret), ret);
-        return 0;
-    }
-    return static_cast<uint32_t>(producerStickyTransform);
-}
-
-bool Layer::latchUnsignaledBuffers() {
-    static bool propertyLoaded = false;
-    static bool latch = false;
-    static std::mutex mutex;
-    std::lock_guard<std::mutex> lock(mutex);
-    if (!propertyLoaded) {
-        char value[PROPERTY_VALUE_MAX] = {};
-        property_get("debug.sf.latch_unsignaled", value, "0");
-        latch = atoi(value);
-        propertyLoaded = true;
-    }
-    return latch;
-}
-
-uint64_t Layer::getHeadFrameNumber() const {
-    Mutex::Autolock lock(mQueueItemLock);
-    if (!mQueueItems.empty()) {
-        return mQueueItems[0].mFrameNumber;
-    } else {
-        return mCurrentFrameNumber;
-    }
-}
-
-bool Layer::headFenceHasSignaled() const {
-#ifdef USE_HWC2
-    if (latchUnsignaledBuffers()) {
-        return true;
-    }
-
-    Mutex::Autolock lock(mQueueItemLock);
-    if (mQueueItems.empty()) {
-        return true;
-    }
-    if (mQueueItems[0].mIsDroppable) {
-        // Even though this buffer's fence may not have signaled yet, it could
-        // be replaced by another buffer before it has a chance to, which means
-        // that it's possible to get into a situation where a buffer is never
-        // able to be latched. To avoid this, grab this buffer anyway.
-        return true;
-    }
-    return mQueueItems[0].mFenceTime->getSignalTime() !=
-            Fence::SIGNAL_TIME_PENDING;
-#else
-    return true;
-#endif
+    return getBE().mHwcLayers.at(hwcId).clearClientTarget;
 }
 
 bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
@@ -1393,28 +813,6 @@
     return mFiltering;
 }
 
-// As documented in libhardware header, formats in the range
-// 0x100 - 0x1FF are specific to the HAL implementation, and
-// are known to have no alpha channel
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool Layer::getOpacityForFormat(uint32_t format) {
-    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
-        return true;
-    }
-    switch (format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        case HAL_PIXEL_FORMAT_RGBA_FP16:
-        case HAL_PIXEL_FORMAT_RGBA_1010102:
-            return false;
-    }
-    // in all other case, we have no blending (also for unknown formats)
-    return true;
-}
-
 // ----------------------------------------------------------------------------
 // local state
 // ----------------------------------------------------------------------------
@@ -1434,13 +832,12 @@
     }
 }
 
-void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
-        bool useIdentityTransform) const
-{
+void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh,
+                            bool useIdentityTransform) const {
     const Layer::State& s(getDrawingState());
-    const Transform hwTransform(hw->getTransform());
-    const uint32_t hw_h = hw->getHeight();
-    Rect win = computeBounds();
+    const Transform renderAreaTransform(renderArea.getTransform());
+    const uint32_t height = renderArea.getHeight();
+    FloatRect win = computeBounds();
 
     vec2 lt = vec2(win.left, win.top);
     vec2 lb = vec2(win.left, win.bottom);
@@ -1463,53 +860,20 @@
     }
 
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    position[0] = hwTransform.transform(lt);
-    position[1] = hwTransform.transform(lb);
-    position[2] = hwTransform.transform(rb);
-    position[3] = hwTransform.transform(rt);
-    for (size_t i=0 ; i<4 ; i++) {
-        position[i].y = hw_h - position[i].y;
+    position[0] = renderAreaTransform.transform(lt);
+    position[1] = renderAreaTransform.transform(lb);
+    position[2] = renderAreaTransform.transform(rb);
+    position[3] = renderAreaTransform.transform(rt);
+    for (size_t i = 0; i < 4; i++) {
+        position[i].y = height - position[i].y;
     }
 }
 
-bool Layer::isOpaque(const Layer::State& s) const
-{
-    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
-    // layer's opaque flag.
-    if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
-        return false;
-    }
-
-    // if the layer has the opaque flag, then we're always opaque,
-    // otherwise we use the current buffer's format.
-    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
-}
-
-bool Layer::isSecure() const
-{
+bool Layer::isSecure() const {
     const Layer::State& s(mDrawingState);
     return (s.flags & layer_state_t::eLayerSecure);
 }
 
-bool Layer::isProtected() const
-{
-    const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
-    return (activeBuffer != 0) &&
-            (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
-bool Layer::isFixedSize() const {
-    return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-}
-
-bool Layer::isCropped() const {
-    return !mCurrentCrop.isEmpty();
-}
-
-bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const {
-    return mNeedsFiltering || hw->needsFiltering();
-}
-
 void Layer::setVisibleRegion(const Region& visibleRegion) {
     // always called from main thread
     this->visibleRegion = visibleRegion;
@@ -1520,12 +884,17 @@
     this->coveredRegion = coveredRegion;
 }
 
-void Layer::setVisibleNonTransparentRegion(const Region&
-        setVisibleNonTransparentRegion) {
+void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) {
     // always called from main thread
     this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
 }
 
+void Layer::clearVisibilityRegions() {
+    visibleRegion.clear();
+    visibleNonTransparentRegion.clear();
+    coveredRegion.clear();
+}
+
 // ----------------------------------------------------------------------------
 // transaction
 // ----------------------------------------------------------------------------
@@ -1546,8 +915,7 @@
             // to be applied as per normal (no synchronization).
             mCurrentState.barrierLayer = nullptr;
         } else {
-            auto syncPoint = std::make_shared<SyncPoint>(
-                    mCurrentState.frameNumber);
+            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
             if (barrierLayer->addSyncPoint(syncPoint)) {
                 mRemoteSyncPoints.push_back(std::move(syncPoint));
             } else {
@@ -1566,10 +934,7 @@
 }
 
 void Layer::popPendingState(State* stateToCommit) {
-    auto oldFlags = stateToCommit->flags;
     *stateToCommit = mPendingStates[0];
-    stateToCommit->flags = (oldFlags & ~stateToCommit->mask) |
-            (stateToCommit->flags & stateToCommit->mask);
 
     mPendingStates.removeAt(0);
     ATRACE_INT(mTransactionName.string(), mPendingStates.size());
@@ -1589,10 +954,8 @@
                 continue;
             }
 
-            if (mRemoteSyncPoints.front()->getFrameNumber() !=
-                    mPendingStates[0].frameNumber) {
-                ALOGE("[%s] Unexpected sync point frame number found",
-                        mName.string());
+            if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) {
+                ALOGE("[%s] Unexpected sync point frame number found", mName.string());
 
                 // Signal our end of the sync point and then dispose of it
                 mRemoteSyncPoints.front()->setTransactionApplied();
@@ -1628,17 +991,6 @@
     return stateUpdateAvailable;
 }
 
-void Layer::notifyAvailableFrames() {
-    auto headFrameNumber = getHeadFrameNumber();
-    bool headFenceSignaled = headFenceHasSignaled();
-    Mutex::Autolock lock(mLocalSyncPointMutex);
-    for (auto& point : mLocalSyncPoints) {
-        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
-            point->setFrameAvailable();
-        }
-    }
-}
-
 uint32_t Layer::doTransaction(uint32_t flags) {
     ATRACE_CALL();
 
@@ -1650,59 +1002,50 @@
 
     const Layer::State& s(getDrawingState());
 
-    const bool sizeChanged = (c.requested.w != s.requested.w) ||
-                             (c.requested.h != s.requested.h);
+    const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h);
 
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         ALOGD_IF(DEBUG_RESIZE,
-                "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
-                "  current={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
-                "            requested={ wh={%4u,%4u} }}\n"
-                "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
-                "            requested={ wh={%4u,%4u} }}\n",
-                this, getName().string(), mCurrentTransform,
-                getEffectiveScalingMode(),
-                c.active.w, c.active.h,
-                c.crop.left,
-                c.crop.top,
-                c.crop.right,
-                c.crop.bottom,
-                c.crop.getWidth(),
-                c.crop.getHeight(),
-                c.requested.w, c.requested.h,
-                s.active.w, s.active.h,
-                s.crop.left,
-                s.crop.top,
-                s.crop.right,
-                s.crop.bottom,
-                s.crop.getWidth(),
-                s.crop.getHeight(),
-                s.requested.w, s.requested.h);
+                 "doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
+                 "  current={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+                 "            requested={ wh={%4u,%4u} }}\n"
+                 "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+                 "            requested={ wh={%4u,%4u} }}\n",
+                 this, getName().string(), mCurrentTransform,
+                 getEffectiveScalingMode(), c.active.w, c.active.h, c.crop.left, c.crop.top,
+                 c.crop.right, c.crop.bottom, c.crop.getWidth(), c.crop.getHeight(), c.requested.w,
+                 c.requested.h, s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right,
+                 s.crop.bottom, s.crop.getWidth(), s.crop.getHeight(), s.requested.w,
+                 s.requested.h);
 
         // record the new size, form this point on, when the client request
         // a buffer, it'll get the new size.
-        mSurfaceFlingerConsumer->setDefaultBufferSize(
-                c.requested.w, c.requested.h);
+        setDefaultBufferSize(c.requested.w, c.requested.h);
     }
 
-    const bool resizePending = (c.requested.w != c.active.w) ||
-            (c.requested.h != c.active.h);
+    // Don't let Layer::doTransaction update the drawing state
+    // if we have a pending resize, unless we are in fixed-size mode.
+    // the drawing state will be updated only once we receive a buffer
+    // with the correct size.
+    //
+    // In particular, we want to make sure the clip (which is part
+    // of the geometry state) is latched together with the size but is
+    // latched immediately when no resizing is involved.
+    //
+    // If a sideband stream is attached, however, we want to skip this
+    // optimization so that transactions aren't missed when a buffer
+    // never arrives
+    //
+    // In the case that we don't have a buffer we ignore other factors
+    // and avoid entering the resizePending state. At a high level the
+    // resizePending state is to avoid applying the state of the new buffer
+    // to the old buffer. However in the state where we don't have an old buffer
+    // there is no such concern but we may still be being used as a parent layer.
+    const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
+            (getBE().compositionInfo.mBuffer != nullptr);
     if (!isFixedSize()) {
-        if (resizePending && mSidebandStream == NULL) {
-            // don't let Layer::doTransaction update the drawing state
-            // if we have a pending resize, unless we are in fixed-size mode.
-            // the drawing state will be updated only once we receive a buffer
-            // with the correct size.
-            //
-            // in particular, we want to make sure the clip (which is part
-            // of the geometry state) is latched together with the size but is
-            // latched immediately when no resizing is involved.
-            //
-            // If a sideband stream is attached, however, we want to skip this
-            // optimization so that transactions aren't missed when a buffer
-            // never arrives
-
+        if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
             flags |= eDontUpdateGeometryState;
         }
     }
@@ -1749,8 +1092,7 @@
 
         // we may use linear filtering, if the matrix scales us
         const uint8_t type = c.active.transform.getType();
-        mNeedsFiltering = (!c.active.transform.preserveRects() ||
-                (type >= Transform::SCALE));
+        mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE));
     }
 
     // If the layer is hidden, signal and clear out all local sync points so
@@ -1808,13 +1150,27 @@
     if (childLayer->setLayer(z)) {
         mCurrentChildren.removeAt(idx);
         mCurrentChildren.add(childLayer);
+        return true;
     }
-    return true;
+    return false;
+}
+
+bool Layer::setChildRelativeLayer(const sp<Layer>& childLayer,
+        const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
+    ssize_t idx = mCurrentChildren.indexOf(childLayer);
+    if (idx < 0) {
+        return false;
+    }
+    if (childLayer->setRelativeLayer(relativeToHandle, relativeZ)) {
+        mCurrentChildren.removeAt(idx);
+        mCurrentChildren.add(childLayer);
+        return true;
+    }
+    return false;
 }
 
 bool Layer::setLayer(int32_t z) {
-    if (mCurrentState.z == z)
-        return false;
+    if (mCurrentState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
     mCurrentState.sequence++;
     mCurrentState.z = z;
     mCurrentState.modified = true;
@@ -1845,7 +1201,7 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) {
+bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
     sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
     if (handle == nullptr) {
         return false;
@@ -1855,10 +1211,19 @@
         return false;
     }
 
+    if (mCurrentState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
+            mCurrentState.zOrderRelativeOf == relative) {
+        return false;
+    }
+
     mCurrentState.sequence++;
     mCurrentState.modified = true;
-    mCurrentState.z = z;
+    mCurrentState.z = relativeZ;
 
+    auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
+    if (oldZOrderRelativeOf != nullptr) {
+        oldZOrderRelativeOf->removeZOrderRelative(this);
+    }
     mCurrentState.zOrderRelativeOf = relative;
     relative->addZOrderRelative(this);
 
@@ -1868,31 +1233,47 @@
 }
 
 bool Layer::setSize(uint32_t w, uint32_t h) {
-    if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
-        return false;
+    if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false;
     mCurrentState.requested.w = w;
     mCurrentState.requested.h = h;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-#ifdef USE_HWC2
 bool Layer::setAlpha(float alpha) {
-#else
-bool Layer::setAlpha(uint8_t alpha) {
-#endif
-    if (mCurrentState.alpha == alpha)
-        return false;
+    if (mCurrentState.color.a == alpha) return false;
     mCurrentState.sequence++;
-    mCurrentState.alpha = alpha;
+    mCurrentState.color.a = alpha;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
+
+bool Layer::setColor(const half3& color) {
+    if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g &&
+        color.b == mCurrentState.color.b)
+        return false;
+
     mCurrentState.sequence++;
-    mCurrentState.requested.transform.set(
-            matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+    mCurrentState.color.r = color.r;
+    mCurrentState.color.g = color.g;
+    mCurrentState.color.b = color.b;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
+        bool allowNonRectPreservingTransforms) {
+    Transform t;
+    t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+    if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
+        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+        return false;
+    }
+    mCurrentState.sequence++;
+    mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1905,19 +1286,16 @@
 }
 bool Layer::setFlags(uint8_t flags, uint8_t mask) {
     const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
-    if (mCurrentState.flags == newFlags)
-        return false;
+    if (mCurrentState.flags == newFlags) return false;
     mCurrentState.sequence++;
     mCurrentState.flags = newFlags;
-    mCurrentState.mask = mask;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
 
 bool Layer::setCrop(const Rect& crop, bool immediate) {
-    if (mCurrentState.requestedCrop == crop)
-        return false;
+    if (mCurrentState.requestedCrop == crop) return false;
     mCurrentState.sequence++;
     mCurrentState.requestedCrop = crop;
     if (immediate && !mFreezeGeometryUpdates) {
@@ -1931,8 +1309,7 @@
 }
 
 bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
-    if (mCurrentState.requestedFinalCrop == crop)
-        return false;
+    if (mCurrentState.requestedFinalCrop == crop) return false;
     mCurrentState.sequence++;
     mCurrentState.requestedFinalCrop = crop;
     if (immediate && !mFreezeGeometryUpdates) {
@@ -1946,30 +1323,21 @@
 }
 
 bool Layer::setOverrideScalingMode(int32_t scalingMode) {
-    if (scalingMode == mOverrideScalingMode)
-        return false;
+    if (scalingMode == mOverrideScalingMode) return false;
     mOverrideScalingMode = scalingMode;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
 
-void Layer::setInfo(uint32_t type, uint32_t appId) {
-  mCurrentState.appId = appId;
-  mCurrentState.type = type;
-  mCurrentState.modified = true;
-  setTransactionFlags(eTransactionNeeded);
-}
-
-uint32_t Layer::getEffectiveScalingMode() const {
-    if (mOverrideScalingMode >= 0) {
-      return mOverrideScalingMode;
-    }
-    return mCurrentScalingMode;
+void Layer::setInfo(int32_t type, int32_t appId) {
+    mCurrentState.appId = appId;
+    mCurrentState.type = type;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
 }
 
 bool Layer::setLayerStack(uint32_t layerStack) {
-    if (mCurrentState.layerStack == layerStack)
-        return false;
+    if (mCurrentState.layerStack == layerStack) return false;
     mCurrentState.sequence++;
     mCurrentState.layerStack = layerStack;
     mCurrentState.modified = true;
@@ -1977,20 +1345,6 @@
     return true;
 }
 
-bool Layer::setDataSpace(android_dataspace dataSpace) {
-    if (mCurrentState.dataSpace == dataSpace)
-        return false;
-    mCurrentState.sequence++;
-    mCurrentState.dataSpace = dataSpace;
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-android_dataspace Layer::getDataSpace() const {
-    return mCurrentState.dataSpace;
-}
-
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
@@ -1999,8 +1353,7 @@
     return p->getLayerStack();
 }
 
-void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer,
-        uint64_t frameNumber) {
+void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
     mCurrentState.barrierLayer = barrierLayer;
     mCurrentState.frameNumber = frameNumber;
     // We don't set eTransactionNeeded, because just receiving a deferral
@@ -2012,124 +1365,16 @@
     mCurrentState.modified = false;
 }
 
-void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle,
-        uint64_t frameNumber) {
+void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
     sp<Handle> handle = static_cast<Handle*>(barrierHandle.get());
     deferTransactionUntil(handle->owner.promote(), frameNumber);
 }
 
-void Layer::useSurfaceDamage() {
-    if (mFlinger->mForceFullDamage) {
-        surfaceDamageRegion = Region::INVALID_REGION;
-    } else {
-        surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
-    }
-}
-
-void Layer::useEmptyDamage() {
-    surfaceDamageRegion.clear();
-}
 
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
-bool Layer::shouldPresentNow(const DispSync& dispSync) const {
-    if (mSidebandStreamChanged || mAutoRefresh) {
-        return true;
-    }
-
-    Mutex::Autolock lock(mQueueItemLock);
-    if (mQueueItems.empty()) {
-        return false;
-    }
-    auto timestamp = mQueueItems[0].mTimestamp;
-    nsecs_t expectedPresent =
-            mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
-
-    // Ignore timestamps more than a second in the future
-    bool isPlausible = timestamp < (expectedPresent + s2ns(1));
-    ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
-            "relative to expectedPresent %" PRId64, mName.string(), timestamp,
-            expectedPresent);
-
-    bool isDue = timestamp < expectedPresent;
-    return isDue || !isPlausible;
-}
-
-bool Layer::onPreComposition(nsecs_t refreshStartTime) {
-    if (mBufferLatched) {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
-    }
-    mRefreshPending = false;
-    return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
-}
-
-bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
-        const std::shared_ptr<FenceTime>& presentFence,
-        const CompositorTiming& compositorTiming) {
-    // mFrameLatencyNeeded is true when a new frame was latched for the
-    // composition.
-    if (!mFrameLatencyNeeded)
-        return false;
-
-    // Update mFrameEventHistory.
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
-                glDoneFence, presentFence, compositorTiming);
-    }
-
-    // Update mFrameTracker.
-    nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
-    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
-
-    std::shared_ptr<FenceTime> frameReadyFence =
-            mSurfaceFlingerConsumer->getCurrentFenceTime();
-    if (frameReadyFence->isValid()) {
-        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
-    } else {
-        // There was no fence for this frame, so assume that it was ready
-        // to be presented at the desired present time.
-        mFrameTracker.setFrameReadyTime(desiredPresentTime);
-    }
-
-    if (presentFence->isValid()) {
-        mFrameTracker.setActualPresentFence(
-                std::shared_ptr<FenceTime>(presentFence));
-    } else {
-        // The HWC doesn't support present fences, so use the refresh
-        // timestamp instead.
-        mFrameTracker.setActualPresentTime(
-            mFlinger->getHwComposer().getRefreshTimestamp(
-                HWC_DISPLAY_PRIMARY));
-    }
-
-    mFrameTracker.advanceFrame();
-    mFrameLatencyNeeded = false;
-    return true;
-}
-
-#ifdef USE_HWC2
-void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
-    if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
-        return;
-    }
-
-    auto releaseFenceTime = std::make_shared<FenceTime>(
-            mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
-    mReleaseTimeline.updateSignalTimes();
-    mReleaseTimeline.push(releaseFenceTime);
-
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    if (mPreviousFrameNumber != 0) {
-        mFrameEventHistory.addRelease(mPreviousFrameNumber,
-                dequeueReadyTime, std::move(releaseFenceTime));
-    }
-}
-#endif
-
 bool Layer::isHiddenByPolicy() const {
     const Layer::State& s(mDrawingState);
     const auto& parent = mDrawingParent.promote();
@@ -2139,256 +1384,7 @@
     return s.flags & layer_state_t::eLayerHidden;
 }
 
-bool Layer::isVisible() const {
-#ifdef USE_HWC2
-    return !(isHiddenByPolicy()) && getAlpha() > 0.0f
-            && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#else
-    return !(isHiddenByPolicy()) && getAlpha()
-            && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#endif
-}
-
-bool Layer::allTransactionsSignaled() {
-    auto headFrameNumber = getHeadFrameNumber();
-    bool matchingFramesFound = false;
-    bool allTransactionsApplied = true;
-    Mutex::Autolock lock(mLocalSyncPointMutex);
-
-    for (auto& point : mLocalSyncPoints) {
-        if (point->getFrameNumber() > headFrameNumber) {
-            break;
-        }
-        matchingFramesFound = true;
-
-        if (!point->frameIsAvailable()) {
-           // We haven't notified the remote layer that the frame for
-           // this point is available yet. Notify it now, and then
-           // abort this attempt to latch.
-           point->setFrameAvailable();
-           allTransactionsApplied = false;
-           break;
-        }
-
-        allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
-    }
-    return !matchingFramesFound || allTransactionsApplied;
-}
-
-Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
-{
-    ATRACE_CALL();
-
-    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
-        // mSidebandStreamChanged was true
-        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
-        if (mSidebandStream != NULL) {
-            setTransactionFlags(eTransactionNeeded);
-            mFlinger->setTransactionFlags(eTraversalNeeded);
-        }
-        recomputeVisibleRegions = true;
-
-        const State& s(getDrawingState());
-        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
-    }
-
-    Region outDirtyRegion;
-    if (mQueuedFrames <= 0 && !mAutoRefresh) {
-        return outDirtyRegion;
-    }
-
-    // if we've already called updateTexImage() without going through
-    // a composition step, we have to skip this layer at this point
-    // because we cannot call updateTeximage() without a corresponding
-    // compositionComplete() call.
-    // we'll trigger an update in onPreComposition().
-    if (mRefreshPending) {
-        return outDirtyRegion;
-    }
-
-    // If the head buffer's acquire fence hasn't signaled yet, return and
-    // try again later
-    if (!headFenceHasSignaled()) {
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    }
-
-    // Capture the old state of the layer for comparisons later
-    const State& s(getDrawingState());
-    const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
-
-    if (!allTransactionsSignaled()) {
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    }
-
-    // This boolean is used to make sure that SurfaceFlinger's shadow copy
-    // of the buffer queue isn't modified when the buffer queue is returning
-    // BufferItem's that weren't actually queued. This can happen in shared
-    // buffer mode.
-    bool queuedBuffer = false;
-    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(),
-                    mOverrideScalingMode, mFreezeGeometryUpdates);
-    status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
-            mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
-            mLastFrameNumberReceived);
-    if (updateResult == BufferQueue::PRESENT_LATER) {
-        // Producer doesn't want buffer to be displayed yet.  Signal a
-        // layer update so we check again at the next opportunity.
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
-        // If the buffer has been rejected, remove it from the shadow queue
-        // and return early
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            mQueueItems.removeAt(0);
-            android_atomic_dec(&mQueuedFrames);
-        }
-        return outDirtyRegion;
-    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
-        // This can occur if something goes wrong when trying to create the
-        // EGLImage for this buffer. If this happens, the buffer has already
-        // been released, so we need to clean up the queue and bug out
-        // early.
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            mQueueItems.clear();
-            android_atomic_and(0, &mQueuedFrames);
-        }
-
-        // Once we have hit this state, the shadow queue may no longer
-        // correctly reflect the incoming BufferQueue's contents, so even if
-        // updateTexImage starts working, the only safe course of action is
-        // to continue to ignore updates.
-        mUpdateTexImageFailed = true;
-
-        return outDirtyRegion;
-    }
-
-    if (queuedBuffer) {
-        // Autolock scope
-        auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Remove any stale buffers that have been dropped during
-        // updateTexImage
-        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
-            mQueueItems.removeAt(0);
-            android_atomic_dec(&mQueuedFrames);
-        }
-
-        mQueueItems.removeAt(0);
-    }
-
-
-    // Decrement the queued-frames count.  Signal another event if we
-    // have more frames pending.
-    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
-            || mAutoRefresh) {
-        mFlinger->signalLayerUpdate();
-    }
-
-    // update the active buffer
-    mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(
-            &mActiveBufferSlot);
-    if (mActiveBuffer == NULL) {
-        // this can only happen if the very first buffer was rejected.
-        return outDirtyRegion;
-    }
-
-    mBufferLatched = true;
-    mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-#ifndef USE_HWC2
-        auto releaseFenceTime = std::make_shared<FenceTime>(
-                mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
-        mReleaseTimeline.updateSignalTimes();
-        mReleaseTimeline.push(releaseFenceTime);
-        if (mPreviousFrameNumber != 0) {
-            mFrameEventHistory.addRelease(mPreviousFrameNumber,
-                    latchTime, std::move(releaseFenceTime));
-        }
-#endif
-    }
-
-    mRefreshPending = true;
-    mFrameLatencyNeeded = true;
-    if (oldActiveBuffer == NULL) {
-         // the first time we receive a buffer, we need to trigger a
-         // geometry invalidation.
-        recomputeVisibleRegions = true;
-     }
-
-    setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
-
-    Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
-    const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
-    const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
-    if ((crop != mCurrentCrop) ||
-        (transform != mCurrentTransform) ||
-        (scalingMode != mCurrentScalingMode))
-    {
-        mCurrentCrop = crop;
-        mCurrentTransform = transform;
-        mCurrentScalingMode = scalingMode;
-        recomputeVisibleRegions = true;
-    }
-
-    if (oldActiveBuffer != NULL) {
-        uint32_t bufWidth  = mActiveBuffer->getWidth();
-        uint32_t bufHeight = mActiveBuffer->getHeight();
-        if (bufWidth != uint32_t(oldActiveBuffer->width) ||
-            bufHeight != uint32_t(oldActiveBuffer->height)) {
-            recomputeVisibleRegions = true;
-        }
-    }
-
-    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
-    if (oldOpacity != isOpaque(s)) {
-        recomputeVisibleRegions = true;
-    }
-
-    // Remove any sync points corresponding to the buffer which was just
-    // latched
-    {
-        Mutex::Autolock lock(mLocalSyncPointMutex);
-        auto point = mLocalSyncPoints.begin();
-        while (point != mLocalSyncPoints.end()) {
-            if (!(*point)->frameIsAvailable() ||
-                    !(*point)->transactionIsApplied()) {
-                // This sync point must have been added since we started
-                // latching. Don't drop it yet.
-                ++point;
-                continue;
-            }
-
-            if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
-                point = mLocalSyncPoints.erase(point);
-            } else {
-                ++point;
-            }
-        }
-    }
-
-    // FIXME: postedRegion should be dirty & bounds
-    Region dirtyRegion(Rect(s.active.w, s.active.h));
-
-    // transform the dirty region to window-manager space
-    outDirtyRegion = (getTransform().transform(dirtyRegion));
-
-    return outDirtyRegion;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const
-{
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const {
     // TODO: should we do something special if mSecure is set?
     if (mProtectedByApp) {
         // need a hardware-protected path to external video sink
@@ -2413,79 +1409,60 @@
             orientation = 0;
         }
     }
-    mSurfaceFlingerConsumer->setTransformHint(orientation);
+    setTransformHint(orientation);
 }
 
 // ----------------------------------------------------------------------------
 // debugging
 // ----------------------------------------------------------------------------
 
-void Layer::dump(String8& result, Colorizer& colorizer) const
-{
-    const Layer::State& s(getDrawingState());
-
-    colorizer.colorize(result, Colorizer::GREEN);
-    result.appendFormat(
-            "+ %s %p (%s)\n",
-            getTypeId(), this, getName().string());
-    colorizer.reset(result);
-
-    s.activeTransparentRegion.dump(result, "transparentRegion");
-    visibleRegion.dump(result, "visibleRegion");
-    surfaceDamageRegion.dump(result, "surfaceDamageRegion");
-    sp<Client> client(mClientRef.promote());
-    PixelFormat pf = PIXEL_FORMAT_UNKNOWN;
-    const sp<GraphicBuffer>& buffer(getActiveBuffer());
-    if (buffer != NULL) {
-        pf = buffer->getPixelFormat();
+LayerDebugInfo Layer::getLayerDebugInfo() const {
+    LayerDebugInfo info;
+    const Layer::State& ds = getDrawingState();
+    info.mName = getName();
+    sp<Layer> parent = getParent();
+    info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
+    info.mType = String8(getTypeId());
+    info.mTransparentRegion = ds.activeTransparentRegion;
+    info.mVisibleRegion = visibleRegion;
+    info.mSurfaceDamageRegion = surfaceDamageRegion;
+    info.mLayerStack = getLayerStack();
+    info.mX = ds.active.transform.tx();
+    info.mY = ds.active.transform.ty();
+    info.mZ = ds.z;
+    info.mWidth = ds.active.w;
+    info.mHeight = ds.active.h;
+    info.mCrop = ds.crop;
+    info.mFinalCrop = ds.finalCrop;
+    info.mColor = ds.color;
+    info.mFlags = ds.flags;
+    info.mPixelFormat = getPixelFormat();
+    info.mDataSpace = static_cast<android_dataspace>(mCurrentDataSpace);
+    info.mMatrix[0][0] = ds.active.transform[0][0];
+    info.mMatrix[0][1] = ds.active.transform[0][1];
+    info.mMatrix[1][0] = ds.active.transform[1][0];
+    info.mMatrix[1][1] = ds.active.transform[1][1];
+    {
+        sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
+        if (buffer != 0) {
+            info.mActiveBufferWidth = buffer->getWidth();
+            info.mActiveBufferHeight = buffer->getHeight();
+            info.mActiveBufferStride = buffer->getStride();
+            info.mActiveBufferFormat = buffer->format;
+        } else {
+            info.mActiveBufferWidth = 0;
+            info.mActiveBufferHeight = 0;
+            info.mActiveBufferStride = 0;
+            info.mActiveBufferFormat = 0;
+        }
     }
-
-    result.appendFormat(            "      "
-            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
-            "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
-            "isOpaque=%1d, invalidate=%1d, "
-            "dataspace=%s, pixelformat=%s "
-#ifdef USE_HWC2
-            "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#else
-            "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
-#endif
-            "      client=%p\n",
-            getLayerStack(), s.z,
-            s.active.transform.tx(), s.active.transform.ty(),
-            s.active.w, s.active.h,
-            s.crop.left, s.crop.top,
-            s.crop.right, s.crop.bottom,
-            s.finalCrop.left, s.finalCrop.top,
-            s.finalCrop.right, s.finalCrop.bottom,
-            isOpaque(s), contentDirty,
-            dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(),
-            s.alpha, s.flags,
-            s.active.transform[0][0], s.active.transform[0][1],
-            s.active.transform[1][0], s.active.transform[1][1],
-            client.get());
-
-    sp<const GraphicBuffer> buf0(mActiveBuffer);
-    uint32_t w0=0, h0=0, s0=0, f0=0;
-    if (buf0 != 0) {
-        w0 = buf0->getWidth();
-        h0 = buf0->getHeight();
-        s0 = buf0->getStride();
-        f0 = buf0->format;
-    }
-    result.appendFormat(
-            "      "
-            "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " queued-frames=%d, mRefreshPending=%d\n",
-            mFormat, w0, h0, s0,f0,
-            mQueuedFrames, mRefreshPending);
-
-    if (mSurfaceFlingerConsumer != 0) {
-        mSurfaceFlingerConsumer->dumpState(result, "            ");
-    }
+    info.mNumQueuedFrames = getQueuedFrameCount();
+    info.mRefreshPending = isBufferLatched();
+    info.mIsOpaque = isOpaque(ds);
+    info.mContentDirty = contentDirty;
+    return info;
 }
 
-#ifdef USE_HWC2
 void Layer::miniDumpHeader(String8& result) {
     result.append("----------------------------------------");
     result.append("---------------------------------------\n");
@@ -2499,7 +1476,7 @@
 }
 
 void Layer::miniDump(String8& result, int32_t hwcId) const {
-    if (mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(hwcId) == 0) {
         return;
     }
 
@@ -2517,21 +1494,21 @@
     result.appendFormat(" %s\n", name.string());
 
     const Layer::State& layerState(getDrawingState());
-    const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
-    result.appendFormat("  %10u | ", layerState.z);
-    result.appendFormat("%10s | ",
-            to_string(getCompositionType(hwcId)).c_str());
+    const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId);
+    if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
+        result.appendFormat("  rel %6d | ", layerState.z);
+    } else {
+        result.appendFormat("  %10d | ", layerState.z);
+    }
+    result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str());
     const Rect& frame = hwcInfo.displayFrame;
-    result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top,
-            frame.right, frame.bottom);
+    result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
     const FloatRect& crop = hwcInfo.sourceCrop;
-    result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top,
-            crop.right, crop.bottom);
+    result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
 
     result.append("- - - - - - - - - - - - - - - - - - - - ");
     result.append("- - - - - - - - - - - - - - - - - - - -\n");
 }
-#endif
 
 void Layer::dumpFrameStats(String8& result) const {
     mFrameTracker.dumpStats(result);
@@ -2550,8 +1527,7 @@
 }
 
 void Layer::dumpFrameEvents(String8& result) {
-    result.appendFormat("- Layer %s (%s, %p)\n",
-            getName().string(), getTypeId(), this);
+    result.appendFormat("- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this);
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.checkFencesForCompletion();
     mFrameEventHistory.dump(result);
@@ -2560,10 +1536,16 @@
 void Layer::onDisconnect() {
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.onDisconnect();
+    mTimeStats.onDisconnect(getName().c_str());
 }
 
 void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
-        FrameEventHistoryDelta *outDelta) {
+                                     FrameEventHistoryDelta* outDelta) {
+    if (newTimestamps) {
+        mTimeStats.setPostTime(getName().c_str(), newTimestamps->frameNumber,
+                               newTimestamps->postedTime);
+    }
+
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     if (newTimestamps) {
         // If there are any unsignaled fences in the aquire timeline at this
@@ -2581,23 +1563,6 @@
     }
 }
 
-std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
-        bool forceFlush) {
-    std::vector<OccupancyTracker::Segment> history;
-    status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush,
-            &history);
-    if (result != NO_ERROR) {
-        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(),
-                result);
-        return {};
-    }
-    return history;
-}
-
-bool Layer::getTransformToDisplayInverse() const {
-    return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
-}
-
 size_t Layer::getChildrenCount() const {
     size_t count = 0;
     for (const sp<Layer>& child : mCurrentChildren) {
@@ -2634,7 +1599,7 @@
 
         sp<Client> client(child->mClientRef.promote());
         if (client != nullptr) {
-            client->setParentLayer(newParent);
+            client->updateParent(newParent);
         }
     }
     mCurrentChildren.clear();
@@ -2642,21 +1607,59 @@
     return true;
 }
 
-bool Layer::detachChildren() {
-    traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) {
-        if (child == this) {
-            return;
-        }
+void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->mDrawingParent = newParent;
+    }
+}
 
-        sp<Client> client(child->mClientRef.promote());
-        if (client != nullptr) {
-            client->detachLayer(child);
-        }
-    });
+bool Layer::reparent(const sp<IBinder>& newParentHandle) {
+    if (newParentHandle == nullptr) {
+        return false;
+    }
+
+    auto handle = static_cast<Handle*>(newParentHandle.get());
+    sp<Layer> newParent = handle->owner.promote();
+    if (newParent == nullptr) {
+        ALOGE("Unable to promote Layer handle");
+        return false;
+    }
+
+    sp<Layer> parent = getParent();
+    if (parent != nullptr) {
+        parent->removeChild(this);
+    }
+    newParent->addChild(this);
+
+    sp<Client> client(mClientRef.promote());
+    sp<Client> newParentClient(newParent->mClientRef.promote());
+
+    if (client != newParentClient) {
+        client->updateParent(newParent);
+    }
 
     return true;
 }
 
+bool Layer::detachChildren() {
+    for (const sp<Layer>& child : mCurrentChildren) {
+        sp<Client> parentClient = mClientRef.promote();
+        sp<Client> client(child->mClientRef.promote());
+        if (client != nullptr && parentClient != client) {
+            client->detachLayer(child.get());
+            child->detachChildren();
+        }
+    }
+
+    return true;
+}
+
+bool Layer::isLegacyDataSpace() const {
+    // return true when no higher bits are set
+    return !(mCurrentDataSpace & (ui::Dataspace::STANDARD_MASK |
+                ui::Dataspace::TRANSFER_MASK | ui::Dataspace::RANGE_MASK));
+}
+
 void Layer::setParent(const sp<Layer>& layer) {
     mCurrentParent = layer;
 }
@@ -2677,7 +1680,14 @@
     return mDrawingState.z;
 }
 
-LayerVector Layer::makeTraversalList(LayerVector::StateSet stateSet) {
+bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) {
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const State& state = useDrawing ? mDrawingState : mCurrentState;
+    return state.zOrderRelativeOf != nullptr;
+}
+
+__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
+        LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) {
     LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
                         "makeTraversalList received invalid stateSet");
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
@@ -2685,10 +1695,11 @@
     const State& state = useDrawing ? mDrawingState : mCurrentState;
 
     if (state.zOrderRelatives.size() == 0) {
+        *outSkipRelativeZUsers = true;
         return children;
     }
-    LayerVector traverse;
 
+    LayerVector traverse(stateSet);
     for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
         sp<Layer> strongRelative = weakRelative.promote();
         if (strongRelative != nullptr) {
@@ -2697,6 +1708,10 @@
     }
 
     for (const sp<Layer>& child : children) {
+        const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
+        if (childState.zOrderRelativeOf != nullptr) {
+            continue;
+        }
         traverse.add(child);
     }
 
@@ -2707,19 +1722,35 @@
  * Negatively signed relatives are before 'this' in Z-order.
  */
 void Layer::traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor) {
-    LayerVector list = makeTraversalList(stateSet);
+    // In the case we have other layers who are using a relative Z to us, makeTraversalList will
+    // produce a new list for traversing, including our relatives, and not including our children
+    // who are relatives of another surface. In the case that there are no relative Z,
+    // makeTraversalList returns our children directly to avoid significant overhead.
+    // However in this case we need to take the responsibility for filtering children which
+    // are relatives of another surface here.
+    bool skipRelativeZUsers = false;
+    const LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers);
 
     size_t i = 0;
     for (; i < list.size(); i++) {
         const auto& relative = list[i];
+        if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
+            continue;
+        }
+
         if (relative->getZ() >= 0) {
             break;
         }
         relative->traverseInZOrder(stateSet, visitor);
     }
+
     visitor(this);
     for (; i < list.size(); i++) {
         const auto& relative = list[i];
+
+        if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
+            continue;
+        }
         relative->traverseInZOrder(stateSet, visitor);
     }
 }
@@ -2729,23 +1760,110 @@
  */
 void Layer::traverseInReverseZOrder(LayerVector::StateSet stateSet,
                                     const LayerVector::Visitor& visitor) {
-    LayerVector list = makeTraversalList(stateSet);
+    // See traverseInZOrder for documentation.
+    bool skipRelativeZUsers = false;
+    LayerVector list = makeTraversalList(stateSet, &skipRelativeZUsers);
 
     int32_t i = 0;
-    for (i = list.size()-1; i>=0; i--) {
+    for (i = int32_t(list.size()) - 1; i >= 0; i--) {
         const auto& relative = list[i];
+
+        if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
+            continue;
+        }
+
         if (relative->getZ() < 0) {
             break;
         }
         relative->traverseInReverseZOrder(stateSet, visitor);
     }
     visitor(this);
-    for (; i>=0; i--) {
+    for (; i >= 0; i--) {
         const auto& relative = list[i];
+
+        if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
+            continue;
+        }
+
         relative->traverseInReverseZOrder(stateSet, visitor);
     }
 }
 
+LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet,
+                                             const std::vector<Layer*>& layersInTree) {
+    LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
+                        "makeTraversalList received invalid stateSet");
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+    const State& state = useDrawing ? mDrawingState : mCurrentState;
+
+    LayerVector traverse(stateSet);
+    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+        sp<Layer> strongRelative = weakRelative.promote();
+        // Only add relative layers that are also descendents of the top most parent of the tree.
+        // If a relative layer is not a descendent, then it should be ignored.
+        if (std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
+            traverse.add(strongRelative);
+        }
+    }
+
+    for (const sp<Layer>& child : children) {
+        const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
+        // If a layer has a relativeOf layer, only ignore if the layer it's relative to is a
+        // descendent of the top most parent of the tree. If it's not a descendent, then just add
+        // the child here since it won't be added later as a relative.
+        if (std::binary_search(layersInTree.begin(), layersInTree.end(),
+                               childState.zOrderRelativeOf.promote().get())) {
+            continue;
+        }
+        traverse.add(child);
+    }
+
+    return traverse;
+}
+
+void Layer::traverseChildrenInZOrderInner(const std::vector<Layer*>& layersInTree,
+                                          LayerVector::StateSet stateSet,
+                                          const LayerVector::Visitor& visitor) {
+    const LayerVector list = makeChildrenTraversalList(stateSet, layersInTree);
+
+    size_t i = 0;
+    for (; i < list.size(); i++) {
+        const auto& relative = list[i];
+        if (relative->getZ() >= 0) {
+            break;
+        }
+        relative->traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
+    }
+
+    visitor(this);
+    for (; i < list.size(); i++) {
+        const auto& relative = list[i];
+        relative->traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
+    }
+}
+
+std::vector<Layer*> Layer::getLayersInTree(LayerVector::StateSet stateSet) {
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+
+    std::vector<Layer*> layersInTree = {this};
+    for (size_t i = 0; i < children.size(); i++) {
+        const auto& child = children[i];
+        std::vector<Layer*> childLayers = child->getLayersInTree(stateSet);
+        layersInTree.insert(layersInTree.end(), childLayers.cbegin(), childLayers.cend());
+    }
+
+    return layersInTree;
+}
+
+void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+                                     const LayerVector::Visitor& visitor) {
+    std::vector<Layer*> layersInTree = getLayersInTree(stateSet);
+    std::sort(layersInTree.begin(), layersInTree.end());
+    traverseChildrenInZOrderInner(layersInTree, stateSet, visitor);
+}
+
 Transform Layer::getTransform() const {
     Transform t;
     const auto& p = mDrawingParent.promote();
@@ -2757,20 +1875,18 @@
         // for in the transform. We need to mirror this scaling in child surfaces
         // or we will break the contract where WM can treat child surfaces as
         // pixels in the parent surface.
-        if (p->isFixedSize() && p->mActiveBuffer != nullptr) {
+        if (p->isFixedSize() && p->getBE().compositionInfo.mBuffer != nullptr) {
             int bufferWidth;
             int bufferHeight;
             if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
-                bufferWidth = p->mActiveBuffer->getWidth();
-                bufferHeight = p->mActiveBuffer->getHeight();
+                bufferWidth = p->getBE().compositionInfo.mBuffer->getWidth();
+                bufferHeight = p->getBE().compositionInfo.mBuffer->getHeight();
             } else {
-                bufferHeight = p->mActiveBuffer->getWidth();
-                bufferWidth = p->mActiveBuffer->getHeight();
+                bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
+                bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
             }
-            float sx = p->getDrawingState().active.w /
-                    static_cast<float>(bufferWidth);
-            float sy = p->getDrawingState().active.h /
-                    static_cast<float>(bufferHeight);
+            float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
+            float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
             Transform extraParentScaling;
             extraParentScaling.set(sx, 0, 0, sy);
             t = t * extraParentScaling;
@@ -2779,23 +1895,17 @@
     return t * getDrawingState().active.transform;
 }
 
-#ifdef USE_HWC2
-float Layer::getAlpha() const {
+half Layer::getAlpha() const {
     const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
-    return parentAlpha * getDrawingState().alpha;
+    half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
+    return parentAlpha * getDrawingState().color.a;
 }
-#else
-uint8_t Layer::getAlpha() const {
-    const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
-    float drawingAlpha = getDrawingState().alpha / 255.0f;
-    drawingAlpha = drawingAlpha * parentAlpha;
-    return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+half4 Layer::getColor() const {
+    const half4 color(getDrawingState().color);
+    return half4(color.r, color.g, color.b, getAlpha());
 }
-#endif
 
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
@@ -2806,6 +1916,123 @@
     mDrawingParent = mCurrentParent;
 }
 
+void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+    const State& state = useDrawing ? mDrawingState : mCurrentState;
+
+    Transform requestedTransform = state.active.transform;
+    Transform transform = getTransform();
+
+    layerInfo->set_id(sequence);
+    layerInfo->set_name(getName().c_str());
+    layerInfo->set_type(String8(getTypeId()));
+
+    for (const auto& child : children) {
+        layerInfo->add_children(child->sequence);
+    }
+
+    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+        sp<Layer> strongRelative = weakRelative.promote();
+        if (strongRelative != nullptr) {
+            layerInfo->add_relatives(strongRelative->sequence);
+        }
+    }
+
+    LayerProtoHelper::writeToProto(state.activeTransparentRegion,
+                                   layerInfo->mutable_transparent_region());
+    LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
+    LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
+
+    layerInfo->set_layer_stack(getLayerStack());
+    layerInfo->set_z(state.z);
+
+    PositionProto* position = layerInfo->mutable_position();
+    position->set_x(transform.tx());
+    position->set_y(transform.ty());
+
+    PositionProto* requestedPosition = layerInfo->mutable_requested_position();
+    requestedPosition->set_x(requestedTransform.tx());
+    requestedPosition->set_y(requestedTransform.ty());
+
+    SizeProto* size = layerInfo->mutable_size();
+    size->set_w(state.active.w);
+    size->set_h(state.active.h);
+
+    LayerProtoHelper::writeToProto(state.crop, layerInfo->mutable_crop());
+    LayerProtoHelper::writeToProto(state.finalCrop, layerInfo->mutable_final_crop());
+
+    layerInfo->set_is_opaque(isOpaque(state));
+    layerInfo->set_invalidate(contentDirty);
+
+    // XXX (b/79210409) mCurrentDataSpace is not protected
+    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+
+    layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
+    LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
+    LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
+    layerInfo->set_flags(state.flags);
+
+    LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+    LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform());
+
+    auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+    if (parent != nullptr) {
+        layerInfo->set_parent(parent->sequence);
+    }
+
+    auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
+    if (zOrderRelativeOf != nullptr) {
+        layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+    }
+
+    // XXX getBE().compositionInfo.mBuffer is not protected
+    auto buffer = getBE().compositionInfo.mBuffer;
+    if (buffer != nullptr) {
+        LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+    }
+
+    layerInfo->set_queued_frames(getQueuedFrameCount());
+    layerInfo->set_refresh_pending(isBufferLatched());
+    layerInfo->set_window_type(state.type);
+    layerInfo->set_app_id(state.appId);
+    layerInfo->set_curr_frame(mCurrentFrameNumber);
+
+    for (const auto& pendingState : mPendingStates) {
+        auto barrierLayer = pendingState.barrierLayer.promote();
+        if (barrierLayer != nullptr) {
+            BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+            barrierLayerProto->set_id(barrierLayer->sequence);
+            barrierLayerProto->set_frame_number(pendingState.frameNumber);
+        }
+    }
+}
+
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+    const Rect& frame = hwcInfo.displayFrame;
+    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+    const FloatRect& crop = hwcInfo.sourceCrop;
+    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    layerInfo->set_hwc_transform(transform);
+
+    const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType);
+    layerInfo->set_hwc_composition_type(compositionType);
+
+    if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
+        static_cast<BufferLayer*>(this)->isProtected()) {
+        layerInfo->set_is_protected(true);
+    } else {
+        layerInfo->set_is_protected(false);
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c34d8a0..2239679 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,40 +17,45 @@
 #ifndef ANDROID_LAYER_H
 #define ANDROID_LAYER_H
 
-#include <stdint.h>
 #include <sys/types.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include <ui/FloatRect.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
+#include <gui/BufferQueue.h>
 
 #include <list>
+#include <cstdint>
 
-#include "FrameTracker.h"
 #include "Client.h"
+#include "FrameTracker.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConsumer.h"
+#include "TimeStats/TimeStats.h"
 #include "Transform.h"
 
+#include <layerproto/LayerProtoHeader.h>
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/HWComposerBufferCache.h"
+#include "RenderArea.h"
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 
+#include <math/vec4.h>
+#include <vector>
+
+using namespace android::surfaceflinger;
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -60,20 +65,85 @@
 class DisplayDevice;
 class GraphicBuffer;
 class SurfaceFlinger;
+class LayerDebugInfo;
+class LayerBE;
+
+namespace impl {
+class SurfaceInterceptor;
+}
 
 // ---------------------------------------------------------------------------
 
-/*
- * A new BufferQueue and a new SurfaceFlingerConsumer are created when the
- * Layer is first referenced.
- *
- * This also implements onFrameAvailable(), which notifies SurfaceFlinger
- * that new data has arrived.
- */
-class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
+struct CompositionInfo {
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    struct {
+        HWComposer* hwc;
+        sp<Fence> fence;
+        HWC2::BlendMode blendMode;
+        Rect displayFrame;
+        float alpha;
+        FloatRect sourceCrop;
+        HWC2::Transform transform;
+        int z;
+        int type;
+        int appId;
+        Region visibleRegion;
+        Region surfaceDamage;
+        sp<NativeHandle> sidebandStream;
+        android_dataspace dataspace;
+        hwc_color_t color;
+    } hwc;
+    struct {
+        RE::RenderEngine* renderEngine;
+        Mesh* mesh;
+    } renderEngine;
+};
+
+class LayerBE {
+public:
+    LayerBE();
+
+    // The mesh used to draw the layer in GLES composition mode
+    Mesh mMesh;
+
+    // HWC items, accessed from the main thread
+    struct HWCInfo {
+        HWCInfo()
+              : hwc(nullptr),
+                layer(nullptr),
+                forceClientComposition(false),
+                compositionType(HWC2::Composition::Invalid),
+                clearClientTarget(false),
+                transform(HWC2::Transform::None) {}
+
+        HWComposer* hwc;
+        HWC2::Layer* layer;
+        bool forceClientComposition;
+        HWC2::Composition compositionType;
+        bool clearClientTarget;
+        Rect displayFrame;
+        FloatRect sourceCrop;
+        HWComposerBufferCache bufferCache;
+        HWC2::Transform transform;
+    };
+
+    // A layer can be attached to multiple displays when operating in mirror mode
+    // (a.k.a: when several displays are attached with equal layerStack). In this
+    // case we need to keep track. In non-mirror mode, a layer will have only one
+    // HWCInfo. This map key is a display layerStack.
+    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+    CompositionInfo compositionInfo;
+};
+
+class Layer : public virtual RefBase {
     static int32_t sSequence;
 
 public:
+    LayerBE& getBE() { return mBE; }
+    LayerBE& getBE() const { return mBE; }
     mutable bool contentDirty;
     // regions below are in window-manager space
     Region visibleRegion;
@@ -96,14 +166,11 @@
         uint32_t h;
         Transform transform;
 
-        inline bool operator ==(const Geometry& rhs) const {
-            return (w == rhs.w && h == rhs.h) &&
-                    (transform.tx() == rhs.transform.tx()) &&
+        inline bool operator==(const Geometry& rhs) const {
+            return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
                     (transform.ty() == rhs.transform.ty());
         }
-        inline bool operator !=(const Geometry& rhs) const {
-            return !operator ==(rhs);
-        }
+        inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
     };
 
     struct State {
@@ -118,13 +185,7 @@
         // to achieve mirroring.
         uint32_t layerStack;
 
-#ifdef USE_HWC2
-        float alpha;
-#else
-        uint8_t alpha;
-#endif
         uint8_t flags;
-        uint8_t mask;
         uint8_t reserved[2];
         int32_t sequence; // changes when visible regions can change
         bool modified;
@@ -147,30 +208,25 @@
         // dependent.
         Region activeTransparentRegion;
         Region requestedTransparentRegion;
-        android_dataspace dataSpace;
 
-        uint32_t appId;
-        uint32_t type;
+        int32_t appId;
+        int32_t type;
 
         // If non-null, a Surface this Surface's Z-order is interpreted relative to.
         wp<Layer> zOrderRelativeOf;
 
         // A list of surfaces whose Z-order is interpreted relative to ours.
         SortedVector<wp<Layer>> zOrderRelatives;
+
+        half4 color;
     };
 
-    // -----------------------------------------------------------------------
-
-    Layer(SurfaceFlinger* flinger, const sp<Client>& client,
-            const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-
+    Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+          uint32_t h, uint32_t flags);
     virtual ~Layer();
 
     void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
 
-    // the this layer's size and format
-    status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
-
     // ------------------------------------------------------------------------
     // Geometry setting functions.
     //
@@ -202,7 +258,7 @@
     // Set a 2x2 transformation matrix on the layer. This transform
     // will be applied after parent transforms, but before any final
     // producer specified transform.
-    bool setMatrix(const layer_state_t::matrix22_t& matrix);
+    bool setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms);
 
     // This second set of geometry attributes are controlled by
     // setGeometryAppliesWithResize, and their default mode is to be
@@ -224,29 +280,35 @@
     bool setLayer(int32_t z);
     bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
 
-#ifdef USE_HWC2
     bool setAlpha(float alpha);
-#else
-    bool setAlpha(uint8_t alpha);
-#endif
+    bool setColor(const half3& color);
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setLayerStack(uint32_t layerStack);
-    bool setDataSpace(android_dataspace dataSpace);
-    android_dataspace getDataSpace() const;
     uint32_t getLayerStack() const;
     void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
     void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
     bool setOverrideScalingMode(int32_t overrideScalingMode);
-    void setInfo(uint32_t type, uint32_t appId);
+    void setInfo(int32_t type, int32_t appId);
     bool reparentChildren(const sp<IBinder>& layer);
+    void setChildrenDrawingParent(const sp<Layer>& layer);
+    bool reparent(const sp<IBinder>& newParentHandle);
     bool detachChildren();
 
+    ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
+
+    // Before color management is introduced, contents on Android have to be
+    // desaturated in order to match what they appears like visually.
+    // With color management, these contents will appear desaturated, thus
+    // needed to be saturated so that they match what they are designed for
+    // visually.
+    bool isLegacyDataSpace() const;
+
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
     // one empty rect.
-    void useSurfaceDamage();
-    void useEmptyDamage();
+    virtual void useSurfaceDamage() {}
+    virtual void useEmptyDamage() {}
 
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
@@ -255,17 +317,15 @@
         return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
     }
 
-    void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
-            bool useIdentityTransform) const;
-    Rect computeBounds(const Region& activeTransparentRegion) const;
-    Rect computeBounds() const;
+    void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
+    FloatRect computeBounds(const Region& activeTransparentRegion) const;
+    FloatRect computeBounds() const;
 
     int32_t getSequence() const { return sequence; }
 
     // -----------------------------------------------------------------------
     // Virtuals
-
-    virtual const char* getTypeId() const { return "Layer"; }
+    virtual const char* getTypeId() const = 0;
 
     /*
      * isOpaque - true if this surface is opaque
@@ -274,24 +334,18 @@
      * pixel format includes an alpha channel) and the "opaque" flag set
      * on the layer.  It does not examine the current plane alpha value.
      */
-    virtual bool isOpaque(const Layer::State& s) const;
+    virtual bool isOpaque(const Layer::State&) const { return false; }
 
     /*
      * isSecure - true if this surface is secure, that is if it prevents
      * screenshots or VNC servers.
      */
-    virtual bool isSecure() const;
-
-    /*
-     * isProtected - true if the layer may contain protected content in the
-     * GRALLOC_USAGE_PROTECTED sense.
-     */
-    virtual bool isProtected() const;
+    bool isSecure() const;
 
     /*
      * isVisible - true if this layer is visible, false otherwise
      */
-    virtual bool isVisible() const;
+    virtual bool isVisible() const = 0;
 
     /*
      * isHiddenByPolicy - true if this layer has been forced invisible.
@@ -299,87 +353,88 @@
      * For example if this layer has no active buffer, it may not be hidden by
      * policy, but it still can not be visible.
      */
-    virtual bool isHiddenByPolicy() const;
+    bool isHiddenByPolicy() const;
 
     /*
      * isFixedSize - true if content has a fixed size
      */
-    virtual bool isFixedSize() const;
+    virtual bool isFixedSize() const { return true; }
+
+    // Most layers aren't created from the main thread, and therefore need to
+    // grab the SF state lock to access HWC, but ContainerLayer does, so we need
+    // to avoid grabbing the lock again to avoid deadlock
+    virtual bool isCreatedFromMainThread() const { return false; }
+
+
+    bool isPendingRemoval() const { return mPendingRemoval; }
+
+    void writeToProto(LayerProto* layerInfo,
+                      LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
+
+    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
 
 protected:
     /*
      * onDraw - draws the surface.
      */
-    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-            bool useIdentityTransform) const;
+    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+                        bool useIdentityTransform) const = 0;
 
 public:
-    // -----------------------------------------------------------------------
+    virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
 
-#ifdef USE_HWC2
+    virtual bool isHdrY410() const { return false; }
+
     void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
     void forceClientComposition(int32_t hwcId);
-    void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
+    bool getForceClientComposition(int32_t hwcId);
+    virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
-    void setCompositionType(int32_t hwcId, HWC2::Composition type,
-            bool callIntoHwc = true);
+    void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true);
     HWC2::Composition getCompositionType(int32_t hwcId) const;
-
     void setClearClientTarget(int32_t hwcId, bool clear);
     bool getClearClientTarget(int32_t hwcId) const;
-
     void updateCursorPosition(const sp<const DisplayDevice>& hw);
-#else
-    void setGeometry(const sp<const DisplayDevice>& hw,
-            HWComposer::HWCLayerInterface& layer);
-    void setPerFrameData(const sp<const DisplayDevice>& hw,
-            HWComposer::HWCLayerInterface& layer);
-    void setAcquireFence(const sp<const DisplayDevice>& hw,
-            HWComposer::HWCLayerInterface& layer);
-
-    Rect getPosition(const sp<const DisplayDevice>& hw);
-#endif
 
     /*
      * called after page-flip
      */
-#ifdef USE_HWC2
-    void onLayerDisplayed(const sp<Fence>& releaseFence);
-#else
-    void onLayerDisplayed(const sp<const DisplayDevice>& hw,
-            HWComposer::HWCLayerInterface* layer);
-#endif
+    virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
 
-    bool shouldPresentNow(const DispSync& dispSync) const;
+    virtual void abandon() {}
+
+    virtual bool shouldPresentNow(const DispSync& /*dispSync*/) const { return false; }
+    virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
     /*
      * called before composition.
      * returns true if the layer has pending updates.
      */
-    bool onPreComposition(nsecs_t refreshStartTime);
+    virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
 
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
-            const std::shared_ptr<FenceTime>& presentFence,
-            const CompositorTiming& compositorTiming);
+    virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+                                   const std::shared_ptr<FenceTime>& /*presentFence*/,
+                                   const CompositorTiming& /*compositorTiming*/) {
+        return false;
+    }
 
-#ifdef USE_HWC2
     // If a buffer was replaced this frame, release the former buffer
-    void releasePendingBuffer(nsecs_t dequeueReadyTime);
-#endif
+    virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+
 
     /*
      * draw - performs some global clipping optimizations
      * and calls onDraw().
      */
-    void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
-    void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const;
-    void draw(const sp<const DisplayDevice>& hw) const;
+    void draw(const RenderArea& renderArea, const Region& clip) const;
+    void draw(const RenderArea& renderArea, bool useIdentityTransform) const;
+    void draw(const RenderArea& renderArea) const;
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -404,8 +459,12 @@
      * setVisibleNonTransparentRegion - called when the visible and
      * non-transparent region changes.
      */
-    void setVisibleNonTransparentRegion(const Region&
-            visibleNonTransparentRegion);
+    void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion);
+
+    /*
+     * Clear the visible, covered, and non-transparent regions.
+     */
+    void clearVisibilityRegions();
 
     /*
      * latchBuffer - called each time the screen is redrawn and returns whether
@@ -413,11 +472,13 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
-    bool isBufferLatched() const { return mRefreshPending; }
+    virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
+        return {};
+    }
 
-    bool isPotentialCursor() const { return mPotentialCursor;}
+    virtual bool isBufferLatched() const { return false; }
 
+    bool isPotentialCursor() const { return mPotentialCursor; }
     /*
      * called with the state lock from a binder thread when the layer is
      * removed from the current list to the pending removal list
@@ -430,7 +491,6 @@
      */
     void onRemoved();
 
-
     // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
     void updateTransformHint(const sp<const DisplayDevice>& hw) const;
@@ -444,77 +504,80 @@
     /*
      * Returns if a frame is queued.
      */
-    bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
-            mSidebandStreamChanged || mAutoRefresh; }
+    bool hasQueuedFrame() const {
+        return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
+    }
 
-#ifdef USE_HWC2
+    int32_t getQueuedFrameCount() const { return mQueuedFrames; }
+
     // -----------------------------------------------------------------------
 
     bool createHwcLayer(HWComposer* hwc, int32_t hwcId);
-    void destroyHwcLayer(int32_t hwcId);
+    bool destroyHwcLayer(int32_t hwcId);
     void destroyAllHwcLayers();
 
     bool hasHwcLayer(int32_t hwcId) {
-        return mHwcLayers.count(hwcId) > 0;
+        return getBE().mHwcLayers.count(hwcId) > 0;
     }
 
     HWC2::Layer* getHwcLayer(int32_t hwcId) {
-        if (mHwcLayers.count(hwcId) == 0) {
+        if (getBE().mHwcLayers.count(hwcId) == 0) {
             return nullptr;
         }
-        return mHwcLayers[hwcId].layer;
+        return getBE().mHwcLayers[hwcId].layer;
     }
 
-#endif
     // -----------------------------------------------------------------------
 
-    void clearWithOpenGL(const sp<const DisplayDevice>& hw) const;
+    void clearWithOpenGL(const RenderArea& renderArea) const;
     void setFiltering(bool filtering);
     bool getFiltering() const;
 
-    // only for debugging
-    inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
-    inline  const State&    getDrawingState() const { return mDrawingState; }
-    inline  const State&    getCurrentState() const { return mCurrentState; }
-    inline  State&          getCurrentState()       { return mCurrentState; }
+    inline const State& getDrawingState() const { return mDrawingState; }
+    inline const State& getCurrentState() const { return mCurrentState; }
+    inline State& getCurrentState() { return mCurrentState; }
 
+    LayerDebugInfo getLayerDebugInfo() const;
 
     /* always call base class first */
-    void dump(String8& result, Colorizer& colorizer) const;
-#ifdef USE_HWC2
     static void miniDumpHeader(String8& result);
     void miniDump(String8& result, int32_t hwcId) const;
-#endif
     void dumpFrameStats(String8& result) const;
     void dumpFrameEvents(String8& result);
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
-    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
+    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
+        return {};
+    }
 
     void onDisconnect();
     void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
-            FrameEventHistoryDelta* outDelta);
+                                  FrameEventHistoryDelta* outDelta);
 
-    bool getTransformToDisplayInverse() const;
+    virtual bool getTransformToDisplayInverse() const { return false; }
 
     Transform getTransform() const;
 
     // Returns the Alpha of the Surface, accounting for the Alpha
     // of parent Surfaces in the hierarchy (alpha's will be multiplied
     // down the hierarchy).
-#ifdef USE_HWC2
-    float getAlpha() const;
-#else
-    uint8_t getAlpha() const;
-#endif
+    half getAlpha() const;
+    half4 getColor() const;
 
     void traverseInReverseZOrder(LayerVector::StateSet stateSet,
                                  const LayerVector::Visitor& visitor);
     void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
 
+    /**
+     * Traverse only children in z order, ignoring relative layers that are not children of the
+     * parent.
+     */
+    void traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+                                  const LayerVector::Visitor& visitor);
+
     size_t getChildrenCount() const;
     void addChild(const sp<Layer>& layer);
     // Returns index if removed, or negative value otherwise
@@ -522,15 +585,17 @@
     ssize_t removeChild(const sp<Layer>& layer);
     sp<Layer> getParent() const { return mCurrentParent.promote(); }
     bool hasParent() const { return getParent() != nullptr; }
-
     Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
     bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
+    bool setChildRelativeLayer(const sp<Layer>& childLayer,
+            const sp<IBinder>& relativeToHandle, int32_t relativeZ);
 
     // Copy the current list of children to the drawing state. Called by
     // SurfaceFlinger to complete a transaction.
     void commitChildList();
-
     int32_t getZ() const;
+    void pushPendingState();
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -541,90 +606,57 @@
     class LayerCleaner {
         sp<SurfaceFlinger> mFlinger;
         wp<Layer> mLayer;
+
     protected:
         ~LayerCleaner() {
             // destroy client resources
             mFlinger->onLayerDestroyed(mLayer);
         }
-    public:
-        LayerCleaner(const sp<SurfaceFlinger>& flinger,
-                const sp<Layer>& layer)
-            : mFlinger(flinger), mLayer(layer) {
-        }
-    };
 
+    public:
+        LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+              : mFlinger(flinger), mLayer(layer) {}
+    };
 
     virtual void onFirstRef();
 
-
-
-private:
-    friend class SurfaceInterceptor;
-    // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
-    virtual void onFrameAvailable(const BufferItem& item) override;
-    virtual void onFrameReplaced(const BufferItem& item) override;
-    virtual void onSidebandStreamChanged() override;
+    friend class impl::SurfaceInterceptor;
 
     void commitTransaction(const State& stateToCommit);
 
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const sp<const DisplayDevice>& hw) const;
-
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
     FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
-    // Compute the initial crop as specified by parent layers and the SurfaceControl
-    // for this layer. Does not include buffer crop from the IGraphicBufferProducer
-    // client, as that should not affect child clipping. Returns in screen space.
+    // Compute the initial crop as specified by parent layers and the
+    // SurfaceControl for this layer. Does not include buffer crop from the
+    // IGraphicBufferProducer client, as that should not affect child clipping.
+    // Returns in screen space.
     Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
-    bool isCropped() const;
-    static bool getOpacityForFormat(uint32_t format);
 
     // drawing
-    void clearWithOpenGL(const sp<const DisplayDevice>& hw,
-            float r, float g, float b, float alpha) const;
-    void drawWithOpenGL(const sp<const DisplayDevice>& hw,
-            bool useIdentityTransform) const;
-
-    // Temporary - Used only for LEGACY camera mode.
-    uint32_t getProducerStickyTransform() const;
-
-    // Loads the corresponding system property once per process
-    static bool latchUnsignaledBuffers();
+    void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
+                         float alpha) const;
 
     void setParent(const sp<Layer>& layer);
 
-    LayerVector makeTraversalList(LayerVector::StateSet stateSet);
+    LayerVector makeTraversalList(LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers);
     void addZOrderRelative(const wp<Layer>& relative);
     void removeZOrderRelative(const wp<Layer>& relative);
 
-    // -----------------------------------------------------------------------
-
-    class SyncPoint
-    {
+    class SyncPoint {
     public:
-        explicit SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
-                mFrameIsAvailable(false), mTransactionIsApplied(false) {}
+        explicit SyncPoint(uint64_t frameNumber)
+              : mFrameNumber(frameNumber), mFrameIsAvailable(false), mTransactionIsApplied(false) {}
 
-        uint64_t getFrameNumber() const {
-            return mFrameNumber;
-        }
+        uint64_t getFrameNumber() const { return mFrameNumber; }
 
-        bool frameIsAvailable() const {
-            return mFrameIsAvailable;
-        }
+        bool frameIsAvailable() const { return mFrameIsAvailable; }
 
-        void setFrameAvailable() {
-            mFrameIsAvailable = true;
-        }
+        void setFrameAvailable() { mFrameIsAvailable = true; }
 
-        bool transactionIsApplied() const {
-            return mTransactionIsApplied;
-        }
+        bool transactionIsApplied() const { return mTransactionIsApplied; }
 
-        void setTransactionApplied() {
-            mTransactionIsApplied = true;
-        }
+        void setTransactionApplied() { mTransactionIsApplied = true; }
 
     private:
         const uint64_t mFrameNumber;
@@ -642,13 +674,9 @@
     // is applied
     std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
 
-    uint64_t getHeadFrameNumber() const;
-    bool headFenceHasSignaled() const;
-
     // Returns false if the relevant frame has already been latched
     bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
 
-    void pushPendingState();
     void popPendingState(State* stateToCommit);
     bool applyPendingStates(State* stateToCommit);
 
@@ -657,7 +685,8 @@
     // Returns mCurrentScaling mode (originating from the
     // Client) or mOverrideScalingMode mode (originating from
     // the Surface Controller) if set.
-    uint32_t getEffectiveScalingMode() const;
+    virtual uint32_t getEffectiveScalingMode() const { return 0; }
+
 public:
     /*
      * The layer handle is just a BBinder object passed to the client
@@ -668,34 +697,26 @@
      * this layer when the handle is destroyed.
      */
     class Handle : public BBinder, public LayerCleaner {
-        public:
-            Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
-                : LayerCleaner(flinger, layer), owner(layer) {}
+    public:
+        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+              : LayerCleaner(flinger, layer), owner(layer) {}
 
-            wp<Layer> owner;
+        wp<Layer> owner;
     };
 
     sp<IBinder> getHandle();
-    sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
-    void notifyAvailableFrames();
-private:
+    virtual void notifyAvailableFrames() {}
+    virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
+    bool getPremultipledAlpha() const;
 
+protected:
     // -----------------------------------------------------------------------
+    bool usingRelativeZ(LayerVector::StateSet stateSet);
 
-    // Check all of the local sync points to ensure that all transactions
-    // which need to have been applied prior to the frame which is about to
-    // be latched have signaled
-    bool allTransactionsSignaled();
-
-    // constants
-    sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
-    sp<IGraphicBufferProducer> mProducer;
-    uint32_t mTextureName;      // from GLES
     bool mPremultipliedAlpha;
     String8 mName;
     String8 mTransactionName; // A cached version of "TX - " + mName for systraces
-    PixelFormat mFormat;
 
     bool mPrimaryDisplayOnly = false;
 
@@ -722,66 +743,33 @@
     FenceTimeline mAcquireTimeline;
     FenceTimeline mReleaseTimeline;
 
+    TimeStats& mTimeStats = TimeStats::getInstance();
+
     // main thread
     int mActiveBufferSlot;
     sp<GraphicBuffer> mActiveBuffer;
     sp<NativeHandle> mSidebandStream;
+    ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
-    uint32_t mCurrentScalingMode;
     // We encode unset as -1.
     int32_t mOverrideScalingMode;
     bool mCurrentOpacity;
-    bool mBufferLatched = false;  // TODO: Use mActiveBuffer?
     std::atomic<uint64_t> mCurrentFrameNumber;
-    uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
-    bool mRefreshPending;
     bool mFrameLatencyNeeded;
     // Whether filtering is forced on or not
     bool mFiltering;
     // Whether filtering is needed b/c of the drawingstate
     bool mNeedsFiltering;
-    // The mesh used to draw the layer in GLES composition mode
-    mutable Mesh mMesh;
-    // The texture used to draw the layer in GLES composition mode
-    mutable Texture mTexture;
 
-#ifdef USE_HWC2
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-          : hwc(nullptr),
-            layer(nullptr),
-            forceClientComposition(false),
-            compositionType(HWC2::Composition::Invalid),
-            clearClientTarget(false) {}
-
-        HWComposer* hwc;
-        HWC2::Layer* layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        HWComposerBufferCache bufferCache;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo. This map key is a display layerStack.
-    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-#else
-    bool mIsGlesComposition;
-#endif
+    bool mPendingRemoval = false;
 
     // page-flip thread (currently main thread)
     bool mProtectedByApp; // application requires protected path to external sink
 
     // protected by mLock
     mutable Mutex mLock;
-    // Set to true once we've returned this surface's handle
-    mutable bool mHasSurface;
+
     const wp<Client> mClientRef;
 
     // This layer can be a cursor on some displays.
@@ -792,8 +780,6 @@
     Condition mQueueItemCondition;
     Vector<BufferItem> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived;
-    bool mUpdateTexImageFailed; // This is only accessed on the main thread.
-
     bool mAutoRefresh;
     bool mFreezeGeometryUpdates;
 
@@ -804,6 +790,24 @@
 
     wp<Layer> mCurrentParent;
     wp<Layer> mDrawingParent;
+
+    mutable LayerBE mBE;
+
+private:
+    /**
+     * Returns an unsorted vector of all layers that are part of this tree.
+     * That includes the current layer and all its descendants.
+     */
+    std::vector<Layer*> getLayersInTree(LayerVector::StateSet stateSet);
+    /**
+     * Traverses layers that are part of this tree in the correct z order.
+     * layersInTree must be sorted before calling this method.
+     */
+    void traverseChildrenInZOrderInner(const std::vector<Layer*>& layersInTree,
+                                       LayerVector::StateSet stateSet,
+                                       const LayerVector::Visitor& visitor);
+    LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
+                                          const std::vector<Layer*>& layersInTree);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
deleted file mode 100644
index daebf8a..0000000
--- a/services/surfaceflinger/LayerDim.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "LayerDim"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include "LayerDim.h"
-#include "SurfaceFlinger.h"
-#include "DisplayDevice.h"
-#include "RenderEngine/RenderEngine.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
-        const String8& name, uint32_t w, uint32_t h, uint32_t flags)
-    : Layer(flinger, client, name, w, h, flags) {
-}
-
-LayerDim::~LayerDim() {
-}
-
-void LayerDim::onDraw(const sp<const DisplayDevice>& hw,
-        const Region& /* clip */, bool useIdentityTransform) const
-{
-    const State& s(getDrawingState());
-    if (s.alpha>0) {
-        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
-        computeGeometry(hw, mesh, useIdentityTransform);
-        RenderEngine& engine(mFlinger->getRenderEngine());
-        engine.setupDimLayerBlending(s.alpha);
-        engine.drawMesh(mesh);
-        engine.disableBlending();
-    }
-}
-
-bool LayerDim::isVisible() const {
-    const Layer::State& s(getDrawingState());
-    return !isHiddenByPolicy() && s.alpha;
-}
-
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
deleted file mode 100644
index a0cfca9..0000000
--- a/services/surfaceflinger/LayerDim.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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 ANDROID_LAYER_DIM_H
-#define ANDROID_LAYER_DIM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "Layer.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-class LayerDim : public Layer
-{
-public:
-                LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
-                        const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-        virtual ~LayerDim();
-
-    virtual const char* getTypeId() const { return "LayerDim"; }
-    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-            bool useIdentityTransform) const;
-    virtual bool isOpaque(const Layer::State&) const { return false; }
-    virtual bool isSecure() const         { return false; }
-    virtual bool isFixedSize() const      { return true; }
-    virtual bool isVisible() const;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_DIM_H
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
new file mode 100644
index 0000000..cc39550
--- /dev/null
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerProtoHelper.h"
+
+namespace android {
+namespace surfaceflinger {
+void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+    Region::const_iterator head = region.begin();
+    Region::const_iterator const tail = region.end();
+    uint64_t address = reinterpret_cast<uint64_t>(&region);
+    regionProto->set_id(address);
+    while (head != tail) {
+        RectProto* rectProto = regionProto->add_rect();
+        writeToProto(*head, rectProto);
+        head++;
+    }
+}
+
+void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
+void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
+    colorProto->set_r(color.r);
+    colorProto->set_g(color.g);
+    colorProto->set_b(color.b);
+    colorProto->set_a(color.a);
+}
+
+void LayerProtoHelper::writeToProto(const Transform& transform, TransformProto* transformProto) {
+    transformProto->set_dsdx(transform[0][0]);
+    transformProto->set_dtdx(transform[0][1]);
+    transformProto->set_dsdy(transform[1][0]);
+    transformProto->set_dtdy(transform[1][1]);
+}
+
+void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
+                                    ActiveBufferProto* activeBufferProto) {
+    activeBufferProto->set_width(buffer->getWidth());
+    activeBufferProto->set_height(buffer->getHeight());
+    activeBufferProto->set_stride(buffer->getStride());
+    activeBufferProto->set_format(buffer->format);
+}
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
new file mode 100644
index 0000000..860da63
--- /dev/null
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <layerproto/LayerProtoHeader.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include <Transform.h>
+
+#include <math/vec4.h>
+
+namespace android {
+namespace surfaceflinger {
+class LayerProtoHelper {
+public:
+    static void writeToProto(const Rect& rect, RectProto* rectProto);
+    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
+    static void writeToProto(const Region& region, RegionProto* regionProto);
+    static void writeToProto(const half4 color, ColorProto* colorProto);
+    static void writeToProto(const Transform& transform, TransformProto* transformProto);
+    static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
+};
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index e864607..a5f0b98 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -41,7 +41,7 @@
     mFreezeGeometryUpdates(freezePositionUpdates) {}
 
 bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
-    if (buf == NULL) {
+    if (buf == nullptr) {
         return false;
     }
 
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 828cd8b..40972aa 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -18,10 +18,10 @@
 #define ANDROID_LAYER_REJECTER_H
 
 #include "Layer.h"
-#include "SurfaceFlingerConsumer.h"
+#include "BufferLayerConsumer.h"
 
 namespace android {
-    class LayerRejecter : public SurfaceFlingerConsumer::BufferRejecter {
+    class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
     public:
         LayerRejecter(Layer::State &front,
                       Layer::State &current,
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..04ab121
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+#include "ui/DebugUtils.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mEnabled) return;
+    mLayerShapeStatsMap.clear();
+    mEnabled = true;
+    ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mEnabled) return;
+    mEnabled = false;
+    ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mLayerShapeStatsMap.clear();
+    ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+    return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+        const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+        const LayerProtoParser::LayerGlobal& layerGlobal,
+        std::vector<std::string>* const outLayerShapeVec) {
+    for (const auto& layer : layerTree) {
+        if (!layer) continue;
+        traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
+        std::string key = "";
+        base::StringAppendF(&key, ",%s", layer->type.c_str());
+        base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
+        base::StringAppendF(&key, ",%d", layer->isProtected);
+        base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
+        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+        base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
+                                                true));
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1],
+                                                false));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                            layerGlobal.resolution[0], true));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                            layerGlobal.resolution[1], false));
+        base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str());
+        base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
+
+        outLayerShapeVec->push_back(key);
+        ALOGV("%s", key.c_str());
+    }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+    ATRACE_CALL();
+    ALOGV("Logging");
+    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::vector<std::string> layerShapeVec;
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    traverseLayerTreeStatsLocked(layerTree, layerGlobal, &layerShapeVec);
+
+    std::string layerShapeKey =
+            base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
+                               layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
+                               layerTransform(layerGlobal.globalTransform));
+    ALOGV("%s", layerShapeKey.c_str());
+
+    std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
+    for (auto const& s : layerShapeVec) {
+        layerShapeKey += s;
+    }
+
+    mLayerShapeStatsMap[layerShapeKey]++;
+}
+
+void LayerStats::dump(String8& result) {
+    ATRACE_CALL();
+    ALOGD("Dumping");
+    std::lock_guard<std::mutex> lock(mMutex);
+    result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
+    result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
+    result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
+    for (auto& u : mLayerShapeStatsMap) {
+        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+    }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+    int32_t ratio = location * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isHorizontal) {
+        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+        if (ratio > 6) return "3/4";
+        // use index 0, 2, 4, 6
+        return locationArray[ratio & ~1];
+    }
+    if (ratio > 7) return "7/8";
+    return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+    int32_t ratio = size * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isWidth) {
+        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+        if (ratio > 6) return "1";
+        // use index 1, 3, 5, 7
+        return sizeArray[ratio | 1];
+    }
+    if (ratio > 7) return "1";
+    return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+    return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+const char* LayerStats::layerCompositionType(int32_t compositionType) {
+    return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
+}
+
+const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
+    return decodePixelFormat(pixelFormat).c_str();
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+    std::string ret = "";
+    if (isRotated(layer->hwcTransform)) {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+    } else {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+    }
+    return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+    // Make scale buckets from <1/64 to >= 16, to avoid floating point
+    // calculation, x64 on destinationScale first
+    int32_t scale = destinationScale * 64 / sourceScale;
+    if (!scale) return "<1/64";
+    if (scale < 2) return "1/64";
+    if (scale < 4) return "1/32";
+    if (scale < 8) return "1/16";
+    if (scale < 16) return "1/8";
+    if (scale < 32) return "1/4";
+    if (scale < 64) return "1/2";
+    if (scale < 128) return "1";
+    if (scale < 256) return "2";
+    if (scale < 512) return "4";
+    if (scale < 1024) return "8";
+    return ">=16";
+}
+
+const char* LayerStats::alpha(float a) {
+    if (a == 1.0f) return "1.0";
+    if (a > 0.9f) return "0.99";
+    if (a > 0.8f) return "0.9";
+    if (a > 0.7f) return "0.8";
+    if (a > 0.6f) return "0.7";
+    if (a > 0.5f) return "0.6";
+    if (a > 0.4f) return "0.5";
+    if (a > 0.3f) return "0.4";
+    if (a > 0.2f) return "0.3";
+    if (a > 0.1f) return "0.2";
+    if (a > 0.0f) return "0.1";
+    return "0.0";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+    return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..7a190fd
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void logLayerStats(const LayersProto& layersProto);
+    void dump(String8& result);
+
+private:
+    // Traverse layer tree to get all visible layers' stats
+    void traverseLayerTreeStatsLocked(
+            const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+            const LayerProtoParser::LayerGlobal& layerGlobal,
+            std::vector<std::string>* const outLayerShapeVec);
+    // Convert layer's top-left position into 8x8 percentage of the display
+    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+    // Convert layer's size into 8x8 percentage of the display
+    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+    // Return the name of the transform
+    static const char* layerTransform(int32_t transform);
+    // Return the name of the composition type
+    static const char* layerCompositionType(int32_t compositionType);
+    // Return the name of the pixel format
+    static const char* layerPixelFormat(int32_t pixelFormat);
+    // Calculate scale ratios of layer's width/height with rotation information
+    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+    // Calculate scale ratio from source to destination and convert to string
+    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Bucket the alpha into designed buckets
+    static const char* alpha(float a);
+    // Return whether the original buffer is rotated in final composition
+    static bool isRotated(int32_t transform);
+    // Return whether the original buffer is V-flipped in final composition
+    static bool isVFlipped(int32_t transform);
+    // Return whether the original buffer is H-flipped in final composition
+    static bool isHFlipped(int32_t transform);
+
+    bool mEnabled = false;
+    // Protect mLayersStatsMap
+    std::mutex mMutex;
+    // Hashmap for tracking the frame(layer shape) stats
+    // KEY is a concatenation of all layers' properties within a frame
+    // VALUE is the number of times this particular set has been scanned out
+    std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
+};
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 2233e78..8494524 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -19,30 +19,44 @@
 
 namespace android {
 
-LayerVector::LayerVector() = default;
+LayerVector::LayerVector(const StateSet stateSet) : mStateSet(stateSet) {}
 
-LayerVector::LayerVector(const LayerVector& rhs) : SortedVector<sp<Layer>>(rhs) {
-}
+LayerVector::LayerVector(const LayerVector& rhs, const StateSet stateSet)
+      : SortedVector<sp<Layer>>(rhs), mStateSet(stateSet) {}
 
 LayerVector::~LayerVector() = default;
 
+// This operator override is needed to prevent mStateSet from getting copied over.
+LayerVector& LayerVector::operator=(const LayerVector& rhs) {
+    SortedVector::operator=(rhs);
+    return *this;
+}
+
 int LayerVector::do_compare(const void* lhs, const void* rhs) const
 {
     // sort layers per layer-stack, then by z-order and finally by sequence
     const auto& l = *reinterpret_cast<const sp<Layer>*>(lhs);
     const auto& r = *reinterpret_cast<const sp<Layer>*>(rhs);
 
-    uint32_t ls = l->getCurrentState().layerStack;
-    uint32_t rs = r->getCurrentState().layerStack;
+    const auto& lState =
+            (mStateSet == StateSet::Current) ? l->getCurrentState() : l->getDrawingState();
+    const auto& rState =
+            (mStateSet == StateSet::Current) ? r->getCurrentState() : r->getDrawingState();
+
+    uint32_t ls = lState.layerStack;
+    uint32_t rs = rState.layerStack;
     if (ls != rs)
-        return ls - rs;
+        return (ls > rs) ? 1 : -1;
 
-    uint32_t lz = l->getCurrentState().z;
-    uint32_t rz = r->getCurrentState().z;
+    int32_t lz = lState.z;
+    int32_t rz = rState.z;
     if (lz != rz)
-        return lz - rz;
+        return (lz > rz) ? 1 : -1;
 
-    return l->sequence - r->sequence;
+    if (l->sequence == r->sequence)
+        return 0;
+
+    return (l->sequence > r->sequence) ? 1 : -1;
 }
 
 void LayerVector::traverseInZOrder(StateSet stateSet, const Visitor& visitor) const {
diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h
index a9adb41..88d7711 100644
--- a/services/surfaceflinger/LayerVector.h
+++ b/services/surfaceflinger/LayerVector.h
@@ -32,22 +32,27 @@
  */
 class LayerVector : public SortedVector<sp<Layer>> {
 public:
-    LayerVector();
-    LayerVector(const LayerVector& rhs);
-    ~LayerVector() override;
-
     enum class StateSet {
         Invalid,
         Current,
         Drawing,
     };
 
+    explicit LayerVector(const StateSet stateSet);
+    LayerVector(const LayerVector& rhs, const StateSet stateSet);
+    ~LayerVector() override;
+
+    LayerVector& operator=(const LayerVector& rhs);
+
     // Sorts layer by layer-stack, Z order, and finally creation order (sequence).
     int do_compare(const void* lhs, const void* rhs) const override;
 
     using Visitor = std::function<void(Layer*)>;
     void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const;
     void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const;
+
+private:
+    const StateSet mStateSet;
 };
 }
 
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 0b1199c..056d381 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -14,32 +14,30 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
 #include <errno.h>
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <binder/IPCThreadState.h>
 
-#include <utils/threads.h>
-#include <utils/Timers.h>
 #include <utils/Log.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
 
+#include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
 
-#include "MessageQueue.h"
 #include "EventThread.h"
+#include "MessageQueue.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-MessageBase::MessageBase()
-    : MessageHandler() {
-}
+MessageBase::MessageBase() : MessageHandler() {}
 
-MessageBase::~MessageBase() {
-}
+MessageBase::~MessageBase() {}
 
 void MessageBase::handleMessage(const Message&) {
     this->handler();
@@ -48,6 +46,12 @@
 
 // ---------------------------------------------------------------------------
 
+MessageQueue::~MessageQueue() = default;
+
+// ---------------------------------------------------------------------------
+
+namespace impl {
+
 void MessageQueue::Handler::dispatchRefresh() {
     if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
         mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
@@ -75,22 +79,13 @@
 
 // ---------------------------------------------------------------------------
 
-MessageQueue::MessageQueue()
-{
-}
-
-MessageQueue::~MessageQueue() {
-}
-
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
-{
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
     mFlinger = flinger;
     mLooper = new Looper(true);
     mHandler = new Handler(*this);
 }
 
-void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
-{
+void MessageQueue::setEventThread(android::EventThread* eventThread) {
     if (mEventThread == eventThread) {
         return;
     }
@@ -102,8 +97,8 @@
     mEventThread = eventThread;
     mEvents = eventThread->createEventConnection();
     mEvents->stealReceiveChannel(&mEventTube);
-    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT,
-            MessageQueue::cb_eventReceiver, this);
+    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+                   this);
 }
 
 void MessageQueue::waitMessage() {
@@ -128,9 +123,7 @@
     } while (true);
 }
 
-status_t MessageQueue::postMessage(
-        const sp<MessageBase>& messageHandler, nsecs_t relTime)
-{
+status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
     const Message dummyMessage;
     if (relTime > 0) {
         mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
@@ -140,7 +133,6 @@
     return NO_ERROR;
 }
 
-
 void MessageQueue::invalidate() {
     mEvents->requestNextVsync();
 }
@@ -150,7 +142,7 @@
 }
 
 int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
-    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+    MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
     return queue->eventReceiver(fd, events);
 }
 
@@ -158,7 +150,7 @@
     ssize_t n;
     DisplayEventReceiver::Event buffer[8];
     while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
-        for (int i=0 ; i<n ; i++) {
+        for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                 mHandler->dispatchInvalidate();
                 break;
@@ -170,4 +162,5 @@
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace impl
+} // namespace android
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 14f50bb..90d1c72 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -17,16 +17,16 @@
 #ifndef ANDROID_MESSAGE_QUEUE_H
 #define ANDROID_MESSAGE_QUEUE_H
 
-#include <stdint.h>
 #include <errno.h>
+#include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/threads.h>
-#include <utils/Timers.h>
 #include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
 
+#include <gui/IDisplayEventConnection.h>
 #include <private/gui/BitTube.h>
-#include <gui/DisplayEventReceiver.h>
 
 #include "Barrier.h"
 
@@ -34,17 +34,15 @@
 
 namespace android {
 
-class IDisplayEventConnection;
 class EventThread;
 class SurfaceFlinger;
 
 // ---------------------------------------------------------------------------
 
-class MessageBase : public MessageHandler
-{
+class MessageBase : public MessageHandler {
 public:
     MessageBase();
-    
+
     // return true if message has a handler
     virtual bool handler() = 0;
 
@@ -78,16 +76,34 @@
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
+public:
+    enum {
+        INVALIDATE = 0,
+        REFRESH = 1,
+    };
+
+    virtual ~MessageQueue();
+
+    virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
+    virtual void setEventThread(EventThread* events) = 0;
+    virtual void waitMessage() = 0;
+    virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
+    virtual void invalidate() = 0;
+    virtual void refresh() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+namespace impl {
+
+class MessageQueue final : public android::MessageQueue {
     class Handler : public MessageHandler {
-        enum {
-            eventMaskInvalidate     = 0x1,
-            eventMaskRefresh        = 0x2,
-            eventMaskTransaction    = 0x4
-        };
+        enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
         MessageQueue& mQueue;
         int32_t mEventMask;
+
     public:
-        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
         virtual void handleMessage(const Message& message);
         void dispatchRefresh();
         void dispatchInvalidate();
@@ -97,37 +113,31 @@
 
     sp<SurfaceFlinger> mFlinger;
     sp<Looper> mLooper;
-    sp<EventThread> mEventThread;
+    android::EventThread* mEventThread;
     sp<IDisplayEventConnection> mEvents;
     gui::BitTube mEventTube;
     sp<Handler> mHandler;
 
-
     static int cb_eventReceiver(int fd, int events, void* data);
     int eventReceiver(int fd, int events);
 
 public:
-    enum {
-        INVALIDATE  = 0,
-        REFRESH     = 1,
-    };
+    ~MessageQueue() override = default;
+    void init(const sp<SurfaceFlinger>& flinger) override;
+    void setEventThread(android::EventThread* events) override;
 
-    MessageQueue();
-    ~MessageQueue();
-    void init(const sp<SurfaceFlinger>& flinger);
-    void setEventThread(const sp<EventThread>& events);
-
-    void waitMessage();
-    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
+    void waitMessage() override;
+    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
 
     // sends INVALIDATE message at next VSYNC
-    void invalidate();
+    void invalidate() override;
     // sends REFRESH message at next VSYNC
-    void refresh();
+    void refresh() override;
 };
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace impl
+} // namespace android
 
 #endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 1a5a85e..389fbd2 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -33,26 +33,13 @@
     // because we don't know where this destructor is called from. It could be
     // called with the mStateLock held, leading to a dead-lock (it actually
     // happens).
-    class MessageCleanUpList : public MessageBase {
-    public:
-        MessageCleanUpList(const sp<SurfaceFlinger>& flinger,
-                const wp<IBinder>& producer)
-            : mFlinger(flinger), mProducer(producer) {}
+    sp<LambdaMessage> cleanUpListMessage =
+            new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() {
+                Mutex::Autolock lock(flinger->mStateLock);
+                flinger->mGraphicBufferProducerList.erase(asBinder);
+            });
 
-        virtual ~MessageCleanUpList() {}
-
-        virtual bool handler() {
-            Mutex::Autolock _l(mFlinger->mStateLock);
-            mFlinger->mGraphicBufferProducerList.remove(mProducer);
-            return true;
-        }
-
-    private:
-        sp<SurfaceFlinger> mFlinger;
-        wp<IBinder> mProducer;
-    };
-
-    mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(mProducer)));
+    mFlinger->postMessageAsync(cleanUpListMessage);
 }
 
 status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
new file mode 100644
index 0000000..1a8edf3
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -0,0 +1,49 @@
+#include "RenderArea.h"
+
+#include <gui/LayerState.h>
+
+namespace android {
+
+float RenderArea::getCaptureFillValue(CaptureFill captureFill) {
+    switch(captureFill) {
+        case CaptureFill::CLEAR:
+            return 0.0f;
+        case CaptureFill::OPAQUE:
+        default:
+            return 1.0f;
+    }
+}
+/*
+ * Checks that the requested width and height are valid and updates them to the render area
+ * dimensions if they are set to 0
+ */
+status_t RenderArea::updateDimensions(int displayRotation) {
+    // get screen geometry
+
+    uint32_t width = getWidth();
+    uint32_t height = getHeight();
+
+    if (mRotationFlags & Transform::ROT_90) {
+        std::swap(width, height);
+    }
+
+    if (displayRotation & DisplayState::eOrientationSwapMask) {
+        std::swap(width, height);
+    }
+
+    if ((mReqWidth > width) || (mReqHeight > height)) {
+        ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height);
+        return BAD_VALUE;
+    }
+
+    if (mReqWidth == 0) {
+        mReqWidth = width;
+    }
+    if (mReqHeight == 0) {
+        mReqHeight = height;
+    }
+
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
new file mode 100644
index 0000000..96e4b5f
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <ui/GraphicTypes.h>
+
+#include "Transform.h"
+
+#include <functional>
+
+namespace android {
+
+class RenderArea {
+
+public:
+    enum class CaptureFill {CLEAR, OPAQUE};
+
+    static float getCaptureFillValue(CaptureFill captureFill);
+
+    RenderArea(uint32_t reqHeight, uint32_t reqWidth, CaptureFill captureFill,
+               ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
+          : mReqHeight(reqHeight), mReqWidth(reqWidth), mCaptureFill(captureFill) {
+        mRotationFlags = Transform::fromRotation(rotation);
+    }
+
+    virtual ~RenderArea() = default;
+
+    virtual const Transform& getTransform() const = 0;
+    virtual Rect getBounds() const = 0;
+    virtual int getHeight() const = 0;
+    virtual int getWidth() const = 0;
+    virtual bool isSecure() const = 0;
+    virtual bool needsFiltering() const = 0;
+    virtual Rect getSourceCrop() const = 0;
+
+    virtual void render(std::function<void()> drawLayers) { drawLayers(); }
+
+    int getReqHeight() const { return mReqHeight; };
+    int getReqWidth() const { return mReqWidth; };
+    Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+    status_t updateDimensions(int displayRotation);
+
+    CaptureFill getCaptureFill() const { return mCaptureFill; };
+
+private:
+    uint32_t mReqHeight;
+    uint32_t mReqWidth;
+    Transform::orientation_flags mRotationFlags;
+    CaptureFill mCaptureFill;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index effd319..c218e4d 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -26,23 +26,6 @@
 
 namespace android {
 
-Description::Description() {
-    mPlaneAlpha = 1.0f;
-    mPremultipliedAlpha = false;
-    mOpaque = true;
-    mTextureEnabled = false;
-    mColorMatrixEnabled = false;
-
-    memset(mColor, 0, sizeof(mColor));
-}
-
-Description::~Description() {
-}
-
-void Description::setPlaneAlpha(GLclampf planeAlpha) {
-    mPlaneAlpha = planeAlpha;
-}
-
 void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
     mPremultipliedAlpha = premultipliedAlpha;
 }
@@ -60,11 +43,8 @@
     mTextureEnabled = false;
 }
 
-void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    mColor[0] = red;
-    mColor[1] = green;
-    mColor[2] = blue;
-    mColor[3] = alpha;
+void Description::setColor(const half4& color) {
+    mColor = color;
 }
 
 void Description::setProjectionMatrix(const mat4& mtx) {
@@ -72,17 +52,50 @@
 }
 
 void Description::setColorMatrix(const mat4& mtx) {
-    const mat4 identity;
     mColorMatrix = mtx;
-    mColorMatrixEnabled = (mtx != identity);
+}
+
+void Description::setInputTransformMatrix(const mat3& matrix) {
+    mInputTransformMatrix = matrix;
+}
+
+void Description::setOutputTransformMatrix(const mat4& matrix) {
+    mOutputTransformMatrix = matrix;
+}
+
+bool Description::hasInputTransformMatrix() const {
+    const mat3 identity;
+    return mInputTransformMatrix != identity;
+}
+
+bool Description::hasOutputTransformMatrix() const {
+    const mat4 identity;
+    return mOutputTransformMatrix != identity;
+}
+
+bool Description::hasColorMatrix() const {
+    const mat4 identity;
+    return mColorMatrix != identity;
 }
 
 const mat4& Description::getColorMatrix() const {
     return mColorMatrix;
 }
 
-void Description::setWideGamut(bool wideGamut) {
-    mIsWideGamut = wideGamut;
+void Description::setY410BT2020(bool enable) {
+    mY410BT2020 = enable;
+}
+
+void Description::setInputTransferFunction(TransferFunction transferFunction) {
+    mInputTransferFunction = transferFunction;
+}
+
+void Description::setOutputTransferFunction(TransferFunction transferFunction) {
+    mOutputTransferFunction = transferFunction;
+}
+
+void Description::setDisplayMaxLuminance(const float maxLuminance) {
+    mDisplayMaxLuminance = maxLuminance;
 }
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 3beffdf..6ebb340 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -32,44 +32,66 @@
  * Program and ProgramCache are friends and access the state directly
  */
 class Description {
-    friend class Program;
-    friend class ProgramCache;
-
-    // value of the plane-alpha, between 0 and 1
-    GLclampf mPlaneAlpha;
-    // whether textures are premultiplied
-    bool mPremultipliedAlpha;
-    // whether this layer is marked as opaque
-    bool mOpaque;
-
-    // Texture this layer uses
-    Texture mTexture;
-    bool mTextureEnabled;
-
-    // color used when texturing is disabled
-    GLclampf mColor[4];
-    // projection matrix
-    mat4 mProjectionMatrix;
-
-    bool mColorMatrixEnabled;
-    mat4 mColorMatrix;
-
-    bool mIsWideGamut;
-
 public:
-    Description();
-    ~Description();
+    Description() = default;
+    ~Description() = default;
 
-    void setPlaneAlpha(GLclampf planeAlpha);
     void setPremultipliedAlpha(bool premultipliedAlpha);
     void setOpaque(bool opaque);
     void setTexture(const Texture& texture);
     void disableTexture();
-    void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void setColor(const half4& color);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
+    void setInputTransformMatrix(const mat3& matrix);
+    void setOutputTransformMatrix(const mat4& matrix);
+    bool hasInputTransformMatrix() const;
+    bool hasOutputTransformMatrix() const;
+    bool hasColorMatrix() const;
     const mat4& getColorMatrix() const;
-    void setWideGamut(bool wideGamut);
+
+    void setY410BT2020(bool enable);
+
+    enum class TransferFunction : int {
+        LINEAR,
+        SRGB,
+        ST2084,
+        HLG,  // Hybrid Log-Gamma for HDR.
+    };
+    void setInputTransferFunction(TransferFunction transferFunction);
+    void setOutputTransferFunction(TransferFunction transferFunction);
+    void setDisplayMaxLuminance(const float maxLuminance);
+
+private:
+    friend class Program;
+    friend class ProgramCache;
+
+    // whether textures are premultiplied
+    bool mPremultipliedAlpha = false;
+    // whether this layer is marked as opaque
+    bool mOpaque = true;
+
+    // Texture this layer uses
+    Texture mTexture;
+    bool mTextureEnabled = false;
+
+    // color used when texturing is disabled or when setting alpha.
+    half4 mColor;
+
+    // true if the sampled pixel values are in Y410/BT2020 rather than RGBA
+    bool mY410BT2020 = false;
+
+    // transfer functions for the input/output
+    TransferFunction mInputTransferFunction = TransferFunction::LINEAR;
+    TransferFunction mOutputTransferFunction = TransferFunction::LINEAR;
+
+    float mDisplayMaxLuminance;
+
+    // projection matrix
+    mat4 mProjectionMatrix;
+    mat4 mColorMatrix;
+    mat3 mInputTransformMatrix;
+    mat4 mOutputTransformMatrix;
 };
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 37a530b..744a70c 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -33,18 +33,17 @@
 #include <gui/ISurfaceComposer.h>
 #include <math.h>
 
+#include "Description.h"
 #include "GLES20RenderEngine.h"
+#include "Mesh.h"
 #include "Program.h"
 #include "ProgramCache.h"
-#include "Description.h"
-#include "Mesh.h"
 #include "Texture.h"
 
-#include <sstream>
 #include <fstream>
+#include <sstream>
 
 // ---------------------------------------------------------------------------
-#ifdef USE_HWC2
 bool checkGlError(const char* op, int lineNumber) {
     bool errorFound = false;
     GLint error = glGetError();
@@ -103,75 +102,79 @@
     }
     file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
 }
-#endif
 
 // ---------------------------------------------------------------------------
 namespace android {
+namespace RE {
+namespace impl {
 // ---------------------------------------------------------------------------
 
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) :
-         mVpWidth(0),
-         mVpHeight(0),
-         mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
+using ui::Dataspace;
 
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+      : RenderEngine(featureFlags),
+        mVpWidth(0),
+        mVpHeight(0),
+        mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     glPixelStorei(GL_PACK_ALIGNMENT, 4);
 
-    const uint16_t protTexData[] = { 0 };
+    const uint16_t protTexData[] = {0};
     glGenTextures(1, &mProtectedTexName);
     glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
-            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
 
-    //mColorBlindnessCorrection = M;
+    // mColorBlindnessCorrection = M;
 
-#ifdef USE_HWC2
     if (mPlatformHasWideColor) {
-        // Compute sRGB to DisplayP3 color transform
-        // NOTE: For now, we are limiting wide-color support to
+        ColorSpace srgb(ColorSpace::sRGB());
+        ColorSpace displayP3(ColorSpace::DisplayP3());
+        ColorSpace bt2020(ColorSpace::BT2020());
+
+        // Compute sRGB to Display P3 transform matrix.
+        // NOTE: For now, we are limiting output wide color space support to
         // Display-P3 only.
-        mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
+        mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
 
-        // color transform needs to be expanded to 4x4 to be what the shader wants
-        // mat has an initializer that expands mat3 to mat4, but
-        // not an assignment operator
-        mat4 gamutTransform(srgbToP3);
-        mSrgbToDisplayP3 = gamutTransform;
+        // Compute Display P3 to sRGB transform matrix.
+        mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+
+        // no chromatic adaptation needed since all color spaces use D65 for their white points.
+        mSrgbToXyz = srgb.getRGBtoXYZ();
+        mDisplayP3ToXyz = displayP3.getRGBtoXYZ();
+        mBt2020ToXyz = bt2020.getRGBtoXYZ();
+        mXyzToSrgb = mat4(srgb.getXYZtoRGB());
+        mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
+        mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
     }
-#endif
 }
 
-GLES20RenderEngine::~GLES20RenderEngine() {
-}
-
+GLES20RenderEngine::~GLES20RenderEngine() {}
 
 size_t GLES20RenderEngine::getMaxTextureSize() const {
     return mMaxTextureSize;
 }
 
 size_t GLES20RenderEngine::getMaxViewportDims() const {
-    return
-        mMaxViewportDims[0] < mMaxViewportDims[1] ?
-            mMaxViewportDims[0] : mMaxViewportDims[1];
+    return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
 }
 
-void GLES20RenderEngine::setViewportAndProjection(
-        size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap,
-        Transform::orientation_flags rotation) {
-
-    size_t l = sourceCrop.left;
-    size_t r = sourceCrop.right;
+void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                                  size_t hwh, bool yswap,
+                                                  Transform::orientation_flags rotation) {
+    int32_t l = sourceCrop.left;
+    int32_t r = sourceCrop.right;
 
     // In GL, (0, 0) is the bottom-left corner, so flip y coordinates
-    size_t t = hwh - sourceCrop.top;
-    size_t b = hwh - sourceCrop.bottom;
+    int32_t t = hwh - sourceCrop.top;
+    int32_t b = hwh - sourceCrop.bottom;
 
     mat4 m;
     if (yswap) {
@@ -186,13 +189,13 @@
         case Transform::ROT_0:
             break;
         case Transform::ROT_90:
-            m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
             break;
         case Transform::ROT_180:
-            m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
             break;
         case Transform::ROT_270:
-            m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
             break;
         default:
             break;
@@ -204,25 +207,17 @@
     mVpHeight = vph;
 }
 
-#ifdef USE_HWC2
-void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
-        bool opaque, float alpha) {
-#else
-void GLES20RenderEngine::setupLayerBlending(
-    bool premultipliedAlpha, bool opaque, int alpha) {
-#endif
-
+void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
+                                            bool disableTexture, const half4& color) {
     mState.setPremultipliedAlpha(premultipliedAlpha);
     mState.setOpaque(opaque);
-#ifdef USE_HWC2
-    mState.setPlaneAlpha(alpha);
+    mState.setColor(color);
 
-    if (alpha < 1.0f || !opaque) {
-#else
-    mState.setPlaneAlpha(alpha / 255.0f);
+    if (disableTexture) {
+        mState.disableTexture();
+    }
 
-    if (alpha < 0xFF || !opaque) {
-#endif
+    if (color.a < 1.0f || !opaque) {
         glEnable(GL_BLEND);
         glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     } else {
@@ -230,68 +225,21 @@
     }
 }
 
-#ifdef USE_HWC2
-void GLES20RenderEngine::setupDimLayerBlending(float alpha) {
-#else
-void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
-#endif
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-#ifdef USE_HWC2
-    mState.setColor(0, 0, 0, alpha);
-#else
-    mState.setColor(0, 0, 0, alpha/255.0f);
-#endif
-    mState.disableTexture();
-
-#ifdef USE_HWC2
-    if (alpha == 1.0f) {
-#else
-    if (alpha == 0xFF) {
-#endif
-        glDisable(GL_BLEND);
-    } else {
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-    }
+void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
+    mState.setY410BT2020(enable);
 }
 
-#ifdef USE_HWC2
-void GLES20RenderEngine::setColorMode(android_color_mode mode) {
-    ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
-
-    if (mColorMode == mode) return;
-
-    if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB ||
-        mode == HAL_COLOR_MODE_NATIVE) {
-        // We are returning back to our default color_mode
-        mUseWideColor = false;
-        mWideColorFrameCount = 0;
-    } else {
-        mUseWideColor = true;
-    }
-
-    mColorMode = mode;
-}
-
-void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
-    if (source == HAL_DATASPACE_UNKNOWN) {
-        // Treat UNKNOWN as SRGB
-        source = HAL_DATASPACE_V0_SRGB;
-    }
+void GLES20RenderEngine::setSourceDataSpace(Dataspace source) {
     mDataSpace = source;
 }
 
-void GLES20RenderEngine::setWideColor(bool hasWideColor) {
-    ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
-    mDisplayHasWideColor = hasWideColor;
+void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) {
+    mOutputDataSpace = dataspace;
 }
 
-bool GLES20RenderEngine::usesWideColor() {
-    return mUseWideColor;
+void GLES20RenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
+    mState.setDisplayMaxLuminance(maxLuminance);
 }
-#endif
 
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
     GLuint target = texture.getTextureTarget();
@@ -315,10 +263,8 @@
     mState.setTexture(texture);
 }
 
-mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
-    mat4 oldTransform = mState.getColorMatrix();
+void GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
     mState.setColorMatrix(colorTransform);
-    return oldTransform;
 }
 
 void GLES20RenderEngine::disableTexturing() {
@@ -329,9 +275,8 @@
     glDisable(GL_BLEND);
 }
 
-
-void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image,
-        uint32_t* texName, uint32_t* fbName, uint32_t* status) {
+void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
+                                                uint32_t* fbName, uint32_t* status) {
     GLuint tname, name;
     // turn our EGLImage into a texture
     glGenTextures(1, &tname);
@@ -355,46 +300,125 @@
 }
 
 void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
-    mState.setPlaneAlpha(1.0f);
     mState.setPremultipliedAlpha(true);
     mState.setOpaque(false);
-    mState.setColor(r, g, b, a);
+    mState.setColor(half4(r, g, b, a));
     mState.disableTexture();
     glDisable(GL_BLEND);
 }
 
 void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
-
+    ATRACE_CALL();
     if (mesh.getTexCoordsSize()) {
         glEnableVertexAttribArray(Program::texCoords);
-        glVertexAttribPointer(Program::texCoords,
-                mesh.getTexCoordsSize(),
-                GL_FLOAT, GL_FALSE,
-                mesh.getByteStride(),
-                mesh.getTexCoords());
+        glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
+                              mesh.getByteStride(), mesh.getTexCoords());
     }
 
-    glVertexAttribPointer(Program::position,
-            mesh.getVertexSize(),
-            GL_FLOAT, GL_FALSE,
-            mesh.getByteStride(),
-            mesh.getPositions());
+    glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+                          mesh.getByteStride(), mesh.getPositions());
 
-#ifdef USE_HWC2
-    if (usesWideColor()) {
+    // By default, DISPLAY_P3 is the only supported wide color output. However,
+    // when HDR content is present, hardware composer may be able to handle
+    // BT2020 data space, in that case, the output data space is set to be
+    // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
+    // to respect this and convert non-HDR content to HDR format.
+    if (mPlatformHasWideColor) {
         Description wideColorState = mState;
-        if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
-            wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-            wideColorState.setWideGamut(true);
-            ALOGV("drawMesh: gamut transform applied");
+        Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
+        Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+        Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
+                                                          Dataspace::STANDARD_MASK);
+        Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+                                                          Dataspace::TRANSFER_MASK);
+        bool needsXYZConversion = needsXYZTransformMatrix();
+
+        if (needsXYZConversion) {
+            // The supported input color spaces are standard RGB, Display P3 and BT2020.
+            switch (inputStandard) {
+                case Dataspace::STANDARD_DCI_P3:
+                    wideColorState.setInputTransformMatrix(mDisplayP3ToXyz);
+                    break;
+                case Dataspace::STANDARD_BT2020:
+                    wideColorState.setInputTransformMatrix(mBt2020ToXyz);
+                    break;
+                default:
+                    wideColorState.setInputTransformMatrix(mSrgbToXyz);
+                    break;
+            }
+
+            // The supported output color spaces are BT2020, Display P3 and standard RGB.
+            switch (outputStandard) {
+                case Dataspace::STANDARD_BT2020:
+                    wideColorState.setOutputTransformMatrix(mXyzToBt2020);
+                    break;
+                case Dataspace::STANDARD_DCI_P3:
+                    wideColorState.setOutputTransformMatrix(mXyzToDisplayP3);
+                    break;
+                default:
+                    wideColorState.setOutputTransformMatrix(mXyzToSrgb);
+                    break;
+            }
+        } else if (inputStandard != outputStandard) {
+            // At this point, the input data space and output data space could be both
+            // HDR data spaces, but they match each other, we do nothing in this case.
+            // In addition to the case above, the input data space could be
+            // - scRGB linear
+            // - scRGB non-linear
+            // - sRGB
+            // - Display P3
+            // The output data spaces could be
+            // - sRGB
+            // - Display P3
+            if (outputStandard == Dataspace::STANDARD_BT709) {
+                wideColorState.setOutputTransformMatrix(mDisplayP3ToSrgb);
+            } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
+                wideColorState.setOutputTransformMatrix(mSrgbToDisplayP3);
+            }
         }
+
+        // we need to convert the RGB value to linear space and convert it back when:
+        // - there is a color matrix that is not an identity matrix, or
+        // - there is an output transform matrix that is not an identity matrix, or
+        // - the input transfer function doesn't match the output transfer function.
+        if (wideColorState.hasColorMatrix() || wideColorState.hasOutputTransformMatrix() ||
+            inputTransfer != outputTransfer) {
+            switch (inputTransfer) {
+                case Dataspace::TRANSFER_ST2084:
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
+                    break;
+                case Dataspace::TRANSFER_HLG:
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
+                    break;
+                case Dataspace::TRANSFER_LINEAR:
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+                    break;
+                default:
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                    break;
+            }
+
+            switch (outputTransfer) {
+                case Dataspace::TRANSFER_ST2084:
+                    wideColorState.setOutputTransferFunction(Description::TransferFunction::ST2084);
+                    break;
+                case Dataspace::TRANSFER_HLG:
+                    wideColorState.setOutputTransferFunction(Description::TransferFunction::HLG);
+                    break;
+                default:
+                    wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+                    break;
+            }
+        }
+
         ProgramCache::getInstance().useProgram(wideColorState);
 
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
         if (outputDebugPPMs) {
+            static uint64_t wideColorFrameCount = 0;
             std::ostringstream out;
-            out << "/data/texture_out" << mWideColorFrameCount++;
+            out << "/data/texture_out" << wideColorFrameCount++;
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
@@ -402,11 +426,6 @@
 
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
     }
-#else
-    ProgramCache::getInstance().useProgram(mState);
-
-    glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
-#endif
 
     if (mesh.getTexCoordsSize()) {
         glDisableVertexAttribArray(Program::texCoords);
@@ -415,17 +434,42 @@
 
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
-#ifdef USE_HWC2
-    if (usesWideColor()) {
-        result.append("Wide-color: On\n");
-    } else {
-        result.append("Wide-color: Off\n");
-    }
-#endif
+    result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                        dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                        dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
+}
+
+bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
+    const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
+    const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
+    return standard == Dataspace::STANDARD_BT2020 &&
+        (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+}
+
+// For convenience, we want to convert the input color space to XYZ color space first,
+// and then convert from XYZ color space to output color space when
+// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
+//   HDR content will be tone-mapped to SDR; Or,
+// - there are HDR PQ and HLG contents presented at the same time, where we want to convert
+//   HLG content to PQ content.
+// In either case above, we need to operate the Y value in XYZ color space. Thus, when either
+// input data space or output data space is HDR data space, and the input transfer function
+// doesn't match the output transfer function, we would enable an intermediate transfrom to
+// XYZ color space.
+bool GLES20RenderEngine::needsXYZTransformMatrix() const {
+    const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
+    const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
+    const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+    const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
+                                                            Dataspace::TRANSFER_MASK);
+
+    return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
 }
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace impl
+} // namespace RE
+} // namespace android
 // ---------------------------------------------------------------------------
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index eaf94af..cc8eb1d 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 #ifndef SF_GLES20RENDERENGINE_H_
 #define SF_GLES20RENDERENGINE_H_
 
@@ -24,9 +23,9 @@
 #include <GLES2/gl2.h>
 #include <Transform.h>
 
-#include "RenderEngine.h"
-#include "ProgramCache.h"
 #include "Description.h"
+#include "ProgramCache.h"
+#include "RenderEngine.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -36,6 +35,9 @@
 class Mesh;
 class Texture;
 
+namespace RE {
+namespace impl {
+
 class GLES20RenderEngine : public RenderEngine {
     GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
@@ -54,55 +56,31 @@
     Description mState;
     Vector<Group> mGroupStack;
 
-    virtual void bindImageAsFramebuffer(EGLImageKHR image,
-            uint32_t* texName, uint32_t* fbName, uint32_t* status);
+    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+                                        uint32_t* status);
     virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
 
 public:
     GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
-
-protected:
     virtual ~GLES20RenderEngine();
 
+protected:
     virtual void dump(String8& result);
-    virtual void setViewportAndProjection(size_t vpw, size_t vph,
-            Rect sourceCrop, size_t hwh, bool yswap,
-            Transform::orientation_flags rotation);
-#ifdef USE_HWC2
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            float alpha) override;
-    virtual void setupDimLayerBlending(float alpha) override;
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+                                          bool yswap, Transform::orientation_flags rotation);
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                    const half4& color) override;
 
     // Color management related functions and state
-    void setColorMode(android_color_mode mode);
-    void setSourceDataSpace(android_dataspace source);
-    void setWideColor(bool hasWideColor);
-    bool usesWideColor();
-
-    // Current color mode of display using the render engine
-    android_color_mode mColorMode = HAL_COLOR_MODE_NATIVE;
-
-    // Current dataspace of layer being rendered
-    android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
-
-    // Indicate if wide-color mode is needed or not
-    bool mDisplayHasWideColor = false;
-    bool mUseWideColor = false;
-    uint64_t mWideColorFrameCount = 0;
-
-    // Currently only supporting sRGB and DisplayP3 color spaces
-    mat4 mSrgbToDisplayP3;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            int alpha);
-    virtual void setupDimLayerBlending(int alpha);
-#endif
-    bool mPlatformHasWideColor = false;
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(ui::Dataspace source) override;
+    void setOutputDataSpace(ui::Dataspace dataspace) override;
+    void setDisplayMaxLuminance(const float maxLuminance) override;
 
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
-    virtual mat4 setupColorTransform(const mat4& colorTransform);
+    virtual void setupColorTransform(const mat4& colorTransform);
     virtual void disableTexturing();
     virtual void disableBlending();
 
@@ -110,10 +88,35 @@
 
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
+
+    // Current dataspace of layer being rendered
+    ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Current output dataspace of the render engine
+    ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
+    const bool mPlatformHasWideColor = false;
+    mat4 mSrgbToDisplayP3;
+    mat4 mDisplayP3ToSrgb;
+    mat3 mSrgbToXyz;
+    mat3 mBt2020ToXyz;
+    mat3 mDisplayP3ToXyz;
+    mat4 mXyzToSrgb;
+    mat4 mXyzToDisplayP3;
+    mat4 mXyzToBt2020;
+
+private:
+    // A data space is considered HDR data space if it has BT2020 color space
+    // with PQ or HLG transfer function.
+    bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
+    bool needsXYZTransformMatrix() const;
 };
 
 // ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace impl
+} // namespace RE
+} // namespace android
 // ---------------------------------------------------------------------------
 
 #endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 76bbcc1..dc09a37 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -14,51 +14,44 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "GLExtensions.h"
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
+ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
 
-GLExtensions::GLExtensions()
-    : mHaveFramebufferObject(false)
-{
-}
+SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
+    SortedVector<String8> list;
 
-void GLExtensions::initWithGLStrings(
-        GLubyte const* vendor,
-        GLubyte const* renderer,
-        GLubyte const* version,
-        GLubyte const* extensions)
-{
-    mVendor     = (char const*)vendor;
-    mRenderer   = (char const*)renderer;
-    mVersion    = (char const*)version;
-    mExtensions = (char const*)extensions;
-
-    char const* curr = (char const*)extensions;
+    char const* curr = extensions;
     char const* head = curr;
     do {
         head = strchr(curr, ' ');
-        String8 s(curr, head ? head-curr : strlen(curr));
+        String8 s(curr, head ? head - curr : strlen(curr));
         if (s.length()) {
-            mExtensionList.add(s);
+            list.add(s);
         }
-        curr = head+1;
+        curr = head + 1;
     } while (head);
 
-    if (hasExtension("GL_OES_framebuffer_object")) {
-        mHaveFramebufferObject = true;
-    }
+    return list;
 }
 
-bool GLExtensions::hasExtension(char const* extension) const
-{
+void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
+                                     GLubyte const* version, GLubyte const* extensions) {
+    mVendor = (char const*)vendor;
+    mRenderer = (char const*)renderer;
+    mVersion = (char const*)version;
+    mExtensions = (char const*)extensions;
+    mExtensionList = parseExtensionString(mExtensions);
+}
+
+bool GLExtensions::hasExtension(char const* extension) const {
     const String8 s(extension);
     return mExtensionList.indexOf(s) >= 0;
 }
@@ -75,9 +68,61 @@
     return mVersion.string();
 }
 
-char const* GLExtensions::getExtension() const {
+char const* GLExtensions::getExtensions() const {
     return mExtensions.string();
 }
 
+void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
+    mEGLVersion = eglVersion;
+    mEGLExtensions = eglExtensions;
+    mEGLExtensionList = parseExtensionString(mEGLExtensions);
+
+    // EGL_ANDROIDX_no_config_context is an experimental extension with no
+    // written specification. It will be replaced by something more formal.
+    // SurfaceFlinger is using it to allow a single EGLContext to render to
+    // both a 16-bit primary display framebuffer and a 32-bit virtual display
+    // framebuffer.
+    //
+    // EGL_KHR_no_config_context is official extension to allow creating a
+    // context that works with any surface of a display.
+    if (hasEGLExtension("EGL_ANDROIDX_no_config_context") ||
+        hasEGLExtension("EGL_KHR_no_config_context")) {
+        mHasNoConfigContext = true;
+    }
+
+    if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) {
+        mHasNativeFenceSync = true;
+    }
+    if (hasEGLExtension("EGL_KHR_fence_sync")) {
+        mHasFenceSync = true;
+    }
+    if (hasEGLExtension("EGL_KHR_wait_sync")) {
+        mHasWaitSync = true;
+    }
+
+    if (hasEGLExtension("EGL_ANDROID_image_crop")) {
+        mHasImageCrop = true;
+    }
+    if (hasEGLExtension("EGL_EXT_protected_content")) {
+        mHasProtectedContent = true;
+    }
+    if (hasEGLExtension("EGL_IMG_context_priority")) {
+        mHasContextPriority = true;
+    }
+}
+
+char const* GLExtensions::getEGLVersion() const {
+    return mEGLVersion.string();
+}
+
+char const* GLExtensions::getEGLExtensions() const {
+    return mEGLExtensions.string();
+}
+
+bool GLExtensions::hasEGLExtension(char const* extension) const {
+    const String8 s(extension);
+    return mEGLExtensionList.indexOf(s) >= 0;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index d81ed2a..0d8c10b 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -20,9 +20,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
 #include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -32,11 +32,16 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class GLExtensions : public Singleton<GLExtensions>
-{
+class GLExtensions : public Singleton<GLExtensions> {
     friend class Singleton<GLExtensions>;
 
-    bool mHaveFramebufferObject : 1;
+    bool mHasNoConfigContext = false;
+    bool mHasNativeFenceSync = false;
+    bool mHasFenceSync = false;
+    bool mHasWaitSync = false;
+    bool mHasImageCrop = false;
+    bool mHasProtectedContent = false;
+    bool mHasContextPriority = false;
 
     String8 mVendor;
     String8 mRenderer;
@@ -44,32 +49,40 @@
     String8 mExtensions;
     SortedVector<String8> mExtensionList;
 
+    String8 mEGLVersion;
+    String8 mEGLExtensions;
+    SortedVector<String8> mEGLExtensionList;
+
+    static SortedVector<String8> parseExtensionString(char const* extensions);
+
     GLExtensions(const GLExtensions&);
-    GLExtensions& operator = (const GLExtensions&);
+    GLExtensions& operator=(const GLExtensions&);
 
 protected:
-    GLExtensions();
+    GLExtensions() = default;
 
 public:
+    bool hasNoConfigContext() const { return mHasNoConfigContext; }
+    bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
+    bool hasFenceSync() const { return mHasFenceSync; }
+    bool hasWaitSync() const { return mHasWaitSync; }
+    bool hasImageCrop() const { return mHasImageCrop; }
+    bool hasProtectedContent() const { return mHasProtectedContent; }
+    bool hasContextPriority() const { return mHasContextPriority; }
 
-    inline bool haveFramebufferObject() const {
-        return mHaveFramebufferObject;
-    }
-
-    void initWithGLStrings(
-            GLubyte const* vendor,
-            GLubyte const* renderer,
-            GLubyte const* version,
-            GLubyte const* extensions);
-
+    void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
+                           GLubyte const* extensions);
     char const* getVendor() const;
     char const* getRenderer() const;
     char const* getVersion() const;
-    char const* getExtension() const;
-
+    char const* getExtensions() const;
     bool hasExtension(char const* extension) const;
-};
 
+    void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
+    char const* getEGLVersion() const;
+    char const* getEGLExtensions() const;
+    bool hasEGLExtension(char const* extension) const;
+};
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
new file mode 100644
index 0000000..0d06422
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Image.h"
+
+#include <vector>
+
+#include <log/log.h>
+
+#include "GLExtensions.h"
+#include "RenderEngine.h"
+
+namespace android {
+namespace RE {
+
+Image::~Image() = default;
+
+namespace impl {
+
+Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+Image::~Image() {
+    setNativeWindowBuffer(nullptr, false, 0, 0);
+}
+
+static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
+                                              int32_t cropHeight) {
+    std::vector<EGLint> attrs;
+    attrs.reserve(16);
+
+    attrs.push_back(EGL_IMAGE_PRESERVED_KHR);
+    attrs.push_back(EGL_TRUE);
+
+    if (isProtected && GLExtensions::getInstance().hasProtectedContent()) {
+        attrs.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attrs.push_back(EGL_TRUE);
+    }
+
+    if (cropWidth > 0 && cropHeight > 0) {
+        attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
+        attrs.push_back(cropWidth);
+        attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
+        attrs.push_back(cropHeight);
+    }
+
+    attrs.push_back(EGL_NONE);
+
+    return attrs;
+}
+
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                                  int32_t cropHeight) {
+    if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
+            ALOGE("failed to destroy image: %#x", eglGetError());
+        }
+        mEGLImage = EGL_NO_IMAGE_KHR;
+    }
+
+    if (buffer) {
+        std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                      static_cast<EGLClientBuffer>(buffer), attrs.data());
+        if (mEGLImage == EGL_NO_IMAGE_KHR) {
+            ALOGE("failed to create EGLImage: %#x", eglGetError());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace impl
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
new file mode 100644
index 0000000..1ae7e09
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace RE {
+
+class Image {
+public:
+    virtual ~Image() = 0;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected,
+                                       int32_t cropWidth, int32_t cropHeight) = 0;
+};
+
+namespace impl {
+
+class RenderEngine;
+
+class Image : public RE::Image {
+public:
+    explicit Image(const RenderEngine& engine);
+    ~Image() override;
+
+    Image(const Image&) = delete;
+    Image& operator=(const Image&) = delete;
+
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                               int32_t cropHeight) override;
+
+private:
+    // methods internal to RenderEngine
+    friend class RenderEngine;
+    EGLSurface getEGLImage() const { return mEGLImage; }
+
+    EGLDisplay mEGLDisplay;
+    EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+};
+
+} // namespace impl
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index ffd9be2..6a62b1d 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -21,9 +21,10 @@
 namespace android {
 
 Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
-    : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
-      mPrimitive(primitive)
-{
+      : mVertexCount(vertexCount),
+        mVertexSize(vertexSize),
+        mTexCoordsSize(texCoordSize),
+        mPrimitive(primitive) {
     if (vertexCount == 0) {
         mVertices = new float[1];
         mVertices[0] = 0.0f;
@@ -37,8 +38,7 @@
     // either vertexSize or texCoordSize, it must have overflowed. remainder
     // will be equal to stride as long as stride * vertexCount doesn't overflow.
     if ((stride < vertexSize) || (remainder != stride)) {
-        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
-                texCoordSize);
+        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
         mVertices = new float[1];
         mVertices[0] = 0.0f;
         mVertexCount = 0;
@@ -53,14 +53,13 @@
 }
 
 Mesh::~Mesh() {
-    delete [] mVertices;
+    delete[] mVertices;
 }
 
 Mesh::Primitive Mesh::getPrimitive() const {
     return mPrimitive;
 }
 
-
 float const* Mesh::getPositions() const {
     return mVertices;
 }
@@ -75,7 +74,6 @@
     return mVertices + mVertexSize;
 }
 
-
 size_t Mesh::getVertexCount() const {
     return mVertexCount;
 }
@@ -89,7 +87,7 @@
 }
 
 size_t Mesh::getByteStride() const {
-    return mStride*sizeof(float);
+    return mStride * sizeof(float);
 }
 
 size_t Mesh::getStride() const {
diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h
index b6d42b0..d0a9ac0 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/Mesh.h
@@ -24,9 +24,9 @@
 class Mesh {
 public:
     enum Primitive {
-        TRIANGLES       = 0x0004,       // GL_TRIANGLES
-        TRIANGLE_STRIP  = 0x0005,       // GL_TRIANGLE_STRIP
-        TRIANGLE_FAN    = 0x0006        // GL_TRIANGLE_FAN
+        TRIANGLES = 0x0004,      // GL_TRIANGLES
+        TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP
+        TRIANGLE_FAN = 0x0006    // GL_TRIANGLE_FAN
     };
 
     Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
@@ -40,21 +40,24 @@
         friend class Mesh;
         float* mData;
         size_t mStride;
-        VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { }
+        VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {}
+
     public:
-        TYPE& operator[](size_t index) {
-            return *reinterpret_cast<TYPE*>(&mData[index*mStride]);
-        }
+        TYPE& operator[](size_t index) { return *reinterpret_cast<TYPE*>(&mData[index * mStride]); }
         TYPE const& operator[](size_t index) const {
-            return *reinterpret_cast<TYPE const*>(&mData[index*mStride]);
+            return *reinterpret_cast<TYPE const*>(&mData[index * mStride]);
         }
     };
 
     template <typename TYPE>
-    VertexArray<TYPE> getPositionArray() { return VertexArray<TYPE>(getPositions(), mStride); }
+    VertexArray<TYPE> getPositionArray() {
+        return VertexArray<TYPE>(getPositions(), mStride);
+    }
 
     template <typename TYPE>
-    VertexArray<TYPE> getTexCoordArray() { return VertexArray<TYPE>(getTexCoords(), mStride); }
+    VertexArray<TYPE> getTexCoordArray() {
+        return VertexArray<TYPE>(getTexCoords(), mStride);
+    }
 
     Primitive getPrimitive() const;
 
@@ -81,8 +84,8 @@
 
 private:
     Mesh(const Mesh&);
-    Mesh& operator = (const Mesh&);
-    Mesh const& operator = (const Mesh&) const;
+    Mesh& operator=(const Mesh&);
+    Mesh const& operator=(const Mesh&) const;
 
     float* getPositions();
     float* getTexCoords();
@@ -94,6 +97,5 @@
     Primitive mPrimitive;
 };
 
-
 } /* namespace android */
 #endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 48a8da5..fe536f0 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -19,14 +19,15 @@
 #include <log/log.h>
 #include <utils/String8.h>
 
+#include <math/mat4.h>
+#include "Description.h"
 #include "Program.h"
 #include "ProgramCache.h"
-#include "Description.h"
 
 namespace android {
 
 Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
-        : mInitialized(false) {
+      : mInitialized(false) {
     GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
     GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
     GLuint programId = glCreateProgram();
@@ -57,24 +58,22 @@
         mVertexShader = vertexId;
         mFragmentShader = fragmentId;
         mInitialized = true;
-
-        mColorMatrixLoc = glGetUniformLocation(programId, "colorMatrix");
         mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
-        mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
+        mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
+        mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
+        mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
-        const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
-        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m);
+        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
         glEnableVertexAttribArray(0);
     }
 }
 
-Program::~Program() {
-}
+Program::~Program() {}
 
 bool Program::isValid() const {
     return mInitialized;
@@ -117,14 +116,13 @@
     GLint l;
     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
     char* src = new char[l];
-    glGetShaderSource(shader, l, NULL, src);
+    glGetShaderSource(shader, l, nullptr, src);
     result.append(src);
-    delete [] src;
+    delete[] src;
     return result;
 }
 
 void Program::setUniforms(const Description& desc) {
-
     // TODO: we should have a mechanism here to not always reset uniforms that
     // didn't change for this program.
 
@@ -132,14 +130,23 @@
         glUniform1i(mSamplerLoc, 0);
         glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
     }
-    if (mAlphaPlaneLoc >= 0) {
-        glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
-    }
     if (mColorLoc >= 0) {
-        glUniform4fv(mColorLoc, 1, desc.mColor);
+        const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a};
+        glUniform4fv(mColorLoc, 1, color);
     }
-    if (mColorMatrixLoc >= 0) {
-        glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
+    if (mInputTransformMatrixLoc >= 0) {
+        mat4 inputTransformMatrix = mat4(desc.mInputTransformMatrix);
+        glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
+    }
+    if (mOutputTransformMatrixLoc >= 0) {
+        // The output transform matrix and color matrix can be combined as one matrix
+        // that is applied right before applying OETF.
+        mat4 outputTransformMatrix = desc.mColorMatrix * desc.mOutputTransformMatrix;
+        glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
+                           outputTransformMatrix.asArray());
+    }
+    if (mDisplayMaxLuminanceLoc >= 0) {
+        glUniform1f(mDisplayMaxLuminanceLoc, desc.mDisplayMaxLuminance);
     }
     // these uniforms are always present
     glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 36bd120..ae796c5 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -34,7 +34,7 @@
 class Program {
 public:
     // known locations for position and texture coordinates
-    enum { position=0, texCoords=1 };
+    enum { position = 0, texCoords = 1 };
 
     Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
     ~Program();
@@ -54,7 +54,6 @@
     /* set-up uniforms from the description */
     void setUniforms(const Description& desc);
 
-
 private:
     GLuint buildShader(const char* source, GLenum type);
     String8& dumpShader(String8& result, GLenum type);
@@ -70,22 +69,22 @@
     /* location of the projection matrix uniform */
     GLint mProjectionMatrixLoc;
 
-    /* location of the color matrix uniform */
-    GLint mColorMatrixLoc;
-
     /* location of the texture matrix uniform */
     GLint mTextureMatrixLoc;
 
     /* location of the sampler uniform */
     GLint mSamplerLoc;
 
-    /* location of the alpha plane uniform */
-    GLint mAlphaPlaneLoc;
-
     /* location of the color uniform */
     GLint mColorLoc;
-};
 
+    /* location of display luminance uniform */
+    GLint mDisplayMaxLuminanceLoc;
+
+    /* location of transform matrix */
+    GLint mInputTransformMatrixLoc;
+    GLint mOutputTransformMatrixLoc;
+};
 
 } /* namespace android */
 
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 06b2252..46402d5 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
 #include <utils/String8.h>
+#include <utils/Trace.h>
 
-#include "ProgramCache.h"
-#include "Program.h"
 #include "Description.h"
+#include "Program.h"
+#include "ProgramCache.h"
 
 namespace android {
 // -----------------------------------------------------------------------------------------------
 
-
 /*
  * A simple formatter class to automatically add the endl and
  * manage the indentation.
@@ -42,23 +44,22 @@
     typedef Formatter& (*FormaterManipFunc)(Formatter&);
     friend Formatter& indent(Formatter& f);
     friend Formatter& dedent(Formatter& f);
+
 public:
     Formatter() : mIndent(0) {}
 
-    String8 getString() const {
-        return mString;
-    }
+    String8 getString() const { return mString; }
 
-    friend Formatter& operator << (Formatter& out, const char* in) {
-        for (int i=0 ; i<out.mIndent ; i++) {
+    friend Formatter& operator<<(Formatter& out, const char* in) {
+        for (int i = 0; i < out.mIndent; i++) {
             out.mString.append("    ");
         }
         out.mString.append(in);
         out.mString.append("\n");
         return out;
     }
-    friend inline Formatter& operator << (Formatter& out, const String8& in) {
-        return operator << (out, in.string());
+    friend inline Formatter& operator<<(Formatter& out, const String8& in) {
+        return operator<<(out, in.string());
     }
     friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
         return (*func)(to);
@@ -77,19 +78,13 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
 
-ProgramCache::ProgramCache() {
-    // Until surfaceflinger has a dependable blob cache on the filesystem,
-    // generate shaders on initialization so as to avoid jank.
-    primeCache();
-}
+ProgramCache::ProgramCache() {}
 
-ProgramCache::~ProgramCache() {
-}
+ProgramCache::~ProgramCache() {}
 
-void ProgramCache::primeCache() {
+void ProgramCache::primeCache(bool hasWideColor) {
     uint32_t shaderCount = 0;
-    uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
-                       Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK;
+    uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
     // Prime the cache for all combinations of the above masks,
     // leaving off the experimental color matrix mask options.
 
@@ -98,18 +93,37 @@
         Key shaderKey;
         shaderKey.set(keyMask, keyVal);
         uint32_t tex = shaderKey.getTextureTarget();
-        if (tex != Key::TEXTURE_OFF &&
-            tex != Key::TEXTURE_EXT &&
-            tex != Key::TEXTURE_2D) {
+        if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
             continue;
         }
         Program* program = mCache.valueFor(shaderKey);
-        if (program == NULL) {
+        if (program == nullptr) {
             program = generateProgram(shaderKey);
             mCache.add(shaderKey, program);
             shaderCount++;
         }
     }
+
+    // Prime for sRGB->P3 conversion
+    if (hasWideColor) {
+        Key shaderKey;
+        shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK |
+                              Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK,
+                      Key::BLEND_PREMULT | Key::TEXTURE_EXT | Key::OUTPUT_TRANSFORM_MATRIX_ON |
+                              Key::INPUT_TF_SRGB | Key::OUTPUT_TF_SRGB);
+        for (int i = 0; i < 4; i++) {
+            shaderKey.set(Key::OPACITY_MASK,
+                          (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
+            shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
+            Program* program = mCache.valueFor(shaderKey);
+            if (program == nullptr) {
+                program = generateProgram(shaderKey);
+                mCache.add(shaderKey, program);
+                shaderCount++;
+            }
+        }
+    }
+
     nsecs_t timeAfter = systemTime();
     float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
     ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
@@ -118,34 +132,398 @@
 ProgramCache::Key ProgramCache::computeKey(const Description& description) {
     Key needs;
     needs.set(Key::TEXTURE_MASK,
-            !description.mTextureEnabled ? Key::TEXTURE_OFF :
-            description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
-            description.mTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_2D :
-            Key::TEXTURE_OFF)
-    .set(Key::PLANE_ALPHA_MASK,
-            (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
-    .set(Key::BLEND_MASK,
-            description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
-    .set(Key::OPACITY_MASK,
-            description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
-    .set(Key::COLOR_MATRIX_MASK,
-            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF)
-    .set(Key::WIDE_GAMUT_MASK,
-            description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
+              !description.mTextureEnabled
+                      ? Key::TEXTURE_OFF
+                      : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES
+                              ? Key::TEXTURE_EXT
+                              : description.mTexture.getTextureTarget() == GL_TEXTURE_2D
+                                      ? Key::TEXTURE_2D
+                                      : Key::TEXTURE_OFF)
+            .set(Key::ALPHA_MASK,
+                 (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
+            .set(Key::BLEND_MASK,
+                 description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
+            .set(Key::OPACITY_MASK,
+                 description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
+            .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
+                 description.hasInputTransformMatrix() ?
+                     Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
+            .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
+                 description.hasOutputTransformMatrix() || description.hasColorMatrix() ?
+                     Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
+
+    needs.set(Key::Y410_BT2020_MASK,
+              description.mY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
+
+    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+        switch (description.mInputTransferFunction) {
+            case Description::TransferFunction::LINEAR:
+            default:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR);
+                break;
+            case Description::TransferFunction::SRGB:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB);
+                break;
+            case Description::TransferFunction::ST2084:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084);
+                break;
+            case Description::TransferFunction::HLG:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG);
+                break;
+        }
+
+        switch (description.mOutputTransferFunction) {
+            case Description::TransferFunction::LINEAR:
+            default:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR);
+                break;
+            case Description::TransferFunction::SRGB:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB);
+                break;
+            case Description::TransferFunction::ST2084:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084);
+                break;
+            case Description::TransferFunction::HLG:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG);
+                break;
+        }
+    }
+
     return needs;
 }
 
+// Generate EOTF that converts signal values to relative display light,
+// both normalized to [0, 1].
+void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) {
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_SRGB:
+            fs << R"__SHADER__(
+                float EOTF_sRGB(float srgb) {
+                    return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+                }
+
+                vec3 EOTF_sRGB(const vec3 srgb) {
+                    return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+                }
+
+                vec3 EOTF(const vec3 srgb) {
+                    return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                vec3 EOTF(const highp vec3 color) {
+                    const highp float m1 = (2610.0 / 4096.0) / 4.0;
+                    const highp float m2 = (2523.0 / 4096.0) * 128.0;
+                    const highp float c1 = (3424.0 / 4096.0);
+                    const highp float c2 = (2413.0 / 4096.0) * 32.0;
+                    const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+                    highp vec3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / vec3(m2));
+                    tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
+                    return pow(tmp, 1.0 / vec3(m1));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp float EOTF_channel(const highp float channel) {
+                    const highp float a = 0.17883277;
+                    const highp float b = 0.28466892;
+                    const highp float c = 0.55991073;
+                    return channel <= 0.5 ? channel * channel / 3.0 :
+                            (exp((channel - c) / a) + b) / 12.0;
+                }
+
+                vec3 EOTF(const highp vec3 color) {
+                    return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
+                            EOTF_channel(color.b));
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                vec3 EOTF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) {
+    // Convert relative light to absolute light.
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    return color * 10000.0;
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    // The formula is:
+                    // alpha * pow(Y, gamma - 1.0) * color + beta;
+                    // where alpha is 1000.0, gamma is 1.2, beta is 0.0.
+                    return color * 1000.0 * pow(color.y, 0.2);
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    return color * displayMaxLuminance;
+                }
+            )__SHADER__";
+            break;
+    }
+
+    // Tone map absolute light to display luminance range.
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_ST2084:
+        case Key::INPUT_TF_HLG:
+            switch (needs.getOutputTF()) {
+                case Key::OUTPUT_TF_HLG:
+                    // Right now when mixed PQ and HLG contents are presented,
+                    // HLG content will always be converted to PQ. However, for
+                    // completeness, we simply clamp the value to [0.0, 1000.0].
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            return clamp(color, 0.0, 1000.0);
+                        }
+                    )__SHADER__";
+                    break;
+                case Key::OUTPUT_TF_ST2084:
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            return color;
+                        }
+                    )__SHADER__";
+                    break;
+                default:
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            const float maxMasteringLumi = 1000.0;
+                            const float maxContentLumi = 1000.0;
+                            const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
+                            float maxOutLumi = displayMaxLuminance;
+
+                            float nits = color.y;
+
+                            // clamp to max input luminance
+                            nits = clamp(nits, 0.0, maxInLumi);
+
+                            // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+                            if (maxInLumi <= maxOutLumi) {
+                                nits *= maxOutLumi / maxInLumi;
+                            } else {
+                                // three control points
+                                const float x0 = 10.0;
+                                const float y0 = 17.0;
+                                float x1 = maxOutLumi * 0.75;
+                                float y1 = x1;
+                                float x2 = x1 + (maxInLumi - x1) / 2.0;
+                                float y2 = y1 + (maxOutLumi - y1) * 0.75;
+
+                                // horizontal distances between the last three control points
+                                float h12 = x2 - x1;
+                                float h23 = maxInLumi - x2;
+                                // tangents at the last three control points
+                                float m1 = (y2 - y1) / h12;
+                                float m3 = (maxOutLumi - y2) / h23;
+                                float m2 = (m1 + m3) / 2.0;
+
+                                if (nits < x0) {
+                                    // scale [0.0, x0] to [0.0, y0] linearly
+                                    float slope = y0 / x0;
+                                    nits *= slope;
+                                } else if (nits < x1) {
+                                    // scale [x0, x1] to [y0, y1] linearly
+                                    float slope = (y1 - y0) / (x1 - x0);
+                                    nits = y0 + (nits - x0) * slope;
+                                } else if (nits < x2) {
+                                    // scale [x1, x2] to [y1, y2] using Hermite interp
+                                    float t = (nits - x1) / h12;
+                                    nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
+                                            (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+                                } else {
+                                    // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
+                                    float t = (nits - x2) / h23;
+                                    nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
+                                            (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
+                                }
+                            }
+
+                            return color * (nits / max(1e-6, color.y));
+                        }
+                    )__SHADER__";
+                    break;
+            }
+            break;
+        default:
+            // inverse tone map; the output luminance can be up to maxOutLumi.
+            fs << R"__SHADER__(
+                highp vec3 ToneMap(highp vec3 color) {
+                    const float maxOutLumi = 3000.0;
+
+                    const float x0 = 5.0;
+                    const float y0 = 2.5;
+                    float x1 = displayMaxLuminance * 0.7;
+                    float y1 = maxOutLumi * 0.15;
+                    float x2 = displayMaxLuminance * 0.9;
+                    float y2 = maxOutLumi * 0.45;
+                    float x3 = displayMaxLuminance;
+                    float y3 = maxOutLumi;
+
+                    float c1 = y1 / 3.0;
+                    float c2 = y2 / 2.0;
+                    float c3 = y3 / 1.5;
+
+                    float nits = color.y;
+
+                    float scale;
+                    if (nits <= x0) {
+                        // scale [0.0, x0] to [0.0, y0] linearly
+                        const float slope = y0 / x0;
+                        nits *= slope;
+                    } else if (nits <= x1) {
+                        // scale [x0, x1] to [y0, y1] using a curve
+                        float t = (nits - x0) / (x1 - x0);
+                        nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1;
+                    } else if (nits <= x2) {
+                        // scale [x1, x2] to [y1, y2] using a curve
+                        float t = (nits - x1) / (x2 - x1);
+                        nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2;
+                    } else {
+                        // scale [x2, x3] to [y2, y3] using a curve
+                        float t = (nits - x2) / (x3 - x2);
+                        nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
+                    }
+
+                    return color * (nits / max(1e-6, color.y));
+                }
+            )__SHADER__";
+            break;
+    }
+
+    // convert absolute light to relative light.
+    switch (needs.getOutputTF()) {
+        case Key::OUTPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / 10000.0;
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2);
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / displayMaxLuminance;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+// Generate OOTF that modifies the relative scence light to relative display light.
+void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) {
+    if (!needs.needsToneMapping()) {
+        fs << R"__SHADER__(
+            highp vec3 OOTF(const highp vec3 color) {
+                return color;
+            }
+        )__SHADER__";
+    } else {
+        generateToneMappingProcess(fs, needs);
+        fs << R"__SHADER__(
+            highp vec3 OOTF(const highp vec3 color) {
+                return NormalizeLuminance(ToneMap(ScaleLuminance(color)));
+            }
+        )__SHADER__";
+    }
+}
+
+// Generate OETF that converts relative display light to signal values,
+// both normalized to [0, 1]
+void ProgramCache::generateOETF(Formatter& fs, const Key& needs) {
+    switch (needs.getOutputTF()) {
+        case Key::OUTPUT_TF_SRGB:
+            fs << R"__SHADER__(
+                float OETF_sRGB(const float linear) {
+                    return linear <= 0.0031308 ?
+                            linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+                }
+
+                vec3 OETF_sRGB(const vec3 linear) {
+                    return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+                }
+
+                vec3 OETF(const vec3 linear) {
+                    return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                vec3 OETF(const vec3 linear) {
+                    const highp float m1 = (2610.0 / 4096.0) / 4.0;
+                    const highp float m2 = (2523.0 / 4096.0) * 128.0;
+                    const highp float c1 = (3424.0 / 4096.0);
+                    const highp float c2 = (2413.0 / 4096.0) * 32.0;
+                    const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+                    highp vec3 tmp = pow(linear, vec3(m1));
+                    tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+                    return pow(tmp, vec3(m2));
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp float OETF_channel(const highp float channel) {
+                    const highp float a = 0.17883277;
+                    const highp float b = 0.28466892;
+                    const highp float c = 0.55991073;
+                    return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
+                            a * log(12.0 * channel - b) + c;
+                }
+
+                vec3 OETF(const highp vec3 color) {
+                    return vec3(OETF_channel(color.r), OETF_channel(color.g),
+                            OETF_channel(color.b));
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                vec3 OETF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
 String8 ProgramCache::generateVertexShader(const Key& needs) {
     Formatter vs;
     if (needs.isTexturing()) {
-        vs  << "attribute vec4 texCoords;"
-            << "varying vec2 outTexCoords;";
+        vs << "attribute vec4 texCoords;"
+           << "varying vec2 outTexCoords;";
     }
     vs << "attribute vec4 position;"
        << "uniform mat4 projection;"
        << "uniform mat4 texture;"
-       << "void main(void) {" << indent
-       << "gl_Position = projection * position;";
+       << "void main(void) {" << indent << "gl_Position = projection * position;";
     if (needs.isTexturing()) {
         vs << "outTexCoords = (texture * texCoords).st;";
     }
@@ -168,87 +546,99 @@
     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
         fs << "uniform sampler2D sampler;"
            << "varying vec2 outTexCoords;";
-    } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
+    }
+
+    if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
         fs << "uniform vec4 color;";
     }
-    if (needs.hasPlaneAlpha()) {
-        fs << "uniform float alphaPlane;";
+
+    if (needs.isY410BT2020()) {
+        fs << R"__SHADER__(
+            vec3 convertY410BT2020(const vec3 color) {
+                const vec3 offset = vec3(0.0625, 0.5, 0.5);
+                const mat3 transform = mat3(
+                    vec3(1.1678,  1.1678, 1.1678),
+                    vec3(   0.0, -0.1878, 2.1481),
+                    vec3(1.6836, -0.6523,   0.0));
+                // Y is in G, U is in R, and V is in B
+                return clamp(transform * (color.grb - offset), 0.0, 1.0);
+            }
+            )__SHADER__";
     }
-    if (needs.hasColorMatrix()) {
-        fs << "uniform mat4 colorMatrix;";
-    }
-    if (needs.hasColorMatrix()) {
-        // When in wide gamut mode, the color matrix will contain a color space
-        // conversion matrix that needs to be applied in linear space
-        // When not in wide gamut, we can simply no-op the transfer functions
-        // and let the shader compiler get rid of them
-        if (needs.isWideGamut()) {
+
+    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+        // Currently, display maximum luminance is needed when doing tone mapping.
+        if (needs.needsToneMapping()) {
+            fs << "uniform float displayMaxLuminance;";
+        }
+
+        if (needs.hasInputTransformMatrix()) {
+            fs << "uniform mat4 inputTransformMatrix;";
             fs << R"__SHADER__(
-                  float OETF_sRGB(const float linear) {
-                      return linear <= 0.0031308 ?
-                              linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
-                  }
-
-                  vec3 OETF_sRGB(const vec3 linear) {
-                      return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
-                  }
-
-                  vec3 OETF_scRGB(const vec3 linear) {
-                      return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
-                  }
-
-                  float EOTF_sRGB(float srgb) {
-                      return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
-                  }
-
-                  vec3 EOTF_sRGB(const vec3 srgb) {
-                      return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
-                  }
-
-                  vec3 EOTF_scRGB(const vec3 srgb) {
-                      return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
-                  }
+                highp vec3 InputTransform(const highp vec3 color) {
+                    return vec3(inputTransformMatrix * vec4(color, 1.0));
+                }
             )__SHADER__";
         } else {
             fs << R"__SHADER__(
-                  vec3 OETF_scRGB(const vec3 linear) {
-                      return linear;
-                  }
-
-                  vec3 EOTF_scRGB(const vec3 srgb) {
-                      return srgb;
-                  }
+                highp vec3 InputTransform(const highp vec3 color) {
+                    return color;
+                }
             )__SHADER__";
         }
+
+        // the transformation from a wider colorspace to a narrower one can
+        // result in >1.0 or <0.0 pixel values
+        if (needs.hasOutputTransformMatrix()) {
+            fs << "uniform mat4 outputTransformMatrix;";
+            fs << R"__SHADER__(
+                highp vec3 OutputTransform(const highp vec3 color) {
+                    return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
+                }
+            )__SHADER__";
+        } else {
+            fs << R"__SHADER__(
+                highp vec3 OutputTransform(const highp vec3 color) {
+                    return clamp(color, 0.0, 1.0);
+                }
+            )__SHADER__";
+        }
+
+        generateEOTF(fs, needs);
+        generateOOTF(fs, needs);
+        generateOETF(fs, needs);
     }
+
     fs << "void main(void) {" << indent;
     if (needs.isTexturing()) {
         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+        if (needs.isY410BT2020()) {
+            fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);";
+        }
     } else {
-        fs << "gl_FragColor = color;";
+        fs << "gl_FragColor.rgb = color.rgb;";
+        fs << "gl_FragColor.a = 1.0;";
     }
     if (needs.isOpaque()) {
         fs << "gl_FragColor.a = 1.0;";
     }
-    if (needs.hasPlaneAlpha()) {
-        // modulate the alpha value with planeAlpha
+    if (needs.hasAlpha()) {
+        // modulate the current alpha value with alpha set
         if (needs.isPremultiplied()) {
             // ... and the color too if we're premultiplied
-            fs << "gl_FragColor *= alphaPlane;";
+            fs << "gl_FragColor *= color.a;";
         } else {
-            fs << "gl_FragColor.a *= alphaPlane;";
+            fs << "gl_FragColor.a *= color.a;";
         }
     }
 
-    if (needs.hasColorMatrix()) {
+    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // un-premultiply if needed before linearization
             // avoid divide by 0 by adding 0.5/256 to the alpha channel
             fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
         }
-        fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);";
-        // We assume the last row is always {0,0,0,1} and we skip the division by w
-        fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);";
+        fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // and re-premultiply if needed after gamma correction
             fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
@@ -260,6 +650,8 @@
 }
 
 Program* ProgramCache::generateProgram(const Key& needs) {
+    ATRACE_CALL();
+
     // vertex shader
     String8 vs = generateVertexShader(needs);
 
@@ -271,21 +663,20 @@
 }
 
 void ProgramCache::useProgram(const Description& description) {
-
     // generate the key for the shader based on the description
     Key needs(computeKey(description));
 
-     // look-up the program in the cache
+    // look-up the program in the cache
     Program* program = mCache.valueFor(needs);
-    if (program == NULL) {
+    if (program == nullptr) {
         // we didn't find our program, so generate one...
         nsecs_t time = -systemTime();
         program = generateProgram(needs);
         mCache.add(needs, program);
         time += systemTime();
 
-        //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
-        //        needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
+        ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
+              uint32_t(ns2ms(time)), mCache.size());
     }
 
     // here we have a suitable program for this description
@@ -295,5 +686,4 @@
     }
 }
 
-
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 5b0fbcd..983e7ba 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -19,8 +19,8 @@
 
 #include <GLES2/gl2.h>
 
-#include <utils/Singleton.h>
 #include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
 #include <utils/TypeHelpers.h>
 
 #include "Description.h"
@@ -28,6 +28,7 @@
 namespace android {
 
 class Description;
+class Formatter;
 class Program;
 class String8;
 
@@ -47,63 +48,108 @@
         friend class ProgramCache;
         typedef uint32_t key_t;
         key_t mKey;
+
     public:
         enum {
-            BLEND_PREMULT           =       0x00000001,
-            BLEND_NORMAL            =       0x00000000,
-            BLEND_MASK              =       0x00000001,
+            BLEND_SHIFT = 0,
+            BLEND_MASK = 1 << BLEND_SHIFT,
+            BLEND_PREMULT = 1 << BLEND_SHIFT,
+            BLEND_NORMAL = 0 << BLEND_SHIFT,
 
-            OPACITY_OPAQUE          =       0x00000002,
-            OPACITY_TRANSLUCENT     =       0x00000000,
-            OPACITY_MASK            =       0x00000002,
+            OPACITY_SHIFT = 1,
+            OPACITY_MASK = 1 << OPACITY_SHIFT,
+            OPACITY_OPAQUE = 1 << OPACITY_SHIFT,
+            OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT,
 
-            PLANE_ALPHA_LT_ONE      =       0x00000004,
-            PLANE_ALPHA_EQ_ONE      =       0x00000000,
-            PLANE_ALPHA_MASK        =       0x00000004,
+            ALPHA_SHIFT = 2,
+            ALPHA_MASK = 1 << ALPHA_SHIFT,
+            ALPHA_LT_ONE = 1 << ALPHA_SHIFT,
+            ALPHA_EQ_ONE = 0 << ALPHA_SHIFT,
 
-            TEXTURE_OFF             =       0x00000000,
-            TEXTURE_EXT             =       0x00000008,
-            TEXTURE_2D              =       0x00000010,
-            TEXTURE_MASK            =       0x00000018,
+            TEXTURE_SHIFT = 3,
+            TEXTURE_MASK = 3 << TEXTURE_SHIFT,
+            TEXTURE_OFF = 0 << TEXTURE_SHIFT,
+            TEXTURE_EXT = 1 << TEXTURE_SHIFT,
+            TEXTURE_2D = 2 << TEXTURE_SHIFT,
 
-            COLOR_MATRIX_OFF        =       0x00000000,
-            COLOR_MATRIX_ON         =       0x00000020,
-            COLOR_MATRIX_MASK       =       0x00000020,
+            INPUT_TRANSFORM_MATRIX_SHIFT = 5,
+            INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
+            INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
+            INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
 
-            WIDE_GAMUT_OFF          =       0x00000000,
-            WIDE_GAMUT_ON           =       0x00000040,
-            WIDE_GAMUT_MASK         =       0x00000040,
+            OUTPUT_TRANSFORM_MATRIX_SHIFT = 6,
+            OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+            OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+            OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+
+            INPUT_TF_SHIFT = 7,
+            INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
+            INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
+            INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
+            INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
+            INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
+
+            OUTPUT_TF_SHIFT = 9,
+            OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
+
+            Y410_BT2020_SHIFT = 11,
+            Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
+            Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
+            Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
         };
 
-        inline Key() : mKey(0) { }
-        inline Key(const Key& rhs) : mKey(rhs.mKey) { }
+        inline Key() : mKey(0) {}
+        inline Key(const Key& rhs) : mKey(rhs.mKey) {}
 
         inline Key& set(key_t mask, key_t value) {
             mKey = (mKey & ~mask) | value;
             return *this;
         }
 
-        inline bool isTexturing() const {
-            return (mKey & TEXTURE_MASK) != TEXTURE_OFF;
+        inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+        inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
+        inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
+        inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
+        inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
+        inline bool hasInputTransformMatrix() const {
+            return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
         }
-        inline int getTextureTarget() const {
-            return (mKey & TEXTURE_MASK);
+        inline bool hasOutputTransformMatrix() const {
+            return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
         }
-        inline bool isPremultiplied() const {
-            return (mKey & BLEND_MASK) == BLEND_PREMULT;
+        inline bool hasTransformMatrix() const {
+            return hasInputTransformMatrix() || hasOutputTransformMatrix();
         }
-        inline bool isOpaque() const {
-            return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
+        inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
+        inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
+
+        // When HDR and non-HDR contents are mixed, or different types of HDR contents are
+        // mixed, we will do a tone mapping process to tone map the input content to output
+        // content. Currently, the following conversions handled, they are:
+        // * SDR -> HLG
+        // * SDR -> PQ
+        // * HLG -> PQ
+        inline bool needsToneMapping() const {
+            int inputTF = getInputTF();
+            int outputTF = getOutputTF();
+
+            // Return false when converting from SDR to SDR.
+            if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
+                return false;
+            }
+            if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
+                return false;
+            }
+
+            inputTF >>= Key::INPUT_TF_SHIFT;
+            outputTF >>= Key::OUTPUT_TF_SHIFT;
+            return inputTF != outputTF;
         }
-        inline bool hasPlaneAlpha() const {
-            return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE;
-        }
-        inline bool hasColorMatrix() const {
-            return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
-        }
-        inline bool isWideGamut() const {
-            return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON;
-        }
+        inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
 
         // this is the definition of a friend function -- not a method of class Needs
         friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
@@ -114,15 +160,24 @@
     ProgramCache();
     ~ProgramCache();
 
+    // Generate shaders to populate the cache
+    void primeCache(bool hasWideColor);
+
     // useProgram lookup a suitable program in the cache or generates one
     // if none can be found.
     void useProgram(const Description& description);
 
 private:
-    // Generate shaders to populate the cache
-    void primeCache();
     // compute a cache Key from a Description
     static Key computeKey(const Description& description);
+    // Generate EOTF based from Key.
+    static void generateEOTF(Formatter& fs, const Key& needs);
+    // Generate necessary tone mapping methods for OOTF.
+    static void generateToneMappingProcess(Formatter& fs, const Key& needs);
+    // Generate OOTF based from Key.
+    static void generateOOTF(Formatter& fs, const Key& needs);
+    // Generate OETF based from Key.
+    static void generateOETF(Formatter& fs, const Key& needs);
     // generates a program from the Key
     static Program* generateProgram(const Key& needs);
     // generates the vertex shader from the Key
@@ -135,7 +190,6 @@
     DefaultKeyedVector<Key, Program*> mCache;
 };
 
-
 ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 56e9ac0..d745770 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -18,60 +18,54 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
-#include "RenderEngine.h"
 #include "GLES20RenderEngine.h"
 #include "GLExtensions.h"
+#include "Image.h"
 #include "Mesh.h"
+#include "RenderEngine.h"
 
-#include <vector>
 #include <SurfaceFlinger.h>
+#include <vector>
+
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
 // ---------------------------------------------------------------------------
 namespace android {
+namespace RE {
 // ---------------------------------------------------------------------------
 
-static bool findExtension(const char* exts, const char* name) {
-    if (!exts)
-        return false;
-    size_t len = strlen(name);
+RenderEngine::~RenderEngine() = default;
 
-    const char* pos = exts;
-    while ((pos = strstr(pos, name)) != NULL) {
-        if (pos[len] == '\0' || pos[len] == ' ')
-            return true;
-        pos += len;
+namespace impl {
+
+std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+    // initialize EGL for the default display
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (!eglInitialize(display, nullptr, nullptr)) {
+        LOG_ALWAYS_FATAL("failed to initialize EGL");
     }
 
-    return false;
-}
+    GLExtensions& extensions = GLExtensions::getInstance();
+    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
 
-RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) {
-    // EGL_ANDROIDX_no_config_context is an experimental extension with no
-    // written specification. It will be replaced by something more formal.
-    // SurfaceFlinger is using it to allow a single EGLContext to render to
-    // both a 16-bit primary display framebuffer and a 32-bit virtual display
-    // framebuffer.
-    //
-    // EGL_KHR_no_config_context is official extension to allow creating a
-    // context that works with any surface of a display.
-    //
     // The code assumes that ES2 or later is available if this extension is
     // supported.
     EGLConfig config = EGL_NO_CONFIG;
-    if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
-                       "EGL_ANDROIDX_no_config_context") &&
-        !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
-                       "EGL_KHR_no_config_context")) {
+    if (!extensions.hasNoConfigContext()) {
         config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
 
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG) {
         renderableType = EGL_OPENGL_ES2_BIT;
-    } else if (!eglGetConfigAttrib(display, config,
-            EGL_RENDERABLE_TYPE, &renderableType)) {
+    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
         LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
     }
     EGLint contextClientVersion = 0;
@@ -87,21 +81,17 @@
     contextAttributes.reserve(6);
     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
     contextAttributes.push_back(contextClientVersion);
-#ifdef EGL_IMG_context_priority
-    if (SurfaceFlinger::useContextPriority) {
+    bool useContextPriority = overrideUseContextPriorityFromConfig(extensions.hasContextPriority());
+    if (useContextPriority) {
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
     }
-#endif
-    contextAttributes.push_back(EGL_NONE);
     contextAttributes.push_back(EGL_NONE);
 
-    EGLContext ctxt = eglCreateContext(display, config, NULL,
-                                       contextAttributes.data());
+    EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
 
     // if can't create a GL context, we can only abort.
-    LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
-
+    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
 
     // now figure out what version of GL did we actually get
     // NOTE: a dummy surface is not needed if KHR_create_context is supported
@@ -110,41 +100,37 @@
     if (dummyConfig == EGL_NO_CONFIG) {
         dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
-    EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
+    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
     EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
-    LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer");
+    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
 
-    GLExtensions& extensions(GLExtensions::getInstance());
-    extensions.initWithGLStrings(
-            glGetString(GL_VENDOR),
-            glGetString(GL_RENDERER),
-            glGetString(GL_VERSION),
-            glGetString(GL_EXTENSIONS));
+    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
-    GlesVersion version = parseGlesVersion( extensions.getVersion() );
+    GlesVersion version = parseGlesVersion(extensions.getVersion());
 
     // initialize the renderer while GL is current
 
-    RenderEngine* engine = NULL;
+    std::unique_ptr<RenderEngine> engine;
     switch (version) {
-    case GLES_VERSION_1_0:
-    case GLES_VERSION_1_1:
-        LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
-        break;
-    case GLES_VERSION_2_0:
-    case GLES_VERSION_3_0:
-        engine = new GLES20RenderEngine(featureFlags);
-        break;
+        case GLES_VERSION_1_0:
+        case GLES_VERSION_1_1:
+            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+            break;
+        case GLES_VERSION_2_0:
+        case GLES_VERSION_3_0:
+            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+            break;
     }
-    engine->setEGLHandles(config, ctxt);
+    engine->setEGLHandles(display, config, ctxt);
 
     ALOGI("OpenGL ES informations:");
     ALOGI("vendor    : %s", extensions.getVendor());
     ALOGI("renderer  : %s", extensions.getRenderer());
     ALOGI("version   : %s", extensions.getVersion());
-    ALOGI("extensions: %s", extensions.getExtension());
+    ALOGI("extensions: %s", extensions.getExtensions());
     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
 
@@ -154,31 +140,168 @@
     return engine;
 }
 
-RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {
+bool RenderEngine::overrideUseContextPriorityFromConfig(bool useContextPriority) {
+    OptionalBool ret;
+    ISurfaceFlingerConfigs::getService()->useContextPriority([&ret](OptionalBool b) { ret = b; });
+    if (ret.specified) {
+        return ret.value;
+    } else {
+        return useContextPriority;
+    }
 }
 
+RenderEngine::RenderEngine(uint32_t featureFlags)
+      : mEGLDisplay(EGL_NO_DISPLAY),
+        mEGLConfig(nullptr),
+        mEGLContext(EGL_NO_CONTEXT),
+        mFeatureFlags(featureFlags) {}
+
 RenderEngine::~RenderEngine() {
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEGLDisplay);
 }
 
-void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) {
+void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
+    mEGLDisplay = display;
     mEGLConfig = config;
     mEGLContext = ctxt;
 }
 
-EGLContext RenderEngine::getEGLConfig() const {
+EGLDisplay RenderEngine::getEGLDisplay() const {
+    return mEGLDisplay;
+}
+
+EGLConfig RenderEngine::getEGLConfig() const {
     return mEGLConfig;
 }
 
-EGLContext RenderEngine::getEGLContext() const {
-    return mEGLContext;
+bool RenderEngine::supportsImageCrop() const {
+    return GLExtensions::getInstance().hasImageCrop();
+}
+
+bool RenderEngine::isCurrent() const {
+    return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
+std::unique_ptr<RE::Surface> RenderEngine::createSurface() {
+    return std::make_unique<Surface>(*this);
+}
+
+std::unique_ptr<RE::Image> RenderEngine::createImage() {
+    return std::make_unique<Image>(*this);
+}
+
+bool RenderEngine::setCurrentSurface(const android::RE::Surface& surface) {
+    // Note: RE::Surface is an abstract interface. This implementation only ever
+    // creates RE::impl::Surface's, so it is safe to just cast to the actual
+    // type.
+    return setCurrentSurface(static_cast<const android::RE::impl::Surface&>(surface));
+}
+
+bool RenderEngine::setCurrentSurface(const android::RE::impl::Surface& surface) {
+    bool success = true;
+    EGLSurface eglSurface = surface.getEGLSurface();
+    if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
+        success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
+        if (success && surface.getAsync()) {
+            eglSwapInterval(mEGLDisplay, 0);
+        }
+    }
+
+    return success;
+}
+
+void RenderEngine::resetCurrentSurface() {
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+base::unique_fd RenderEngine::flush() {
+    if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+        return base::unique_fd();
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+        return base::unique_fd();
+    }
+
+    // native fence fd will not be populated until flush() is done.
+    glFlush();
+
+    // get the fence fd
+    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+    }
+
+    return fenceFd;
+}
+
+bool RenderEngine::finish() {
+    if (!GLExtensions::getInstance().hasFenceSync()) {
+        ALOGW("no synchronization support");
+        return false;
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                         2000000000 /*2 sec*/);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (result != EGL_CONDITION_SATISFIED_KHR) {
+        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGW("fence wait timed out");
+        } else {
+            ALOGW("error waiting on EGL fence: %#x", error);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool RenderEngine::waitFence(base::unique_fd fenceFd) {
+    if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+        !GLExtensions::getInstance().hasWaitSync()) {
+        return false;
+    }
+
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    // fenceFd is now owned by EGLSync
+    (void)fenceFd.release();
+
+    // XXX: The spec draft is inconsistent as to whether this should return an
+    // EGLint or void.  Ignore the return value for now, as it's not strictly
+    // needed.
+    eglWaitSyncKHR(mEGLDisplay, sync, 0);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (error != EGL_SUCCESS) {
+        ALOGE("failed to wait for EGL native fence sync: %#x", error);
+        return false;
+    }
+
+    return true;
 }
 
 void RenderEngine::checkErrors() const {
     do {
         // there could be more than one error flag
         GLenum error = glGetError();
-        if (error == GL_NO_ERROR)
-            break;
+        if (error == GL_NO_ERROR) break;
         ALOGE("GL error 0x%04x", int(error));
     } while (true);
 }
@@ -201,41 +324,36 @@
     return GLES_VERSION_1_0;
 }
 
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height,
-        float red, float green, float blue, float alpha) {
+void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
+                                       float green, float blue, float alpha) {
     size_t c;
     Rect const* r = region.getArray(&c);
-    Mesh mesh(Mesh::TRIANGLES, c*6, 2);
+    Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    for (size_t i=0 ; i<c ; i++, r++) {
-        position[i*6 + 0].x = r->left;
-        position[i*6 + 0].y = height - r->top;
-        position[i*6 + 1].x = r->left;
-        position[i*6 + 1].y = height - r->bottom;
-        position[i*6 + 2].x = r->right;
-        position[i*6 + 2].y = height - r->bottom;
-        position[i*6 + 3].x = r->left;
-        position[i*6 + 3].y = height - r->top;
-        position[i*6 + 4].x = r->right;
-        position[i*6 + 4].y = height - r->bottom;
-        position[i*6 + 5].x = r->right;
-        position[i*6 + 5].y = height - r->top;
+    for (size_t i = 0; i < c; i++, r++) {
+        position[i * 6 + 0].x = r->left;
+        position[i * 6 + 0].y = height - r->top;
+        position[i * 6 + 1].x = r->left;
+        position[i * 6 + 1].y = height - r->bottom;
+        position[i * 6 + 2].x = r->right;
+        position[i * 6 + 2].y = height - r->bottom;
+        position[i * 6 + 3].x = r->left;
+        position[i * 6 + 3].y = height - r->top;
+        position[i * 6 + 4].x = r->right;
+        position[i * 6 + 4].y = height - r->bottom;
+        position[i * 6 + 5].x = r->right;
+        position[i * 6 + 5].y = height - r->top;
     }
     setupFillWithColor(red, green, blue, alpha);
     drawMesh(mesh);
 }
 
-void RenderEngine::flush() {
-    glFlush();
-}
-
 void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
     glClearColor(red, green, blue, alpha);
     glClear(GL_COLOR_BUFFER_BIT);
 }
 
-void RenderEngine::setScissor(
-        uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
     glScissor(left, bottom, right, top);
     glEnable(GL_SCISSOR_TEST);
 }
@@ -252,67 +370,102 @@
     glDeleteTextures(count, names);
 }
 
+void RenderEngine::bindExternalTextureImage(uint32_t texName, const android::RE::Image& image) {
+    // Note: RE::Image is an abstract interface. This implementation only ever
+    // creates RE::impl::Image's, so it is safe to just cast to the actual type.
+    return bindExternalTextureImage(texName, static_cast<const android::RE::impl::Image&>(image));
+}
+
+void RenderEngine::bindExternalTextureImage(uint32_t texName,
+                                            const android::RE::impl::Image& image) {
+    const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+    glBindTexture(target, texName);
+    if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
+        glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
+    }
+}
+
 void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
     glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 }
 
 void RenderEngine::dump(String8& result) {
-    const GLExtensions& extensions(GLExtensions::getInstance());
-    result.appendFormat("GLES: %s, %s, %s\n",
-            extensions.getVendor(),
-            extensions.getRenderer(),
-            extensions.getVersion());
-    result.appendFormat("%s\n", extensions.getExtension());
+    const GLExtensions& extensions = GLExtensions::getInstance();
+
+    result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
+    result.appendFormat("%s\n", extensions.getEGLExtensions());
+
+    result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                        extensions.getVersion());
+    result.appendFormat("%s\n", extensions.getExtensions());
 }
 
 // ---------------------------------------------------------------------------
 
-RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
-        RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
-{
-    mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus);
+void RenderEngine::bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
+                                                 RE::BindNativeBufferAsFramebuffer* bindHelper) {
+    bindHelper->mImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                           buffer, nullptr);
+    if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
+        bindHelper->mStatus = NO_MEMORY;
+        return;
+    }
 
-    ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
-            "glCheckFramebufferStatusOES error %d", mStatus);
+    uint32_t glStatus;
+    bindImageAsFramebuffer(bindHelper->mImage, &bindHelper->mTexName, &bindHelper->mFbName,
+                           &glStatus);
+
+    ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+             glStatus);
+
+    bindHelper->mStatus = glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
 }
 
-RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
+void RenderEngine::unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) {
+    if (bindHelper->mImage == EGL_NO_IMAGE_KHR) {
+        return;
+    }
+
     // back to main framebuffer
-    mEngine.unbindFramebuffer(mTexName, mFbName);
-}
+    unbindFramebuffer(bindHelper->mTexName, bindHelper->mFbName);
+    eglDestroyImageKHR(mEGLDisplay, bindHelper->mImage);
 
-status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
-    return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
+    // Workaround for b/77935566 to force the EGL driver to release the
+    // screenshot buffer
+    setScissor(0, 0, 0, 0);
+    clearWithColor(0.0, 0.0, 0.0, 0.0);
+    disableScissor();
 }
 
 // ---------------------------------------------------------------------------
 
-static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs,
-        EGLint attribute, EGLint wanted, EGLConfig* outConfig) {
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+                                         EGLint wanted, EGLConfig* outConfig) {
     EGLint numConfigs = -1, n = 0;
-    eglGetConfigs(dpy, NULL, 0, &numConfigs);
+    eglGetConfigs(dpy, nullptr, 0, &numConfigs);
     EGLConfig* const configs = new EGLConfig[numConfigs];
     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
 
     if (n) {
         if (attribute != EGL_NONE) {
-            for (int i=0 ; i<n ; i++) {
+            for (int i = 0; i < n; i++) {
                 EGLint value = 0;
                 eglGetConfigAttrib(dpy, configs[i], attribute, &value);
                 if (wanted == value) {
                     *outConfig = configs[i];
-                    delete [] configs;
+                    delete[] configs;
                     return NO_ERROR;
                 }
             }
         } else {
             // just pick the first one
             *outConfig = configs[0];
-            delete [] configs;
+            delete[] configs;
             return NO_ERROR;
         }
     }
-    delete [] configs;
+    delete[] configs;
     return NAME_NOT_FOUND;
 }
 
@@ -322,10 +475,10 @@
     friend class Adder;
     KeyedVector<Attribute, EGLint> mList;
     struct Attribute {
-        Attribute() : v(0) {};
-        explicit Attribute(EGLint v) : v(v) { }
+        Attribute() : v(0){};
+        explicit Attribute(EGLint v) : v(v) {}
         EGLint v;
-        bool operator < (const Attribute& other) const {
+        bool operator<(const Attribute& other) const {
             // this places EGL_NONE at the end
             EGLint lhs(v);
             EGLint rhs(other.v);
@@ -338,39 +491,32 @@
         friend class EGLAttributeVector;
         EGLAttributeVector& v;
         EGLint attribute;
-        Adder(EGLAttributeVector& v, EGLint attribute)
-            : v(v), attribute(attribute) {
-        }
+        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
     public:
-        void operator = (EGLint value) {
+        void operator=(EGLint value) {
             if (attribute != EGL_NONE) {
                 v.mList.add(Attribute(attribute), value);
             }
         }
-        operator EGLint () const { return v.mList[attribute]; }
+        operator EGLint() const { return v.mList[attribute]; }
     };
+
 public:
-    EGLAttributeVector() {
-        mList.add(Attribute(EGL_NONE), EGL_NONE);
-    }
+    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
     void remove(EGLint attribute) {
         if (attribute != EGL_NONE) {
             mList.removeItem(Attribute(attribute));
         }
     }
-    Adder operator [] (EGLint attribute) {
-        return Adder(*this, attribute);
-    }
-    EGLint operator [] (EGLint attribute) const {
-       return mList[attribute];
-    }
+    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
     // cast-operator to (EGLint const*)
-    operator EGLint const* () const { return &mList.keyAt(0).v; }
+    operator EGLint const*() const { return &mList.keyAt(0).v; }
 };
 
-
-static status_t selectEGLConfig(EGLDisplay display, EGLint format,
-    EGLint renderableType, EGLConfig* config) {
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+                                EGLConfig* config) {
     // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
     // it is to be used with WIFI displays
     status_t err;
@@ -379,24 +525,23 @@
 
     EGLAttributeVector attribs;
     if (renderableType) {
-        attribs[EGL_RENDERABLE_TYPE]            = renderableType;
-        attribs[EGL_RECORDABLE_ANDROID]         = EGL_TRUE;
-        attribs[EGL_SURFACE_TYPE]               = EGL_WINDOW_BIT|EGL_PBUFFER_BIT;
+        attribs[EGL_RENDERABLE_TYPE] = renderableType;
+        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
         attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
-        attribs[EGL_RED_SIZE]                   = 8;
-        attribs[EGL_GREEN_SIZE]                 = 8;
-        attribs[EGL_BLUE_SIZE]                  = 8;
-        attribs[EGL_ALPHA_SIZE]                 = 8;
-        wantedAttribute                         = EGL_NONE;
-        wantedAttributeValue                    = EGL_NONE;
+        attribs[EGL_RED_SIZE] = 8;
+        attribs[EGL_GREEN_SIZE] = 8;
+        attribs[EGL_BLUE_SIZE] = 8;
+        attribs[EGL_ALPHA_SIZE] = 8;
+        wantedAttribute = EGL_NONE;
+        wantedAttributeValue = EGL_NONE;
     } else {
         // if no renderable type specified, fallback to a simplified query
-        wantedAttribute                         = EGL_NATIVE_VISUAL_ID;
-        wantedAttributeValue                    = format;
+        wantedAttribute = EGL_NATIVE_VISUAL_ID;
+        wantedAttributeValue = format;
     }
 
-    err = selectConfigForAttribute(display, attribs,
-            wantedAttribute, wantedAttributeValue, config);
+    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
     if (err == NO_ERROR) {
         EGLint caveat;
         if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
@@ -406,8 +551,7 @@
     return err;
 }
 
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format,
-                                        bool logConfig) {
+EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
     status_t err;
     EGLConfig config;
 
@@ -430,29 +574,28 @@
 
     if (logConfig) {
         // print some debugging info
-        EGLint r,g,b,a;
-        eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
+        EGLint r, g, b, a;
+        eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
         eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
-        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
+        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
         eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
         ALOGI("EGL information:");
         ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
         ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
         ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
-        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
         ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
     }
 
     return config;
 }
 
-
 void RenderEngine::primeCache() const {
-    // Getting the ProgramCache instance causes it to prime its shader cache,
-    // which is performed in its constructor
-    ProgramCache::getInstance();
+    ProgramCache::getInstance().primeCache(mFeatureFlags & WIDE_COLOR_SUPPORT);
 }
 
 // ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
+
+} // namespace impl
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 9544579..1786155 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -14,20 +14,25 @@
  * limitations under the License.
  */
 
-
 #ifndef SF_RENDERENGINE_H_
 #define SF_RENDERENGINE_H_
 
+#include <memory>
+
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <math/mat4.h>
 #include <Transform.h>
+#include <android-base/unique_fd.h>
+#include <gui/SurfaceControl.h>
+#include <math/mat4.h>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
+struct ANativeWindowBuffer;
+
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -38,101 +43,211 @@
 class Mesh;
 class Texture;
 
+namespace RE {
+
+class Image;
+class Surface;
+class BindNativeBufferAsFramebuffer;
+
+namespace impl {
+class RenderEngine;
+}
+
 class RenderEngine {
-    enum GlesVersion {
-        GLES_VERSION_1_0    = 0x10000,
-        GLES_VERSION_1_1    = 0x10001,
-        GLES_VERSION_2_0    = 0x20000,
-        GLES_VERSION_3_0    = 0x30000,
-    };
-    static GlesVersion parseGlesVersion(const char* str);
-
-    EGLConfig mEGLConfig;
-    EGLContext mEGLContext;
-    void setEGLHandles(EGLConfig config, EGLContext ctxt);
-
-    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0;
-    virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
-
-protected:
-    RenderEngine();
-    virtual ~RenderEngine() = 0;
-
 public:
     enum FeatureFlag {
         WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
     };
-    static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
 
-    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+    virtual ~RenderEngine() = 0;
 
-    void primeCache() const;
+    virtual std::unique_ptr<RE::Surface> createSurface() = 0;
+    virtual std::unique_ptr<RE::Image> createImage() = 0;
+
+    virtual void primeCache() const = 0;
 
     // dump the extension strings. always call the base class.
-    virtual void dump(String8& result);
+    virtual void dump(String8& result) = 0;
+
+    virtual bool supportsImageCrop() const = 0;
+
+    virtual bool isCurrent() const = 0;
+    virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
+    virtual void resetCurrentSurface() = 0;
 
     // helpers
-    void flush();
-    void clearWithColor(float red, float green, float blue, float alpha);
-    void fillRegionWithColor(const Region& region, uint32_t height,
-            float red, float green, float blue, float alpha);
+    // flush submits RenderEngine command stream for execution and returns a
+    // native fence fd that is signaled when the execution has completed.  It
+    // returns -1 on errors.
+    virtual base::unique_fd flush() = 0;
+    // finish waits until RenderEngine command stream has been executed.  It
+    // returns false on errors.
+    virtual bool finish() = 0;
+    // waitFence inserts a wait on an external fence fd to RenderEngine
+    // command stream.  It returns false on errors.
+    virtual bool waitFence(base::unique_fd fenceFd) = 0;
+
+    virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
+    virtual void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+                                     float blue, float alpha) = 0;
 
     // common to all GL versions
-    void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top);
-    void disableScissor();
-    void genTextures(size_t count, uint32_t* names);
-    void deleteTextures(size_t count, uint32_t const* names);
-    void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
-
-    class BindImageAsFramebuffer {
-        RenderEngine& mEngine;
-        uint32_t mTexName, mFbName;
-        uint32_t mStatus;
-    public:
-        BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image);
-        ~BindImageAsFramebuffer();
-        int getStatus() const;
-    };
+    virtual void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) = 0;
+    virtual void disableScissor() = 0;
+    virtual void genTextures(size_t count, uint32_t* names) = 0;
+    virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
+    virtual void bindExternalTextureImage(uint32_t texName, const RE::Image& image) = 0;
+    virtual void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) = 0;
+    virtual void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
+                                               RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
+    virtual void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) = 0;
 
     // set-up
     virtual void checkErrors() const;
-    virtual void setViewportAndProjection(size_t vpw, size_t vph,
-            Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
-#ifdef USE_HWC2
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
-    virtual void setupDimLayerBlending(float alpha) = 0;
-    virtual void setColorMode(android_color_mode mode) = 0;
-    virtual void setSourceDataSpace(android_dataspace source) = 0;
-    virtual void setWideColor(bool hasWideColor) = 0;
-    virtual bool usesWideColor() = 0;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
-    virtual void setupDimLayerBlending(int alpha) = 0;
-#endif
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+                                          bool yswap, Transform::orientation_flags rotation) = 0;
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                    const half4& color) = 0;
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
-    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
-        return mat4();
-    }
+    virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
 
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
+    // HDR and wide color gamut support
+    virtual void setSourceY410BT2020(bool enable) = 0;
+    virtual void setSourceDataSpace(ui::Dataspace source) = 0;
+    virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
+    virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
+
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
-
-    EGLConfig getEGLConfig() const;
-    EGLContext getEGLContext() const;
 };
 
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
+class BindNativeBufferAsFramebuffer {
+public:
+    BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
+          : mEngine(engine) {
+        mEngine.bindNativeBufferAsFrameBuffer(buffer, this);
+    }
+    ~BindNativeBufferAsFramebuffer() { mEngine.unbindNativeBufferAsFrameBuffer(this); }
+    status_t getStatus() const { return mStatus; }
+
+protected:
+    friend impl::RenderEngine;
+
+    RenderEngine& mEngine;
+    EGLImageKHR mImage;
+    uint32_t mTexName, mFbName;
+    status_t mStatus;
+};
+
+namespace impl {
+
+class Image;
+class Surface;
+
+class RenderEngine : public RE::RenderEngine {
+    enum GlesVersion {
+        GLES_VERSION_1_0 = 0x10000,
+        GLES_VERSION_1_1 = 0x10001,
+        GLES_VERSION_2_0 = 0x20000,
+        GLES_VERSION_3_0 = 0x30000,
+    };
+    static GlesVersion parseGlesVersion(const char* str);
+
+    EGLDisplay mEGLDisplay;
+    EGLConfig mEGLConfig;
+    EGLContext mEGLContext;
+    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
+
+    static bool overrideUseContextPriorityFromConfig(bool useContextPriority);
+
+protected:
+    RenderEngine(uint32_t featureFlags);
+
+    const uint32_t mFeatureFlags;
+
+public:
+    virtual ~RenderEngine() = 0;
+
+    static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+
+    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+
+    // RenderEngine interface implementation
+
+    std::unique_ptr<RE::Surface> createSurface() override;
+    std::unique_ptr<RE::Image> createImage() override;
+
+    void primeCache() const override;
+
+    // dump the extension strings. always call the base class.
+    void dump(String8& result) override;
+
+    bool supportsImageCrop() const override;
+
+    bool isCurrent() const;
+    bool setCurrentSurface(const RE::Surface& surface) override;
+    void resetCurrentSurface() override;
+
+    // synchronization
+
+    // flush submits RenderEngine command stream for execution and returns a
+    // native fence fd that is signaled when the execution has completed.  It
+    // returns -1 on errors.
+    base::unique_fd flush() override;
+    // finish waits until RenderEngine command stream has been executed.  It
+    // returns false on errors.
+    bool finish() override;
+    // waitFence inserts a wait on an external fence fd to RenderEngine
+    // command stream.  It returns false on errors.
+    bool waitFence(base::unique_fd fenceFd) override;
+
+    // helpers
+    void clearWithColor(float red, float green, float blue, float alpha) override;
+    void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+                             float blue, float alpha) override;
+
+    // common to all GL versions
+    void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
+    void disableScissor() override;
+    void genTextures(size_t count, uint32_t* names) override;
+    void deleteTextures(size_t count, uint32_t const* names) override;
+    void bindExternalTextureImage(uint32_t texName, const RE::Image& image) override;
+    void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) override;
+
+    void checkErrors() const override;
+
+    void setupColorTransform(const mat4& /* colorTransform */) override {}
+
+    // internal to RenderEngine
+    EGLDisplay getEGLDisplay() const;
+    EGLConfig getEGLConfig() const;
+
+    // Common implementation
+    bool setCurrentSurface(const RE::impl::Surface& surface);
+    void bindExternalTextureImage(uint32_t texName, const RE::impl::Image& image);
+
+    void bindNativeBufferAsFrameBuffer(ANativeWindowBuffer* buffer,
+                                       RE::BindNativeBufferAsFramebuffer* bindHelper) override;
+    void unbindNativeBufferAsFrameBuffer(RE::BindNativeBufferAsFramebuffer* bindHelper) override;
+
+    // Overriden by each specialization
+    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+                                        uint32_t* status) = 0;
+    virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
+};
+
+} // namespace impl
+} // namespace RE
+} // namespace android
 
 #endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp
new file mode 100644
index 0000000..0d20f1f
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Surface.h"
+
+#include "RenderEngine.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace RE {
+
+Surface::~Surface() = default;
+
+namespace impl {
+
+Surface::Surface(const RenderEngine& engine)
+      : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
+    // RE does not assume any config when EGL_KHR_no_config_context is supported
+    if (mEGLConfig == EGL_NO_CONFIG_KHR) {
+        mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
+    }
+}
+
+Surface::~Surface() {
+    setNativeWindow(nullptr);
+}
+
+void Surface::setNativeWindow(ANativeWindow* window) {
+    if (mEGLSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(mEGLDisplay, mEGLSurface);
+        mEGLSurface = EGL_NO_SURFACE;
+    }
+
+    mWindow = window;
+    if (mWindow) {
+        mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr);
+    }
+}
+
+void Surface::swapBuffers() const {
+    if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
+        EGLint error = eglGetError();
+
+        const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x";
+        if (mCritical || error == EGL_CONTEXT_LOST) {
+            LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error);
+        } else {
+            ALOGE(format, mEGLDisplay, mEGLSurface, error);
+        }
+    }
+}
+
+EGLint Surface::queryConfig(EGLint attrib) const {
+    EGLint value;
+    if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+EGLint Surface::querySurface(EGLint attrib) const {
+    EGLint value;
+    if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+int32_t Surface::queryRedSize() const {
+    return queryConfig(EGL_RED_SIZE);
+}
+
+int32_t Surface::queryGreenSize() const {
+    return queryConfig(EGL_GREEN_SIZE);
+}
+
+int32_t Surface::queryBlueSize() const {
+    return queryConfig(EGL_BLUE_SIZE);
+}
+
+int32_t Surface::queryAlphaSize() const {
+    return queryConfig(EGL_ALPHA_SIZE);
+}
+
+int32_t Surface::queryWidth() const {
+    return querySurface(EGL_WIDTH);
+}
+
+int32_t Surface::queryHeight() const {
+    return querySurface(EGL_HEIGHT);
+}
+
+} // namespace impl
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.h b/services/surfaceflinger/RenderEngine/Surface.h
new file mode 100644
index 0000000..d4d3d8c
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+
+struct ANativeWindow;
+
+namespace android {
+namespace RE {
+
+class Surface {
+public:
+    virtual ~Surface() = 0;
+
+    virtual void setCritical(bool enable) = 0;
+    virtual void setAsync(bool enable) = 0;
+
+    virtual void setNativeWindow(ANativeWindow* window) = 0;
+    virtual void swapBuffers() const = 0;
+
+    virtual int32_t queryRedSize() const = 0;
+    virtual int32_t queryGreenSize() const = 0;
+    virtual int32_t queryBlueSize() const = 0;
+    virtual int32_t queryAlphaSize() const = 0;
+
+    virtual int32_t queryWidth() const = 0;
+    virtual int32_t queryHeight() const = 0;
+};
+
+namespace impl {
+
+class RenderEngine;
+
+class Surface final : public RE::Surface {
+public:
+    Surface(const RenderEngine& engine);
+    ~Surface();
+
+    Surface(const Surface&) = delete;
+    Surface& operator=(const Surface&) = delete;
+
+    // RE::Surface implementation
+    void setCritical(bool enable) override { mCritical = enable; }
+    void setAsync(bool enable) override { mAsync = enable; }
+
+    void setNativeWindow(ANativeWindow* window) override;
+    void swapBuffers() const override;
+
+    int32_t queryRedSize() const override;
+    int32_t queryGreenSize() const override;
+    int32_t queryBlueSize() const override;
+    int32_t queryAlphaSize() const override;
+
+    int32_t queryWidth() const override;
+    int32_t queryHeight() const override;
+
+private:
+    EGLint queryConfig(EGLint attrib) const;
+    EGLint querySurface(EGLint attrib) const;
+
+    // methods internal to RenderEngine
+    friend class RenderEngine;
+    bool getAsync() const { return mAsync; }
+    EGLSurface getEGLSurface() const { return mEGLSurface; }
+
+    EGLDisplay mEGLDisplay;
+    EGLConfig mEGLConfig;
+
+    bool mCritical = false;
+    bool mAsync = false;
+
+    ANativeWindow* mWindow = nullptr;
+    EGLSurface mEGLSurface = EGL_NO_SURFACE;
+};
+
+} // namespace impl
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp
index 8875b6d..351430f 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/services/surfaceflinger/RenderEngine/Texture.cpp
@@ -20,24 +20,22 @@
 
 namespace android {
 
-Texture::Texture() :
-    mTextureName(0), mTextureTarget(TEXTURE_2D),
-    mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture()
+      : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
 
-Texture::Texture(Target textureTarget, uint32_t textureName) :
-            mTextureName(textureName), mTextureTarget(textureTarget),
-            mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture(Target textureTarget, uint32_t textureName)
+      : mTextureName(textureName),
+        mTextureTarget(textureTarget),
+        mWidth(0),
+        mHeight(0),
+        mFiltering(false) {}
 
 void Texture::init(Target textureTarget, uint32_t textureName) {
     mTextureName = textureName;
     mTextureTarget = textureTarget;
 }
 
-Texture::~Texture() {
-}
-
+Texture::~Texture() {}
 
 void Texture::setMatrix(float const* matrix) {
     mTextureMatrix = mat4(matrix);
diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/Texture.h
index a07e0c3..56b6b31 100644
--- a/services/surfaceflinger/RenderEngine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/Texture.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
 #include <math/mat4.h>
+#include <stdint.h>
 
 #ifndef SF_RENDER_ENGINE_TEXTURE_H
 #define SF_RENDER_ENGINE_TEXTURE_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4055693..11e7ff0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -28,8 +28,6 @@
 #include <stdatomic.h>
 #include <optional>
 
-#include <EGL/egl.h>
-
 #include <cutils/properties.h>
 #include <log/log.h>
 
@@ -39,6 +37,7 @@
 
 #include <dvr/vr_flinger.h>
 
+#include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
@@ -46,6 +45,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
 #include <ui/GraphicBufferAllocator.h>
@@ -62,19 +62,21 @@
 #include <private/android_filesystem_config.h>
 #include <private/gui/SyncFeatures.h>
 
+#include "BufferLayer.h"
 #include "Client.h"
-#include "clz.h"
+#include "ColorLayer.h"
 #include "Colorizer.h"
+#include "ContainerLayer.h"
 #include "DdmConnection.h"
-#include "DisplayDevice.h"
 #include "DispSync.h"
+#include "DisplayDevice.h"
 #include "EventControlThread.h"
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerVector.h"
-#include "LayerDim.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
+#include "clz.h"
 
 #include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/FramebufferSurface.h"
@@ -87,8 +89,12 @@
 #include <cutils/compiler.h>
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/types.h>
 #include <configstore/Utils.h>
 
+#include <layerproto/LayerProtoParser.h>
+
 #define DISPLAY_COUNT       1
 
 /*
@@ -97,12 +103,14 @@
  */
 #define DEBUG_SCREENSHOTS   false
 
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
 namespace android {
 
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::Hdr;
+using ui::RenderIntent;
 
 namespace {
 class ConditionalLock {
@@ -129,29 +137,93 @@
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
 int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
-bool SurfaceFlinger::useContextPriority;
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
 bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
 bool SurfaceFlinger::hasWideColorDisplay;
 
-SurfaceFlinger::SurfaceFlinger()
-    :   BnSurfaceComposer(),
+
+std::string getHwcServiceName() {
+    char value[PROPERTY_VALUE_MAX] = {};
+    property_get("debug.sf.hwc_service_name", value, "default");
+    ALOGI("Using HWComposer service: '%s'", value);
+    return std::string(value);
+}
+
+bool useTrebleTestingOverride() {
+    char value[PROPERTY_VALUE_MAX] = {};
+    property_get("debug.sf.treble_testing_override", value, "false");
+    ALOGI("Treble testing override: '%s'", value);
+    return std::string(value) == "true";
+}
+
+std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
+    switch(displayColorSetting) {
+        case DisplayColorSetting::MANAGED:
+            return std::string("Managed");
+        case DisplayColorSetting::UNMANAGED:
+            return std::string("Unmanaged");
+        case DisplayColorSetting::ENHANCED:
+            return std::string("Enhanced");
+        default:
+            return std::string("Unknown ") +
+                std::to_string(static_cast<int>(displayColorSetting));
+    }
+}
+
+NativeWindowSurface::~NativeWindowSurface() = default;
+
+namespace impl {
+
+class NativeWindowSurface final : public android::NativeWindowSurface {
+public:
+    static std::unique_ptr<android::NativeWindowSurface> create(
+            const sp<IGraphicBufferProducer>& producer) {
+        return std::make_unique<NativeWindowSurface>(producer);
+    }
+
+    explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
+          : surface(new Surface(producer, false)) {}
+
+    ~NativeWindowSurface() override = default;
+
+private:
+    sp<ANativeWindow> getNativeWindow() const override { return surface; }
+
+    void preallocateBuffers() override { surface->allocateBuffers(); }
+
+    sp<Surface> surface;
+};
+
+} // namespace impl
+
+SurfaceFlingerBE::SurfaceFlingerBE()
+      : mHwcServiceName(getHwcServiceName()),
+        mRenderEngine(nullptr),
+        mFrameBuckets(),
+        mTotalTime(0),
+        mLastSwapTime(0),
+        mComposerSequenceId(0) {
+}
+
+SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
+      : BnSurfaceComposer(),
         mTransactionFlags(0),
         mTransactionPending(false),
         mAnimTransactionPending(false),
         mLayersRemoved(false),
         mLayersAdded(false),
         mRepaintEverything(0),
-        mRenderEngine(nullptr),
         mBootTime(systemTime()),
         mBuiltinDisplays(),
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
+        mBootStage(BootStage::BOOTLOADER),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -160,22 +232,18 @@
         mLastSwapBufferTime(0),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
-        mBootFinished(false),
         mForceFullDamage(false),
-        mInterceptor(this),
         mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
-        mHasColorMatrix(false),
         mHasPoweredOff(false),
-        mFrameBuckets(),
-        mTotalTime(0),
-        mLastSwapTime(0),
         mNumLayers(0),
         mVrFlingerRequestsDisplay(false),
         mMainThreadId(std::this_thread::get_id()),
-        mComposerSequenceId(0)
-{
+        mCreateBufferQueue(&BufferQueue::createBufferQueue),
+        mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {}
+
+SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
 
     vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -187,9 +255,6 @@
     hasSyncFramework = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::hasSyncFramework>(true);
 
-    useContextPriority = getBool< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::useContextPriority>(false);
-
     dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
 
@@ -209,7 +274,27 @@
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
-    mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+    V1_1::DisplayOrientation primaryDisplayOrientation =
+        getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
+            V1_1::DisplayOrientation::ORIENTATION_0);
+
+    switch (primaryDisplayOrientation) {
+        case V1_1::DisplayOrientation::ORIENTATION_90:
+            mPrimaryDisplayOrientation = DisplayState::eOrientation90;
+            break;
+        case V1_1::DisplayOrientation::ORIENTATION_180:
+            mPrimaryDisplayOrientation = DisplayState::eOrientation180;
+            break;
+        case V1_1::DisplayOrientation::ORIENTATION_270:
+            mPrimaryDisplayOrientation = DisplayState::eOrientation270;
+            break;
+        default:
+            mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
+            break;
+    }
+    ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
+
+    mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -243,22 +328,53 @@
     mLayerTripleBufferingDisabled = atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
 
+    const size_t defaultListSize = MAX_LAYERS;
+    auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
+    mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+
+    property_get("debug.sf.early_phase_offset_ns", value, "-1");
+    const int earlySfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+    const int earlyGlSfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+    const int earlyAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+    const int earlyGlAppOffsetNs = atoi(value);
+
+    const VSyncModulator::Offsets earlyOffsets =
+            {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+    const VSyncModulator::Offsets earlyGlOffsets =
+            {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+    mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
+            {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
+
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
     // comes online to attempt to read the property. The property is
     // instead read after the boot animation
+
+    if (useTrebleTestingOverride()) {
+        // Without the override SurfaceFlinger cannot connect to HIDL
+        // services that are not listed in the manifests.  Considered
+        // deriving the setting from the set service name, but it
+        // would be brittle if the name that's not 'default' is used
+        // for production purposes later on.
+        setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+    }
 }
 
 void SurfaceFlinger::onFirstRef()
 {
-    mEventQueue.init(this);
+    mEventQueue->init(this);
 }
 
 SurfaceFlinger::~SurfaceFlinger()
 {
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglTerminate(display);
 }
 
 void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -320,7 +436,7 @@
     DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
     info.displayName = displayName;
     mCurrentState.displays.add(token, info);
-    mInterceptor.saveDisplayCreation(info);
+    mInterceptor->saveDisplayCreation(info);
     return token;
 }
 
@@ -338,26 +454,15 @@
         ALOGE("destroyDisplay called for non-virtual display");
         return;
     }
-    mInterceptor.saveDisplayDeletion(info.displayId);
+    mInterceptor->saveDisplayDeletion(info.displayId);
     mCurrentState.displays.removeItemsAt(idx);
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
-void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
-    ALOGV("createBuiltinDisplayLocked(%d)", type);
-    ALOGW_IF(mBuiltinDisplays[type],
-            "Overwriting display token for display type %d", type);
-    mBuiltinDisplays[type] = new BBinder();
-    // All non-virtual displays are currently considered secure.
-    DisplayDeviceState info(type, true);
-    mCurrentState.displays.add(mBuiltinDisplays[type], info);
-    mInterceptor.saveDisplayCreation(info);
-}
-
 sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
     if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
         ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
-        return NULL;
+        return nullptr;
     }
     return mBuiltinDisplays[id];
 }
@@ -393,18 +498,39 @@
 
     sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
         readPersistentProperties();
+        mBootStage = BootStage::FINISHED;
     });
     postMessageAsync(readProperties);
 }
 
+uint32_t SurfaceFlinger::getNewTexture() {
+    {
+        std::lock_guard lock(mTexturePoolMutex);
+        if (!mTexturePool.empty()) {
+            uint32_t name = mTexturePool.back();
+            mTexturePool.pop_back();
+            ATRACE_INT("TexturePoolSize", mTexturePool.size());
+            return name;
+        }
+
+        // The pool was too small, so increase it for the future
+        ++mTexturePoolSize;
+    }
+
+    // The pool was empty, so we need to get a new texture name directly using a
+    // blocking call to the main thread
+    uint32_t name = 0;
+    postMessageSync(new LambdaMessage([&]() { getRenderEngine().genTextures(1, &name); }));
+    return name;
+}
+
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
     class MessageDestroyGLTexture : public MessageBase {
-        RenderEngine& engine;
+        RE::RenderEngine& engine;
         uint32_t texture;
     public:
-        MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
-            : engine(engine), texture(texture) {
-        }
+        MessageDestroyGLTexture(RE::RenderEngine& engine, uint32_t texture)
+              : engine(engine), texture(texture) {}
         virtual bool handler() {
             engine.deleteTextures(1, &texture);
             return true;
@@ -413,7 +539,7 @@
     postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
 }
 
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
         const char* name) :
@@ -424,14 +550,13 @@
             mVsyncEventLabel(String8::format("VSYNC-%s", name)),
             mDispSync(dispSync),
             mCallbackMutex(),
-            mCallback(),
             mVsyncMutex(),
             mPhaseOffset(phaseOffset),
             mEnabled(false) {}
 
-    virtual ~DispSyncSource() {}
+    ~DispSyncSource() override = default;
 
-    virtual void setVSyncEnabled(bool enable) {
+    void setVSyncEnabled(bool enable) override {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
             status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
@@ -453,12 +578,12 @@
         mEnabled = enable;
     }
 
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+    void setCallback(VSyncSource::Callback* callback) override{
         Mutex::Autolock lock(mCallbackMutex);
         mCallback = callback;
     }
 
-    virtual void setPhaseOffset(nsecs_t phaseOffset) {
+    void setPhaseOffset(nsecs_t phaseOffset) override {
         Mutex::Autolock lock(mVsyncMutex);
 
         // Normalize phaseOffset to [0, period)
@@ -476,26 +601,17 @@
             return;
         }
 
-        // Remove the listener with the old offset
-        status_t err = mDispSync->removeEventListener(
-                static_cast<DispSync::Callback*>(this));
+        status_t err = mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this),
+                mPhaseOffset);
         if (err != NO_ERROR) {
-            ALOGE("error unregistering vsync callback: %s (%d)",
-                    strerror(-err), err);
-        }
-
-        // Add a listener with the new offset
-        err = mDispSync->addEventListener(mName, mPhaseOffset,
-                static_cast<DispSync::Callback*>(this));
-        if (err != NO_ERROR) {
-            ALOGE("error registering vsync callback: %s (%d)",
+            ALOGE("error changing vsync offset: %s (%d)",
                     strerror(-err), err);
         }
     }
 
 private:
     virtual void onDispSyncEvent(nsecs_t when) {
-        sp<VSyncSource::Callback> callback;
+        VSyncSource::Callback* callback;
         {
             Mutex::Autolock lock(mCallbackMutex);
             callback = mCallback;
@@ -506,7 +622,7 @@
             }
         }
 
-        if (callback != NULL) {
+        if (callback != nullptr) {
             callback->onVSyncEvent(when);
         }
     }
@@ -522,37 +638,36 @@
     DispSync* mDispSync;
 
     Mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
+    VSyncSource::Callback* mCallback = nullptr;
 
     Mutex mVsyncMutex; // Protects the following
     nsecs_t mPhaseOffset;
     bool mEnabled;
 };
 
-class InjectVSyncSource : public VSyncSource {
+class InjectVSyncSource final : public VSyncSource {
 public:
-    InjectVSyncSource() {}
+    InjectVSyncSource() = default;
+    ~InjectVSyncSource() override = default;
 
-    virtual ~InjectVSyncSource() {}
-
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+    void setCallback(VSyncSource::Callback* callback) override {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         mCallback = callback;
     }
 
-    virtual void onInjectSyncEvent(nsecs_t when) {
+    void onInjectSyncEvent(nsecs_t when) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
-        if (mCallback != nullptr) {
+        if (mCallback) {
             mCallback->onVSyncEvent(when);
         }
     }
 
-    virtual void setVSyncEnabled(bool) {}
-    virtual void setPhaseOffset(nsecs_t) {}
+    void setVSyncEnabled(bool) override {}
+    void setPhaseOffset(nsecs_t) override {}
 
 private:
     std::mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
+    VSyncSource::Callback* mCallback = nullptr;
 };
 
 // Do not call property_set on main thread which will be blocked by init
@@ -565,44 +680,49 @@
 
     Mutex::Autolock _l(mStateLock);
 
-    // initialize EGL for the default display
-    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(mEGLDisplay, NULL, NULL);
-
     // start the EventThread
-    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            vsyncPhaseOffsetNs, true, "app");
-    mEventThread = new EventThread(vsyncSrc, *this, false);
-    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            sfVsyncPhaseOffsetNs, true, "sf");
-    mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
-    mEventQueue.setEventThread(mSFEventThread);
+    mEventThreadSource =
+            std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
+                                             true, "app");
+    mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
+                                                       [this]() { resyncWithRateLimit(); },
+                                                       impl::EventThread::InterceptVSyncsCallback(),
+                                                       "appEventThread");
+    mSfEventThreadSource =
+            std::make_unique<DispSyncSource>(&mPrimaryDispSync,
+                                             SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
 
-    // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
-    struct sched_param param = {0};
-    param.sched_priority = 2;
-    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
-    }
-    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for EventThread");
-    }
+    mSFEventThread =
+            std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
+                                                [this]() { resyncWithRateLimit(); },
+                                                [this](nsecs_t timestamp) {
+                                                    mInterceptor->saveVSyncEvent(timestamp);
+                                                },
+                                                "sfEventThread");
+    mEventQueue->setEventThread(mSFEventThread.get());
+    mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
-    mRenderEngine = RenderEngine::create(mEGLDisplay,
-            HAL_PIXEL_FORMAT_RGBA_8888,
-            hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-
-    // retrieve the EGL context that was selected/created
-    mEGLContext = mRenderEngine->getEGLContext();
-
-    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
-            "couldn't create EGLContext");
+    getBE().mRenderEngine =
+            RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
+                                           hasWideColorDisplay
+                                                   ? RE::RenderEngine::WIDE_COLOR_SUPPORT
+                                                   : 0);
+    LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
-    mHwc.reset(new HWComposer(false));
-    mHwc->registerCallback(this, mComposerSequenceId);
+    getBE().mHwc.reset(
+            new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
+    getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
+    // Process any initial hotplug and resulting display changes.
+    processDisplayHotplugEventsLocked();
+    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
+            "Registered composer callback but didn't create the default primary display");
+
+    // make the default display GLContext current so that we can create textures
+    // when creating Layers (which may happens before we render something)
+    getDefaultDisplayDeviceLocked()->makeCurrent();
 
     if (useVrFlinger) {
         auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
@@ -619,15 +739,16 @@
             });
             postMessageAsync(message);
         };
-        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
-                                            vrFlingerRequestDisplayCallback);
+        mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
+                getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
+                vrFlingerRequestDisplayCallback);
         if (!mVrFlinger) {
             ALOGE("Failed to start vrflinger");
         }
     }
 
-    mEventControlThread = new EventControlThread(this);
-    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+    mEventControlThread = std::make_unique<impl::EventControlThread>(
+            [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
 
     // initialize our drawing state
     mDrawingState = mCurrentState;
@@ -635,7 +756,7 @@
     // set initial conditions (e.g. unblank default device)
     initializeDisplays();
 
-    mRenderEngine->primeCache();
+    getBE().mRenderEngine->primeCache();
 
     // Inform native graphics APIs whether the present timestamp is supported:
     if (getHwComposer().hasCapability(
@@ -649,21 +770,39 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
+    // This is a hack. Per definition of getDataspaceSaturationMatrix, the returned matrix
+    // is used to saturate legacy sRGB content. However, to make sure the same color under
+    // Display P3 will be saturated to the same color, we intentionally break the API spec
+    // and apply this saturation matrix on Display P3 content. Unless the risk of applying
+    // such saturation matrix on Display P3 is understood fully, the API should always return
+    // identify matrix.
+    mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+            Dataspace::SRGB_LINEAR);
+
+    // we will apply this on Display P3.
+    if (mEnhancedSaturationMatrix != mat4()) {
+        ColorSpace srgb(ColorSpace::sRGB());
+        ColorSpace displayP3(ColorSpace::DisplayP3());
+        mat4 srgbToP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
+        mat4 p3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+        mEnhancedSaturationMatrix = srgbToP3 * mEnhancedSaturationMatrix * p3ToSrgb;
+    }
+
     ALOGV("Done initializing");
 }
 
 void SurfaceFlinger::readPersistentProperties() {
+    Mutex::Autolock _l(mStateLock);
+
     char value[PROPERTY_VALUE_MAX];
 
     property_get("persist.sys.sf.color_saturation", value, "1.0");
-    mSaturation = atof(value);
-    ALOGV("Saturation is set to %.2f", mSaturation);
+    mGlobalSaturationFactor = atof(value);
+    updateColorMatrixLocked();
+    ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
 
     property_get("persist.sys.sf.native_mode", value, "0");
-    mForceNativeColorMode = atoi(value) == 1;
-    if (mForceNativeColorMode) {
-        ALOGV("Forcing native color mode");
-    }
+    mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
 }
 
 void SurfaceFlinger::startBootAnim() {
@@ -677,11 +816,11 @@
 }
 
 size_t SurfaceFlinger::getMaxTextureSize() const {
-    return mRenderEngine->getMaxTextureSize();
+    return getBE().mRenderEngine->getMaxTextureSize();
 }
 
 size_t SurfaceFlinger::getMaxViewportDims() const {
-    return mRenderEngine->getMaxViewportDims();
+    return getBE().mRenderEngine->getMaxViewportDims();
 }
 
 // ----------------------------------------------------------------------------
@@ -695,7 +834,7 @@
 bool SurfaceFlinger::authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const {
     sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
-    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
+    return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
@@ -721,7 +860,7 @@
 
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
-    if ((configs == NULL) || (display.get() == NULL)) {
+    if (configs == nullptr || display.get() == nullptr) {
         return BAD_VALUE;
     }
 
@@ -745,7 +884,7 @@
         static int getDensityFromProperty(char const* propName) {
             char property[PROPERTY_VALUE_MAX];
             int density = 0;
-            if (property_get(propName, property, NULL) > 0) {
+            if (property_get(propName, property, nullptr) > 0) {
                 density = atoi(property);
             }
             return density;
@@ -785,7 +924,7 @@
 
             // TODO: this needs to go away (currently needed only by webkit)
             sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
-            info.orientation = hw->getOrientation();
+            info.orientation = hw ? hw->getOrientation() : 0;
         } else {
             // TODO: where should this value come from?
             static const int TV_DENSITY = 213;
@@ -818,6 +957,11 @@
         // All non-virtual displays are currently considered secure.
         info.secure = true;
 
+        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+            mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+            std::swap(info.w, info.h);
+        }
+
         configs->push_back(info);
     }
 
@@ -826,7 +970,7 @@
 
 status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
         DisplayStatInfo* stats) {
-    if (stats == NULL) {
+    if (stats == nullptr) {
         return BAD_VALUE;
     }
 
@@ -837,14 +981,29 @@
     return NO_ERROR;
 }
 
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
-    if (display == NULL) {
-        ALOGE("%s : display is NULL", __func__);
+status_t SurfaceFlinger::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+    if (outViewport == nullptr || display.get() == nullptr) {
         return BAD_VALUE;
     }
 
     sp<const DisplayDevice> device(getDisplayDevice(display));
-    if (device != NULL) {
+    if (device == nullptr) {
+        return BAD_VALUE;
+    }
+
+    *outViewport = device->getViewport();
+
+    return NO_ERROR;
+}
+
+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
+    if (display == nullptr) {
+        ALOGE("%s : display is nullptr", __func__);
+        return BAD_VALUE;
+    }
+
+    sp<const DisplayDevice> device(getDisplayDevice(display));
+    if (device != nullptr) {
         return device->getActiveConfig();
     }
 
@@ -889,7 +1048,7 @@
                 return true;
             }
             sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == NULL) {
+            if (hw == nullptr) {
                 ALOGE("Attempt to set active config = %d for null display %p",
                         mMode, mDisplay.get());
             } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -906,7 +1065,7 @@
     return NO_ERROR;
 }
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
+        Vector<ColorMode>* outColorModes) {
     if ((outColorModes == nullptr) || (display.get() == nullptr)) {
         return BAD_VALUE;
     }
@@ -927,7 +1086,7 @@
         return type;
     }
 
-    std::vector<android_color_mode_t> modes;
+    std::vector<ColorMode> modes;
     {
         ConditionalLock _l(mStateLock,
                 std::this_thread::get_id() != mMainThreadId);
@@ -939,20 +1098,24 @@
     return NO_ERROR;
 }
 
-android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
     sp<const DisplayDevice> device(getDisplayDevice(display));
     if (device != nullptr) {
         return device->getActiveColorMode();
     }
-    return static_cast<android_color_mode_t>(BAD_VALUE);
+    return static_cast<ColorMode>(BAD_VALUE);
 }
 
 void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
-        android_color_mode_t mode) {
+                                                ColorMode mode, Dataspace dataSpace,
+                                                RenderIntent renderIntent) {
     int32_t type = hw->getDisplayType();
-    android_color_mode_t currentMode = hw->getActiveColorMode();
+    ColorMode currentMode = hw->getActiveColorMode();
+    Dataspace currentDataSpace = hw->getCompositionDataSpace();
+    RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
 
-    if (mode == currentMode) {
+    if (mode == currentMode && dataSpace == currentDataSpace &&
+        renderIntent == currentRenderIntent) {
         return;
     }
 
@@ -961,29 +1124,33 @@
         return;
     }
 
-    ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
-          hw->getDisplayType());
-
     hw->setActiveColorMode(mode);
-    getHwComposer().setActiveColorMode(type, mode);
+    hw->setCompositionDataSpace(dataSpace);
+    hw->setActiveRenderIntent(renderIntent);
+    getHwComposer().setActiveColorMode(type, mode, renderIntent);
+
+    ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+          decodeColorMode(mode).c_str(), mode,
+          decodeRenderIntent(renderIntent).c_str(), renderIntent,
+          hw->getDisplayType());
 }
 
 
 status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
+        ColorMode colorMode) {
     class MessageSetActiveColorMode: public MessageBase {
         SurfaceFlinger& mFlinger;
         sp<IBinder> mDisplay;
-        android_color_mode_t mMode;
+        ColorMode mMode;
     public:
         MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
-                               android_color_mode_t mode) :
+                               ColorMode mode) :
             mFlinger(flinger), mDisplay(disp) { mMode = mode; }
         virtual bool handler() {
-            Vector<android_color_mode_t> modes;
+            Vector<ColorMode> modes;
             mFlinger.getDisplayColorModes(mDisplay, &modes);
             bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
-            if (mMode < 0 || !exists) {
+            if (mMode < ColorMode::NATIVE || !exists) {
                 ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
                       decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
                 return true;
@@ -996,7 +1163,8 @@
                 ALOGW("Attempt to set active color mode %s %d for virtual display",
                       decodeColorMode(mMode).c_str(), mMode);
             } else {
-                mFlinger.setActiveColorModeInternal(hw, mMode);
+                mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN,
+                                                    RenderIntent::COLORIMETRIC);
             }
             return true;
         }
@@ -1028,53 +1196,45 @@
         return BAD_VALUE;
     }
 
-    std::unique_ptr<HdrCapabilities> capabilities =
-            mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
-    if (capabilities) {
-        std::swap(*outCapabilities, *capabilities);
-    } else {
-        return BAD_VALUE;
-    }
+    // At this point the DisplayDeivce should already be set up,
+    // meaning the luminance information is already queried from
+    // hardware composer and stored properly.
+    const HdrCapabilities& capabilities = displayDevice->getHdrCapabilities();
+    *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
+                                       capabilities.getDesiredMaxLuminance(),
+                                       capabilities.getDesiredMaxAverageLuminance(),
+                                       capabilities.getDesiredMinLuminance());
 
     return NO_ERROR;
 }
 
-void SurfaceFlinger::enableVSyncInjectionsInternal(bool enable) {
-    Mutex::Autolock _l(mStateLock);
-
-    if (mInjectVSyncs == enable) {
-        return;
-    }
-
-    if (enable) {
-        ALOGV("VSync Injections enabled");
-        if (mVSyncInjector.get() == nullptr) {
-            mVSyncInjector = new InjectVSyncSource();
-            mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
-        }
-        mEventQueue.setEventThread(mInjectorEventThread);
-    } else {
-        ALOGV("VSync Injections disabled");
-        mEventQueue.setEventThread(mSFEventThread);
-    }
-
-    mInjectVSyncs = enable;
-}
-
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    class MessageEnableVSyncInjections : public MessageBase {
-        SurfaceFlinger* mFlinger;
-        bool mEnable;
-    public:
-        MessageEnableVSyncInjections(SurfaceFlinger* flinger, bool enable)
-            : mFlinger(flinger), mEnable(enable) { }
-        virtual bool handler() {
-            mFlinger->enableVSyncInjectionsInternal(mEnable);
-            return true;
+    sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+        Mutex::Autolock _l(mStateLock);
+
+        if (mInjectVSyncs == enable) {
+            return;
         }
-    };
-    sp<MessageBase> msg = new MessageEnableVSyncInjections(this, enable);
-    postMessageSync(msg);
+
+        if (enable) {
+            ALOGV("VSync Injections enabled");
+            if (mVSyncInjector.get() == nullptr) {
+                mVSyncInjector = std::make_unique<InjectVSyncSource>();
+                mInjectorEventThread = std::make_unique<
+                        impl::EventThread>(mVSyncInjector.get(),
+                                           [this]() { resyncWithRateLimit(); },
+                                           impl::EventThread::InterceptVSyncsCallback(),
+                                           "injEventThread");
+            }
+            mEventQueue->setEventThread(mInjectorEventThread.get());
+        } else {
+            ALOGV("VSync Injections disabled");
+            mEventQueue->setEventThread(mSFEventThread.get());
+        }
+
+        mInjectVSyncs = enable;
+    });
+    postMessageSync(enableVSyncInjections);
     return NO_ERROR;
 }
 
@@ -1092,6 +1252,34 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
+        NO_THREAD_SAFETY_ANALYSIS {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL) &&
+            !PermissionCache::checkPermission(sDump, pid, uid)) {
+        ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+        return PERMISSION_DENIED;
+    }
+
+    // Try to acquire a lock for 1s, fail gracefully
+    const status_t err = mStateLock.timedLock(s2ns(1));
+    const bool locked = (err == NO_ERROR);
+    if (!locked) {
+        ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+        return TIMED_OUT;
+    }
+
+    outLayers->clear();
+    mCurrentState.traverseInZOrder([&](Layer* layer) {
+        outLayers->push_back(layer->getLayerDebugInfo());
+    });
+
+    mStateLock.unlock();
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1106,30 +1294,30 @@
 // ----------------------------------------------------------------------------
 
 void SurfaceFlinger::waitForEvent() {
-    mEventQueue.waitMessage();
+    mEventQueue->waitMessage();
 }
 
 void SurfaceFlinger::signalTransaction() {
-    mEventQueue.invalidate();
+    mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalLayerUpdate() {
-    mEventQueue.invalidate();
+    mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalRefresh() {
     mRefreshPending = true;
-    mEventQueue.refresh();
+    mEventQueue->refresh();
 }
 
 status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t /* flags */) {
-    return mEventQueue.postMessage(msg, reltime);
+    return mEventQueue->postMessage(msg, reltime);
 }
 
 status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t /* flags */) {
-    status_t res = mEventQueue.postMessage(msg, reltime);
+    status_t res = mEventQueue->postMessage(msg, reltime);
     if (res == NO_ERROR) {
         msg->wait();
     }
@@ -1163,7 +1351,7 @@
         return;
     }
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
     mPrimaryDispSync.reset();
@@ -1206,12 +1394,12 @@
         hwc2_display_t displayId, int64_t timestamp) {
     Mutex::Autolock lock(mStateLock);
     // Ignore any vsyncs from a previous hardware composer.
-    if (sequenceId != mComposerSequenceId) {
+    if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
 
     int32_t type;
-    if (!mHwc->onVsync(displayId, timestamp, &type)) {
+    if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
         return;
     }
 
@@ -1232,108 +1420,43 @@
 }
 
 void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    *compositorTiming = mCompositorTiming;
+    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+    *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::createDefaultDisplayDevice() {
-    const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY;
-    wp<IBinder> token = mBuiltinDisplays[type];
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+                                       HWC2::Connection connection) {
+    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+          connection == HWC2::Connection::Connected ? "connected" : "disconnected");
 
-    // All non-virtual displays are currently considered secure.
-    const bool isSecure = true;
-
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer);
-
-    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, type, consumer);
-
-    bool hasWideColorModes = false;
-    std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
-    for (android_color_mode_t colorMode : modes) {
-        switch (colorMode) {
-            case HAL_COLOR_MODE_DISPLAY_P3:
-            case HAL_COLOR_MODE_ADOBE_RGB:
-            case HAL_COLOR_MODE_DCI_P3:
-                hasWideColorModes = true;
-                break;
-            default:
-                break;
-        }
+    // Ignore events that do not have the right sequenceId.
+    if (sequenceId != getBE().mComposerSequenceId) {
+        return;
     }
-    bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
-    sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
-                                             token, fbs, producer, mRenderEngine->getEGLConfig(),
-                                             useWideColorMode);
-    mDisplays.add(token, hw);
-    android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
-    if (useWideColorMode) {
-        defaultColorMode = HAL_COLOR_MODE_SRGB;
-    }
-    setActiveColorModeInternal(hw, defaultColorMode);
-    hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
-
-    // Add the primary display token to mDrawingState so we don't try to
-    // recreate the DisplayDevice for the primary display.
-    mDrawingState.displays.add(token, DisplayDeviceState(type, true));
-
-    // make the GLContext current so that we can create textures when creating
-    // Layers (which may happens before we render something)
-    hw->makeCurrent(mEGLDisplay, mEGLContext);
-}
-
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
-        hwc2_display_t display, HWC2::Connection connection,
-        bool primaryDisplay) {
-    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
-          sequenceId, display,
-          connection == HWC2::Connection::Connected ?
-                  "connected" : "disconnected",
-          primaryDisplay ? "primary" : "external");
 
     // Only lock if we're not on the main thread. This function is normally
     // called on a hwbinder thread, but for the primary display it's called on
     // the main thread with the state lock already held, so don't attempt to
     // acquire it here.
-    ConditionalLock lock(mStateLock,
-            std::this_thread::get_id() != mMainThreadId);
+    ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
 
-    if (primaryDisplay) {
-        mHwc->onHotplug(display, connection);
-        if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
-            createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
-        }
-        createDefaultDisplayDevice();
-    } else {
-        if (sequenceId != mComposerSequenceId) {
-            return;
-        }
-        if (mHwc->isUsingVrComposer()) {
-            ALOGE("External displays are not supported by the vr hardware composer.");
-            return;
-        }
-        mHwc->onHotplug(display, connection);
-        auto type = DisplayDevice::DISPLAY_EXTERNAL;
-        if (connection == HWC2::Connection::Connected) {
-            createBuiltinDisplayLocked(type);
-        } else {
-            mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
-            mBuiltinDisplays[type].clear();
-        }
-        setTransactionFlags(eDisplayTransactionNeeded);
+    mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
 
-        // Defer EventThread notification until SF has updated mDisplays.
+    if (std::this_thread::get_id() == mMainThreadId) {
+        // Process all pending hot plug events immediately if we are on the main thread.
+        processDisplayHotplugEventsLocked();
     }
+
+    setTransactionFlags(eDisplayTransactionNeeded);
 }
 
 void SurfaceFlinger::onRefreshReceived(int sequenceId,
                                        hwc2_display_t /*display*/) {
     Mutex::Autolock lock(mStateLock);
-    if (sequenceId != mComposerSequenceId) {
+    if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
-    repaintEverythingLocked();
+    repaintEverything();
 }
 
 void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
@@ -1351,7 +1474,7 @@
     // mCurrentState and mDrawingState and re-apply all changes when we make the
     // transition.
     mDrawingState.displays.clear();
-    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    getRenderEngine().resetCurrentSurface();
     mDisplays.clear();
 }
 
@@ -1359,11 +1482,11 @@
     if (!mVrFlinger)
         return;
     bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
-    if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
+    if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) {
         return;
     }
 
-    if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) {
+    if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) {
         ALOGE("Vr flinger is only supported for remote hardware composer"
               " service connections. Ignoring request to transition to vr"
               " flinger.");
@@ -1381,12 +1504,13 @@
     }
 
     resetDisplayState();
-    mHwc.reset();  // Delete the current instance before creating the new one
-    mHwc.reset(new HWComposer(vrFlingerRequestsDisplay));
-    mHwc->registerCallback(this, ++mComposerSequenceId);
+    getBE().mHwc.reset(); // Delete the current instance before creating the new one
+    getBE().mHwc.reset(new HWComposer(std::make_unique<Hwc2::impl::Composer>(
+            vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)));
+    getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
 
-    LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(),
-            "Switched to non-remote hardware composer");
+    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
+                        "Switched to non-remote hardware composer");
 
     if (vrFlingerRequestsDisplay) {
         mVrFlinger->GrantDisplayOwnership();
@@ -1403,7 +1527,7 @@
     setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -1424,9 +1548,12 @@
                     (mPreviousPresentFence->getSignalTime() ==
                             Fence::SIGNAL_TIME_PENDING);
             ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
-            if (mPropagateBackpressure && frameMissed) {
-                signalLayerUpdate();
-                break;
+            if (frameMissed) {
+                mTimeStats.incrementMissedFrames();
+                if (mPropagateBackpressure) {
+                    signalLayerUpdate();
+                    break;
+                }
             }
 
             // Now that we're going to make it to the handleMessageTransaction()
@@ -1437,7 +1564,7 @@
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
             refreshNeeded |= mRepaintEverything;
-            if (refreshNeeded) {
+            if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
                 // Signal a refresh if a transaction modified the window state,
                 // a new buffer was latched, or if HWC has requested a full
                 // repaint
@@ -1477,17 +1604,20 @@
     rebuildLayerStacks();
     setUpHWComposer();
     doDebugFlashRegions();
+    doTracing("handleRefresh");
+    logLayerStats();
     doComposition();
     postComposition(refreshStartTime);
 
-    mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
 
     mHadClientComposition = false;
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
         const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
         mHadClientComposition = mHadClientComposition ||
-                mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+                getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
     }
+    mVsyncModulator.onRefreshed(mHadClientComposition);
 
     mLayersWithQueuedFrames.clear();
 }
@@ -1506,11 +1636,11 @@
             const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
             if (!dirtyRegion.isEmpty()) {
                 // redraw the whole screen
-                doComposeSurfaces(hw, Region(hw->bounds()));
+                doComposeSurfaces(hw);
 
                 // and draw the dirty region
                 const int32_t height = hw->getHeight();
-                RenderEngine& engine(getRenderEngine());
+                auto& engine(getRenderEngine());
                 engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
 
                 hw->swapBuffers(getHwComposer());
@@ -1530,9 +1660,38 @@
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*mHwc);
-        ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
-                " %d (%s)", displayId, result, strerror(-result));
+        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
+        ALOGE_IF(result != NO_ERROR,
+                 "prepareFrame for display %zd failed:"
+                 " %d (%s)",
+                 displayId, result, strerror(-result));
+    }
+}
+
+void SurfaceFlinger::doTracing(const char* where) {
+    ATRACE_CALL();
+    ATRACE_NAME(where);
+    if (CC_UNLIKELY(mTracing.isEnabled())) {
+        mTracing.traceLayers(where, dumpProtoInfo(LayerVector::StateSet::Drawing));
+    }
+}
+
+void SurfaceFlinger::logLayerStats() {
+    ATRACE_CALL();
+    if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+        int32_t hwcId = -1;
+        for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
+            const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
+            if (displayDevice->isPrimary()) {
+                hwcId = displayDevice->getHwcDisplayId();
+                break;
+            }
+        }
+        if (hwcId < 0) {
+            ALOGE("LayerStats: Hmmm, no primary display?");
+            return;
+        }
+        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
     }
 }
 
@@ -1558,10 +1717,10 @@
         std::shared_ptr<FenceTime>& presentFenceTime) {
     // Update queue of past composite+present times and determine the
     // most recently known composite to present latency.
-    mCompositePresentTimes.push({compositeTime, presentFenceTime});
+    getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
     nsecs_t compositeToPresentLatency = -1;
-    while (!mCompositePresentTimes.empty()) {
-        CompositePresentTime& cpt = mCompositePresentTimes.front();
+    while (!getBE().mCompositePresentTimes.empty()) {
+        SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
         // Cached values should have been updated before calling this method,
         // which helps avoid duplicate syscalls.
         nsecs_t displayTime = cpt.display->getCachedSignalTime();
@@ -1569,12 +1728,12 @@
             break;
         }
         compositeToPresentLatency = displayTime - cpt.composite;
-        mCompositePresentTimes.pop();
+        getBE().mCompositePresentTimes.pop();
     }
 
     // Don't let mCompositePresentTimes grow unbounded, just in case.
-    while (mCompositePresentTimes.size() > 16) {
-        mCompositePresentTimes.pop();
+    while (getBE().mCompositePresentTimes.size() > 16) {
+        getBE().mCompositePresentTimes.pop();
     }
 
     setCompositorTimingSnapped(
@@ -1606,10 +1765,10 @@
     nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
             idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
 
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    mCompositorTiming.deadline = vsyncPhase - idealLatency;
-    mCompositorTiming.interval = vsyncInterval;
-    mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+    getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
+    getBE().mCompositorTiming.interval = vsyncInterval;
+    getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
@@ -1626,20 +1785,20 @@
     // |mStateLock| not needed as we are on the main thread
     const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
-    mGlCompositionDoneTimeline.updateSignalTimes();
+    getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+    if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
-        mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
+        getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
 
-    mDisplayTimeline.updateSignalTimes();
-    sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    getBE().mDisplayTimeline.updateSignalTimes();
+    sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
     auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
-    mDisplayTimeline.push(presentFenceTime);
+    getBE().mDisplayTimeline.push(presentFenceTime);
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1651,8 +1810,8 @@
         vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
     {
-        std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-        compositorTiming = mCompositorTiming;
+        std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+        compositorTiming = getBE().mCompositorTiming;
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
@@ -1673,7 +1832,7 @@
     }
 
     if (!hasSyncFramework) {
-        if (hw->isDisplayOn()) {
+        if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
             enableHardwareVsync();
         }
     }
@@ -1684,17 +1843,23 @@
         if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
                     std::move(presentFenceTime));
-        } else {
+        } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
             nsecs_t presentTime =
-                    mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+                    getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
     }
 
-    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+    mTimeStats.incrementTotalFrames();
+    if (mHadClientComposition) {
+        mTimeStats.incrementClientCompositionFrames();
+    }
+
+    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
+            hw->getPowerMode() == HWC_POWER_MODE_OFF) {
         return;
     }
 
@@ -1702,16 +1867,27 @@
     if (mHasPoweredOff) {
         mHasPoweredOff = false;
     } else {
-        nsecs_t elapsedTime = currentTime - mLastSwapTime;
+        nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
         size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
-        if (numPeriods < NUM_BUCKETS - 1) {
-            mFrameBuckets[numPeriods] += elapsedTime;
+        if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
+            getBE().mFrameBuckets[numPeriods] += elapsedTime;
         } else {
-            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+            getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
         }
-        mTotalTime += elapsedTime;
+        getBE().mTotalTime += elapsedTime;
     }
-    mLastSwapTime = currentTime;
+    getBE().mLastSwapTime = currentTime;
+
+    {
+        std::lock_guard lock(mTexturePoolMutex);
+        const size_t refillCount = mTexturePoolSize - mTexturePool.size();
+        if (refillCount > 0) {
+            const size_t offset = mTexturePool.size();
+            mTexturePool.resize(mTexturePoolSize);
+            getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
+            ATRACE_INT("TexturePoolSize", mTexturePool.size());
+        }
+    }
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -1720,7 +1896,7 @@
 
     // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
-        ATRACE_CALL();
+        ATRACE_NAME("rebuildLayerStacks VR Dirty");
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
 
@@ -1728,6 +1904,7 @@
             Region opaqueRegion;
             Region dirtyRegion;
             Vector<sp<Layer>> layersSortedByZ;
+            Vector<sp<Layer>> layersNeedingFences;
             const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
             const Transform& tr(displayDevice->getTransform());
             const Rect bounds(displayDevice->getBounds());
@@ -1735,6 +1912,7 @@
                 computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
+                    bool hwcLayerDestroyed = false;
                     if (layer->belongsToDisplay(displayDevice->getLayerStack(),
                                 displayDevice->isPrimary())) {
                         Region drawRegion(tr.transform(
@@ -1745,18 +1923,32 @@
                         } else {
                             // Clear out the HWC layer if this layer was
                             // previously visible, but no longer is
-                            layer->destroyHwcLayer(
+                            hwcLayerDestroyed = layer->destroyHwcLayer(
                                     displayDevice->getHwcDisplayId());
                         }
                     } else {
                         // WM changes displayDevice->layerStack upon sleep/awake.
                         // Here we make sure we delete the HWC layers even if
                         // WM changed their layer stack.
-                        layer->destroyHwcLayer(displayDevice->getHwcDisplayId());
+                        hwcLayerDestroyed = layer->destroyHwcLayer(
+                                displayDevice->getHwcDisplayId());
+                    }
+
+                    // If a layer is not going to get a release fence because
+                    // it is invisible, but it is also going to release its
+                    // old buffer, add it to the list of layers needing
+                    // fences.
+                    if (hwcLayerDestroyed) {
+                        auto found = std::find(mLayersWithQueuedFrames.cbegin(),
+                                mLayersWithQueuedFrames.cend(), layer);
+                        if (found != mLayersWithQueuedFrames.cend()) {
+                            layersNeedingFences.add(layer);
+                        }
                     }
                 });
             }
             displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+            displayDevice->setLayersNeedingFences(layersNeedingFences);
             displayDevice->undefinedRegion.set(bounds);
             displayDevice->undefinedRegion.subtractSelf(
                     tr.transform(opaqueRegion));
@@ -1765,65 +1957,82 @@
     }
 }
 
-mat4 SurfaceFlinger::computeSaturationMatrix() const {
-    if (mSaturation == 1.0f) {
-        return mat4();
+// Returns a data space that fits all visible layers.  The returned data space
+// can only be one of
+//  - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
+//  - Dataspace::DISPLAY_P3
+// The returned HDR data space is one of
+//  - Dataspace::UNKNOWN
+//  - Dataspace::BT2020_HLG
+//  - Dataspace::BT2020_PQ
+Dataspace SurfaceFlinger::getBestDataspace(
+    const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const {
+    Dataspace bestDataSpace = Dataspace::SRGB;
+    *outHdrDataSpace = Dataspace::UNKNOWN;
+
+    for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        switch (layer->getDataSpace()) {
+            case Dataspace::V0_SCRGB:
+            case Dataspace::V0_SCRGB_LINEAR:
+            case Dataspace::DISPLAY_P3:
+                bestDataSpace = Dataspace::DISPLAY_P3;
+                break;
+            case Dataspace::BT2020_PQ:
+            case Dataspace::BT2020_ITU_PQ:
+                *outHdrDataSpace = Dataspace::BT2020_PQ;
+                break;
+            case Dataspace::BT2020_HLG:
+            case Dataspace::BT2020_ITU_HLG:
+                // When there's mixed PQ content and HLG content, we set the HDR
+                // data space to be BT2020_PQ and convert HLG to PQ.
+                if (*outHdrDataSpace == Dataspace::UNKNOWN) {
+                    *outHdrDataSpace = Dataspace::BT2020_HLG;
+                }
+                break;
+            default:
+                break;
+        }
     }
 
-    // Rec.709 luma coefficients
-    float3 luminance{0.213f, 0.715f, 0.072f};
-    luminance *= 1.0f - mSaturation;
-    return mat4(
-        vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
-        vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
-        vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
-        vec4{0.0f, 0.0f, 0.0f, 1.0f}
-    );
+    return bestDataSpace;
 }
 
-// pickColorMode translates a given dataspace into the best available color mode.
-// Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
-    if (mForceNativeColorMode) {
-        return HAL_COLOR_MODE_NATIVE;
+// Pick the ColorMode / Dataspace for the display device.
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
+                                   ColorMode* outMode, Dataspace* outDataSpace,
+                                   RenderIntent* outRenderIntent) const {
+    if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
+        *outMode = ColorMode::NATIVE;
+        *outDataSpace = Dataspace::UNKNOWN;
+        *outRenderIntent = RenderIntent::COLORIMETRIC;
+        return;
     }
 
-    switch (dataSpace) {
-        // treat Unknown as regular SRGB buffer, since that's what the rest of the
-        // system expects.
-        case HAL_DATASPACE_UNKNOWN:
-        case HAL_DATASPACE_SRGB:
-        case HAL_DATASPACE_V0_SRGB:
-            return HAL_COLOR_MODE_SRGB;
-            break;
+    Dataspace hdrDataSpace;
+    Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace);
 
-        case HAL_DATASPACE_DISPLAY_P3:
-            return HAL_COLOR_MODE_DISPLAY_P3;
-            break;
+    // respect hdrDataSpace only when there is no legacy HDR support
+    const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
+        !displayDevice->hasLegacyHdrSupport(hdrDataSpace);
+    if (isHdr) {
+        bestDataSpace = hdrDataSpace;
+    }
 
-        default:
-            // TODO (courtneygo): Do we want to assert an error here?
-            ALOGE("No color mode mapping for %s (%#x)", dataspaceDetails(dataSpace).c_str(),
-                  dataSpace);
-            return HAL_COLOR_MODE_SRGB;
+    RenderIntent intent;
+    switch (mDisplayColorSetting) {
+        case DisplayColorSetting::MANAGED:
+        case DisplayColorSetting::UNMANAGED:
+            intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
+            break;
+        case DisplayColorSetting::ENHANCED:
+            intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;
+            break;
+        default: // vendor display color setting
+            intent = static_cast<RenderIntent>(mDisplayColorSetting);
             break;
     }
-}
 
-android_dataspace SurfaceFlinger::bestTargetDataSpace(
-        android_dataspace a, android_dataspace b) const {
-    // Only support sRGB and Display-P3 right now.
-    if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
-        return HAL_DATASPACE_DISPLAY_P3;
-    }
-    if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
-        return HAL_DATASPACE_DISPLAY_P3;
-    }
-    if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
-        return HAL_DATASPACE_DISPLAY_P3;
-    }
-
-    return HAL_DATASPACE_V0_SRGB;
+    displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
 }
 
 void SurfaceFlinger::setUpHWComposer() {
@@ -1831,7 +2040,7 @@
     ALOGV("setUpHWComposer");
 
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
+        bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
         bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
         bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
 
@@ -1871,7 +2080,7 @@
                 for (size_t i = 0; i < currentLayers.size(); i++) {
                     const auto& layer = currentLayers[i];
                     if (!layer->hasHwcLayer(hwcId)) {
-                        if (!layer->createHwcLayer(mHwc.get(), hwcId)) {
+                        if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
                             layer->forceClientComposition(hwcId);
                             continue;
                         }
@@ -1886,9 +2095,6 @@
         }
     }
 
-
-    mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
-
     // Set the per-frame data
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
         auto& displayDevice = mDisplays[displayId];
@@ -1897,32 +2103,44 @@
         if (hwcId < 0) {
             continue;
         }
-        if (colorMatrix != mPreviousColorMatrix) {
-            status_t result = mHwc->setColorTransform(hwcId, colorMatrix);
+        if (mDrawingState.colorMatrixChanged) {
+            displayDevice->setColorTransform(mDrawingState.colorMatrix);
+            status_t result = getBE().mHwc->setColorTransform(hwcId, mDrawingState.colorMatrix);
             ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
                     "display %zd: %d", displayId, result);
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+            if (layer->isHdrY410()) {
+                layer->forceClientComposition(hwcId);
+            } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
+                        layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
+                    !displayDevice->hasHDR10Support()) {
+                layer->forceClientComposition(hwcId);
+            } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
+                        layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
+                    !displayDevice->hasHLGSupport()) {
+                layer->forceClientComposition(hwcId);
+            }
+
+            if (layer->getForceClientComposition(hwcId)) {
+                ALOGV("[%s] Requesting Client composition", layer->getName().string());
+                layer->setCompositionType(hwcId, HWC2::Composition::Client);
+                continue;
+            }
+
             layer->setPerFrameData(displayDevice);
         }
 
         if (hasWideColorDisplay) {
-            android_color_mode newColorMode;
-            android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
-
-            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-                newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace);
-                ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
-                      layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
-                      layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
-            }
-            newColorMode = pickColorMode(newDataSpace);
-
-            setActiveColorModeInternal(displayDevice, newColorMode);
+            ColorMode colorMode;
+            Dataspace dataSpace;
+            RenderIntent renderIntent;
+            pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
+            setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent);
         }
     }
 
-    mPreviousColorMatrix = colorMatrix;
+    mDrawingState.colorMatrixChanged = false;
 
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
         auto& displayDevice = mDisplays[displayId];
@@ -1930,7 +2148,7 @@
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*mHwc);
+        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
         ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
                 " %d (%s)", displayId, result, strerror(-result));
     }
@@ -1951,8 +2169,7 @@
             doDisplayComposition(hw, dirtyRegion);
 
             hw->dirtyRegion.clear();
-            hw->flip(hw->swapRegion);
-            hw->swapRegion.clear();
+            hw->flip();
         }
     }
     postFramebuffer();
@@ -1973,22 +2190,46 @@
         }
         const auto hwcId = displayDevice->getHwcDisplayId();
         if (hwcId >= 0) {
-            mHwc->presentAndGetReleaseFences(hwcId);
+            getBE().mHwc->presentAndGetReleaseFences(hwcId);
         }
         displayDevice->onSwapBuffersCompleted();
-        displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+        displayDevice->makeCurrent();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
-            if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
-                releaseFence = displayDevice->getClientTargetAcquireFence();
-            } else {
-                auto hwcLayer = layer->getHwcLayer(hwcId);
-                releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+
+            // The layer buffer from the previous frame (if any) is released
+            // by HWC only when the release fence from this frame (if any) is
+            // signaled.  Always get the release fence from HWC first.
+            auto hwcLayer = layer->getHwcLayer(hwcId);
+            if (hwcId >= 0) {
+                releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
             }
+
+            // If the layer was client composited in the previous frame, we
+            // need to merge with the previous client target acquire fence.
+            // Since we do not track that, always merge with the current
+            // client target acquire fence when it is available, even though
+            // this is suboptimal.
+            if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
+                releaseFence = Fence::merge("LayerRelease", releaseFence,
+                        displayDevice->getClientTargetAcquireFence());
+            }
+
             layer->onLayerDisplayed(releaseFence);
         }
+
+        // We've got a list of layers needing fences, that are disjoint with
+        // displayDevice->getVisibleLayersSortedByZ.  The best we can do is to
+        // supply them with the present fence.
+        if (!displayDevice->getLayersNeedingFences().isEmpty()) {
+            sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
+            for (auto& layer : displayDevice->getLayersNeedingFences()) {
+                layer->onLayerDisplayed(presentFence);
+            }
+        }
+
         if (hwcId >= 0) {
-            mHwc->clearReleaseFences(hwcId);
+            getBE().mHwc->clearReleaseFences(hwcId);
         }
     }
 
@@ -1996,9 +2237,11 @@
     mDebugInSwapBuffers = 0;
 
     // |mStateLock| not needed as we are on the main thread
-    uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
-    if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
-        logFrameStats();
+    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+        uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+        if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+            logFrameStats();
+        }
     }
 }
 
@@ -2022,6 +2265,7 @@
     // with mStateLock held to guarantee that mCurrentState won't change
     // until the transaction is committed.
 
+    mVsyncModulator.onTransactionHandled();
     transactionFlags = getTransactionFlags(eTransactionMask);
     handleTransactionLocked(transactionFlags);
 
@@ -2031,6 +2275,301 @@
     // here the transaction has been committed
 }
 
+DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
+                                                                HWC2::Connection connection) const {
+    // Figure out whether the event is for the primary display or an
+    // external display by matching the Hwc display id against one for a
+    // connected display. If we did not find a match, we then check what
+    // displays are not already connected to determine the type. If we don't
+    // have a connected primary display, we assume the new display is meant to
+    // be the primary display, and then if we don't have an external display,
+    // we assume it is that.
+    const auto primaryDisplayId =
+            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
+    const auto externalDisplayId =
+            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
+    if (primaryDisplayId && primaryDisplayId == display) {
+        return DisplayDevice::DISPLAY_PRIMARY;
+    } else if (externalDisplayId && externalDisplayId == display) {
+        return  DisplayDevice::DISPLAY_EXTERNAL;
+    } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
+        return DisplayDevice::DISPLAY_PRIMARY;
+    } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
+        return DisplayDevice::DISPLAY_EXTERNAL;
+    }
+
+    return DisplayDevice::DISPLAY_ID_INVALID;
+}
+
+void SurfaceFlinger::processDisplayHotplugEventsLocked() {
+    for (const auto& event : mPendingHotplugEvents) {
+        auto displayType = determineDisplayType(event.display, event.connection);
+        if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
+            ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+            continue;
+        }
+
+        if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
+            ALOGE("External displays are not supported by the vr hardware composer.");
+            continue;
+        }
+
+        getBE().mHwc->onHotplug(event.display, displayType, event.connection);
+
+        if (event.connection == HWC2::Connection::Connected) {
+            if (!mBuiltinDisplays[displayType].get()) {
+                ALOGV("Creating built in display %d", displayType);
+                mBuiltinDisplays[displayType] = new BBinder();
+                // All non-virtual displays are currently considered secure.
+                DisplayDeviceState info(displayType, true);
+                info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
+                        "Built-in Screen" : "External Screen";
+                mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+                mInterceptor->saveDisplayCreation(info);
+            }
+        } else {
+            ALOGV("Removing built in display %d", displayType);
+
+            ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
+            if (idx >= 0) {
+                const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
+                mInterceptor->saveDisplayDeletion(info.displayId);
+                mCurrentState.displays.removeItemsAt(idx);
+            }
+            mBuiltinDisplays[displayType].clear();
+        }
+
+        processDisplayChangesLocked();
+    }
+
+    mPendingHotplugEvents.clear();
+}
+
+sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
+        const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
+        const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
+    bool hasWideColorGamut = false;
+    std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes;
+    HdrCapabilities hdrCapabilities;
+    int32_t supportedPerFrameMetadata = 0;
+
+    if (hasWideColorDisplay && hwcId >= 0) {
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+        for (ColorMode colorMode : modes) {
+            switch (colorMode) {
+                case ColorMode::DISPLAY_P3:
+                case ColorMode::ADOBE_RGB:
+                case ColorMode::DCI_P3:
+                    hasWideColorGamut = true;
+                    break;
+                default:
+                    break;
+            }
+
+            std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
+                                                                                       colorMode);
+            hwcColorModes.emplace(colorMode, renderIntents);
+        }
+    }
+
+    if (hwcId >= 0) {
+        getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
+        supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(hwcId);
+    }
+
+    auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
+    auto nativeWindow = nativeWindowSurface->getNativeWindow();
+
+    /*
+     * Create our display's surface
+     */
+    std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
+    renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
+    renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
+    renderSurface->setNativeWindow(nativeWindow.get());
+    const int displayWidth = renderSurface->queryWidth();
+    const int displayHeight = renderSurface->queryHeight();
+
+    // Make sure that composition can never be stalled by a virtual display
+    // consumer that isn't processing buffers fast enough. We have to do this
+    // in two places:
+    // * Here, in case the display is composed entirely by HWC.
+    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
+    //   window's swap interval in eglMakeCurrent, so they'll override the
+    //   interval we set here.
+    if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) {
+        nativeWindow->setSwapInterval(nativeWindow.get(), 0);
+    }
+
+    // virtual displays are always considered enabled
+    auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL
+                                                                           : HWC_POWER_MODE_OFF;
+
+    sp<DisplayDevice> hw =
+            new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
+                              dispSurface, std::move(renderSurface), displayWidth, displayHeight,
+                              hasWideColorGamut, hdrCapabilities,
+                              supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
+
+    if (maxFrameBufferAcquiredBuffers >= 3) {
+        nativeWindowSurface->preallocateBuffers();
+    }
+
+    ColorMode defaultColorMode = ColorMode::NATIVE;
+    Dataspace defaultDataSpace = Dataspace::UNKNOWN;
+    if (hasWideColorGamut) {
+        defaultColorMode = ColorMode::SRGB;
+        defaultDataSpace = Dataspace::SRGB;
+    }
+    setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
+                               RenderIntent::COLORIMETRIC);
+    if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
+        hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+    }
+    hw->setLayerStack(state.layerStack);
+    hw->setProjection(state.orientation, state.viewport, state.frame);
+    hw->setDisplayName(state.displayName);
+
+    return hw;
+}
+
+void SurfaceFlinger::processDisplayChangesLocked() {
+    // here we take advantage of Vector's copy-on-write semantics to
+    // improve performance by skipping the transaction entirely when
+    // know that the lists are identical
+    const KeyedVector<wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
+    const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
+    if (!curr.isIdenticalTo(draw)) {
+        mVisibleRegionsDirty = true;
+        const size_t cc = curr.size();
+        size_t dc = draw.size();
+
+        // find the displays that were removed
+        // (ie: in drawing state but not in current state)
+        // also handle displays that changed
+        // (ie: displays that are in both lists)
+        for (size_t i = 0; i < dc;) {
+            const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+            if (j < 0) {
+                // in drawing state but not in current state
+                // Call makeCurrent() on the primary display so we can
+                // be sure that nothing associated with this display
+                // is current.
+                const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
+                if (defaultDisplay != nullptr) defaultDisplay->makeCurrent();
+                sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
+                if (hw != nullptr) hw->disconnect(getHwComposer());
+                if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
+                    mEventThread->onHotplugReceived(draw[i].type, false);
+                mDisplays.removeItem(draw.keyAt(i));
+            } else {
+                // this display is in both lists. see if something changed.
+                const DisplayDeviceState& state(curr[j]);
+                const wp<IBinder>& display(curr.keyAt(j));
+                const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
+                const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
+                if (state_binder != draw_binder) {
+                    // changing the surface is like destroying and
+                    // recreating the DisplayDevice, so we just remove it
+                    // from the drawing state, so that it get re-added
+                    // below.
+                    sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
+                    if (hw != nullptr) hw->disconnect(getHwComposer());
+                    mDisplays.removeItem(display);
+                    mDrawingState.displays.removeItemsAt(i);
+                    dc--;
+                    // at this point we must loop to the next item
+                    continue;
+                }
+
+                const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
+                if (disp != nullptr) {
+                    if (state.layerStack != draw[i].layerStack) {
+                        disp->setLayerStack(state.layerStack);
+                    }
+                    if ((state.orientation != draw[i].orientation) ||
+                        (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
+                        disp->setProjection(state.orientation, state.viewport, state.frame);
+                    }
+                    if (state.width != draw[i].width || state.height != draw[i].height) {
+                        disp->setDisplaySize(state.width, state.height);
+                    }
+                }
+            }
+            ++i;
+        }
+
+        // find displays that were added
+        // (ie: in current state but not in drawing state)
+        for (size_t i = 0; i < cc; i++) {
+            if (draw.indexOfKey(curr.keyAt(i)) < 0) {
+                const DisplayDeviceState& state(curr[i]);
+
+                sp<DisplaySurface> dispSurface;
+                sp<IGraphicBufferProducer> producer;
+                sp<IGraphicBufferProducer> bqProducer;
+                sp<IGraphicBufferConsumer> bqConsumer;
+                mCreateBufferQueue(&bqProducer, &bqConsumer, false);
+
+                int32_t hwcId = -1;
+                if (state.isVirtualDisplay()) {
+                    // Virtual displays without a surface are dormant:
+                    // they have external state (layer stack, projection,
+                    // etc.) but no internal state (i.e. a DisplayDevice).
+                    if (state.surface != nullptr) {
+                        // Allow VR composer to use virtual displays.
+                        if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+                            int width = 0;
+                            int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+                            ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
+                            int height = 0;
+                            status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+                            ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
+                            int intFormat = 0;
+                            status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat);
+                            ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
+                            auto format = static_cast<ui::PixelFormat>(intFormat);
+
+                            getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+                        }
+
+                        // TODO: Plumb requested format back up to consumer
+
+                        sp<VirtualDisplaySurface> vds =
+                                new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+                                                          bqProducer, bqConsumer,
+                                                          state.displayName);
+
+                        dispSurface = vds;
+                        producer = vds;
+                    }
+                } else {
+                    ALOGE_IF(state.surface != nullptr,
+                             "adding a supported display, but rendering "
+                             "surface is provided (%p), ignoring it",
+                             state.surface.get());
+
+                    hwcId = state.type;
+                    dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
+                    producer = bqProducer;
+                }
+
+                const wp<IBinder>& display(curr.keyAt(i));
+                if (dispSurface != nullptr) {
+                    mDisplays.add(display,
+                                  setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+                                                                producer));
+                    if (!state.isVirtualDisplay()) {
+                        mEventThread->onHotplugReceived(state.type, true);
+                    }
+                }
+            }
+        }
+    }
+
+    mDrawingState.displays = mCurrentState.displays;
+}
+
 void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
 {
     // Notify all layers of available frames
@@ -2059,165 +2598,11 @@
      */
 
     if (transactionFlags & eDisplayTransactionNeeded) {
-        // here we take advantage of Vector's copy-on-write semantics to
-        // improve performance by skipping the transaction entirely when
-        // know that the lists are identical
-        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
-        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
-        if (!curr.isIdenticalTo(draw)) {
-            mVisibleRegionsDirty = true;
-            const size_t cc = curr.size();
-                  size_t dc = draw.size();
-
-            // find the displays that were removed
-            // (ie: in drawing state but not in current state)
-            // also handle displays that changed
-            // (ie: displays that are in both lists)
-            for (size_t i=0 ; i<dc ; i++) {
-                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
-                if (j < 0) {
-                    // in drawing state but not in current state
-                    if (!draw[i].isMainDisplay()) {
-                        // Call makeCurrent() on the primary display so we can
-                        // be sure that nothing associated with this display
-                        // is current.
-                        const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
-                        defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
-                        sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
-                        if (hw != NULL)
-                            hw->disconnect(getHwComposer());
-                        if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
-                            mEventThread->onHotplugReceived(draw[i].type, false);
-                        mDisplays.removeItem(draw.keyAt(i));
-                    } else {
-                        ALOGW("trying to remove the main display");
-                    }
-                } else {
-                    // this display is in both lists. see if something changed.
-                    const DisplayDeviceState& state(curr[j]);
-                    const wp<IBinder>& display(curr.keyAt(j));
-                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
-                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
-                    if (state_binder != draw_binder) {
-                        // changing the surface is like destroying and
-                        // recreating the DisplayDevice, so we just remove it
-                        // from the drawing state, so that it get re-added
-                        // below.
-                        sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
-                        if (hw != NULL)
-                            hw->disconnect(getHwComposer());
-                        mDisplays.removeItem(display);
-                        mDrawingState.displays.removeItemsAt(i);
-                        dc--; i--;
-                        // at this point we must loop to the next item
-                        continue;
-                    }
-
-                    const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
-                    if (disp != NULL) {
-                        if (state.layerStack != draw[i].layerStack) {
-                            disp->setLayerStack(state.layerStack);
-                        }
-                        if ((state.orientation != draw[i].orientation)
-                                || (state.viewport != draw[i].viewport)
-                                || (state.frame != draw[i].frame))
-                        {
-                            disp->setProjection(state.orientation,
-                                    state.viewport, state.frame);
-                        }
-                        if (state.width != draw[i].width || state.height != draw[i].height) {
-                            disp->setDisplaySize(state.width, state.height);
-                        }
-                    }
-                }
-            }
-
-            // find displays that were added
-            // (ie: in current state but not in drawing state)
-            for (size_t i=0 ; i<cc ; i++) {
-                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
-                    const DisplayDeviceState& state(curr[i]);
-
-                    sp<DisplaySurface> dispSurface;
-                    sp<IGraphicBufferProducer> producer;
-                    sp<IGraphicBufferProducer> bqProducer;
-                    sp<IGraphicBufferConsumer> bqConsumer;
-                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
-
-                    int32_t hwcId = -1;
-                    if (state.isVirtualDisplay()) {
-                        // Virtual displays without a surface are dormant:
-                        // they have external state (layer stack, projection,
-                        // etc.) but no internal state (i.e. a DisplayDevice).
-                        if (state.surface != NULL) {
-
-                            // Allow VR composer to use virtual displays.
-                            if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) {
-                                int width = 0;
-                                int status = state.surface->query(
-                                        NATIVE_WINDOW_WIDTH, &width);
-                                ALOGE_IF(status != NO_ERROR,
-                                        "Unable to query width (%d)", status);
-                                int height = 0;
-                                status = state.surface->query(
-                                        NATIVE_WINDOW_HEIGHT, &height);
-                                ALOGE_IF(status != NO_ERROR,
-                                        "Unable to query height (%d)", status);
-                                int intFormat = 0;
-                                status = state.surface->query(
-                                        NATIVE_WINDOW_FORMAT, &intFormat);
-                                ALOGE_IF(status != NO_ERROR,
-                                        "Unable to query format (%d)", status);
-                                auto format = static_cast<android_pixel_format_t>(
-                                        intFormat);
-
-                                mHwc->allocateVirtualDisplay(width, height, &format,
-                                        &hwcId);
-                            }
-
-                            // TODO: Plumb requested format back up to consumer
-
-                            sp<VirtualDisplaySurface> vds =
-                                    new VirtualDisplaySurface(*mHwc,
-                                            hwcId, state.surface, bqProducer,
-                                            bqConsumer, state.displayName);
-
-                            dispSurface = vds;
-                            producer = vds;
-                        }
-                    } else {
-                        ALOGE_IF(state.surface!=NULL,
-                                "adding a supported display, but rendering "
-                                "surface is provided (%p), ignoring it",
-                                state.surface.get());
-
-                        hwcId = state.type;
-                        dispSurface = new FramebufferSurface(*mHwc, hwcId, bqConsumer);
-                        producer = bqProducer;
-                    }
-
-                    const wp<IBinder>& display(curr.keyAt(i));
-                    if (dispSurface != NULL) {
-                        sp<DisplayDevice> hw =
-                                new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                                  dispSurface, producer,
-                                                  mRenderEngine->getEGLConfig(),
-                                                  hasWideColorDisplay);
-                        hw->setLayerStack(state.layerStack);
-                        hw->setProjection(state.orientation,
-                                state.viewport, state.frame);
-                        hw->setDisplayName(state.displayName);
-                        mDisplays.add(display, hw);
-                        if (!state.isVirtualDisplay()) {
-                            mEventThread->onHotplugReceived(state.type, true);
-                        }
-                    }
-                }
-            }
-        }
+        processDisplayChangesLocked();
+        processDisplayHotplugEventsLocked();
     }
 
-    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
+    if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
         // The transform hint might have changed for some layers
         // (either because a display has changed, or because a layer
         // as changed).
@@ -2254,16 +2639,17 @@
                 for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
                     sp<const DisplayDevice> hw(mDisplays[dpy]);
                     if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
-                        if (disp == NULL) {
-                            disp = hw;
+                        if (disp == nullptr) {
+                            disp = std::move(hw);
                         } else {
-                            disp = NULL;
+                            disp = nullptr;
                             break;
                         }
                     }
                 }
             }
-            if (disp == NULL) {
+
+            if (disp == nullptr) {
                 // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
                 // redraw after transform hint changes. See bug 8508397.
 
@@ -2272,7 +2658,12 @@
                 // screen off/on times.
                 disp = getDefaultDisplayDeviceLocked();
             }
-            layer->updateTransformHint(disp);
+
+            // disp can be null if there is no display available at all to get
+            // the transform hint from.
+            if (disp != nullptr) {
+                layer->updateTransformHint(disp);
+            }
 
             first = false;
         });
@@ -2343,6 +2734,9 @@
     mAnimCompositionPending = mAnimTransactionPending;
 
     mDrawingState = mCurrentState;
+    // clear the "changed" flags in current state
+    mCurrentState.colorMatrixChanged = false;
+
     mDrawingState.traverseInZOrder([](Layer* layer) {
         layer->commitChildList();
     });
@@ -2422,7 +2816,7 @@
 
                 // compute the opaque region
                 const int32_t layerOrientation = tr.getOrientation();
-                if (s.alpha == 1.0f && !translucent &&
+                if (layer->getAlpha() == 1.0f && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
                     opaqueRegion = visibleRegion;
@@ -2430,6 +2824,11 @@
             }
         }
 
+        if (visibleRegion.isEmpty()) {
+            layer->clearVisibilityRegions();
+            return;
+        }
+
         // Clip the covered region to the visible region
         coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
 
@@ -2542,6 +2941,12 @@
         signalLayerUpdate();
     }
 
+    // enter boot animation on first buffer latch
+    if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
+        ALOGI("Enter boot animation");
+        mBootStage = BootStage::BOOTANIMATION;
+    }
+
     // Only continue with the refresh if there is actually new work to do
     return !mLayersWithQueuedFrames.empty() && newDataLatched;
 }
@@ -2567,92 +2972,80 @@
     }
 
     ALOGV("doDisplayComposition");
-
-    Region dirtyRegion(inDirtyRegion);
-
-    // compute the invalid region
-    displayDevice->swapRegion.orSelf(dirtyRegion);
-
-    uint32_t flags = displayDevice->getFlags();
-    if (flags & DisplayDevice::SWAP_RECTANGLE) {
-        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
-        // takes a rectangle, we must make sure to update that whole
-        // rectangle in that case
-        dirtyRegion.set(displayDevice->swapRegion.bounds());
-    } else {
-        if (flags & DisplayDevice::PARTIAL_UPDATES) {
-            // We need to redraw the rectangle that will be updated
-            // (pushed to the framebuffer).
-            // This is needed because PARTIAL_UPDATES only takes one
-            // rectangle instead of a region (see DisplayDevice::flip())
-            dirtyRegion.set(displayDevice->swapRegion.bounds());
-        } else {
-            // we need to redraw everything (the whole screen)
-            dirtyRegion.set(displayDevice->bounds());
-            displayDevice->swapRegion = dirtyRegion;
-        }
-    }
-
-    if (!doComposeSurfaces(displayDevice, dirtyRegion)) return;
-
-    // update the swap region and clear the dirty region
-    displayDevice->swapRegion.orSelf(dirtyRegion);
+    if (!doComposeSurfaces(displayDevice)) return;
 
     // swap buffers (presentation)
     displayDevice->swapBuffers(getHwComposer());
 }
 
-bool SurfaceFlinger::doComposeSurfaces(
-        const sp<const DisplayDevice>& displayDevice, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
 {
     ALOGV("doComposeSurfaces");
 
+    const Region bounds(displayDevice->bounds());
+    const DisplayRenderArea renderArea(displayDevice);
     const auto hwcId = displayDevice->getHwcDisplayId();
+    const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+    ATRACE_INT("hasClientComposition", hasClientComposition);
 
-    mat4 oldColorMatrix;
-    const bool applyColorMatrix = !mHwc->hasDeviceComposition(hwcId) &&
-            !mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
-    if (applyColorMatrix) {
-        mat4 colorMatrix = mColorMatrix * mDaltonizer();
-        oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
-    }
+    bool applyColorMatrix = false;
+    bool needsEnhancedColorMatrix = false;
 
-    bool hasClientComposition = mHwc->hasClientComposition(hwcId);
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-#ifdef USE_HWC2
-        mRenderEngine->setWideColor(
-                displayDevice->getWideColorSupport() && !mForceNativeColorMode);
-        mRenderEngine->setColorMode(mForceNativeColorMode ?
-                HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
-#endif
-        if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
+        Dataspace outputDataspace = Dataspace::UNKNOWN;
+        if (displayDevice->hasWideColorGamut()) {
+            outputDataspace = displayDevice->getCompositionDataSpace();
+        }
+        getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+        getBE().mRenderEngine->setDisplayMaxLuminance(
+                displayDevice->getHdrCapabilities().getDesiredMaxLuminance());
+
+        const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+        const bool skipClientColorTransform = getBE().mHwc->hasCapability(
+            HWC2::Capability::SkipClientColorTransform);
+
+        mat4 colorMatrix;
+        applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
+        if (applyColorMatrix) {
+            colorMatrix = mDrawingState.colorMatrix;
+        }
+
+        // The current enhanced saturation matrix is designed to enhance Display P3,
+        // thus we only apply this matrix when the render intent is not colorimetric
+        // and the output color space is Display P3.
+        needsEnhancedColorMatrix =
+            (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
+             outputDataspace == Dataspace::DISPLAY_P3);
+        if (needsEnhancedColorMatrix) {
+            colorMatrix *= mEnhancedSaturationMatrix;
+        }
+
+        getRenderEngine().setupColorTransform(colorMatrix);
+
+        if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
-            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            getRenderEngine().resetCurrentSurface();
 
             // |mStateLock| not needed as we are on the main thread
-            if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) {
+            if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
               ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
             }
             return false;
         }
 
         // Never touch the framebuffer if we don't have any framebuffer layers
-        const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId);
         if (hasDeviceComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
             // remove where there are opaque FB layers. however, on some
             // GPUs doing a "clean slate" clear might be more efficient.
             // We'll revisit later if needed.
-            mRenderEngine->clearWithColor(0, 0, 0, 0);
+            getBE().mRenderEngine->clearWithColor(0, 0, 0, 0);
         } else {
-            // we start with the whole screen area
-            const Region bounds(displayDevice->getBounds());
-
-            // we remove the scissor part
+            // we start with the whole screen area and remove the scissor part
             // we're left with the letterbox region
             // (common case is that letterbox ends-up being empty)
             const Region letterbox(bounds.subtract(displayDevice->getScissor()));
@@ -2660,9 +3053,6 @@
             // compute the area to clear
             Region region(displayDevice->undefinedRegion.merge(letterbox));
 
-            // but limit it to the dirty region
-            region.andSelf(dirty);
-
             // screen is already cleared here
             if (!region.isEmpty()) {
                 // can happen with SurfaceView
@@ -2670,22 +3060,17 @@
             }
         }
 
-        if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
-            // just to be on the safe side, we don't set the
-            // scissor on the main display. It should never be needed
-            // anyways (though in theory it could since the API allows it).
-            const Rect& bounds(displayDevice->getBounds());
-            const Rect& scissor(displayDevice->getScissor());
-            if (scissor != bounds) {
-                // scissor doesn't match the screen's dimensions, so we
-                // need to clear everything outside of it and enable
-                // the GL scissor so we don't draw anything where we shouldn't
+        const Rect& bounds(displayDevice->getBounds());
+        const Rect& scissor(displayDevice->getScissor());
+        if (scissor != bounds) {
+            // scissor doesn't match the screen's dimensions, so we
+            // need to clear everything outside of it and enable
+            // the GL scissor so we don't draw anything where we shouldn't
 
-                // enable scissor for this frame
-                const uint32_t height = displayDevice->getHeight();
-                mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
-                        scissor.getWidth(), scissor.getHeight());
-            }
+            // enable scissor for this frame
+            const uint32_t height = displayDevice->getHeight();
+            getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
+                                              scissor.getWidth(), scissor.getHeight());
         }
     }
 
@@ -2695,66 +3080,54 @@
 
     ALOGV("Rendering client layers");
     const Transform& displayTransform = displayDevice->getTransform();
-    if (hwcId >= 0) {
-        // we're using h/w composer
-        bool firstLayer = true;
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const Region clip(dirty.intersect(
-                    displayTransform.transform(layer->visibleRegion)));
-            ALOGV("Layer: %s", layer->getName().string());
-            ALOGV("  Composition type: %s",
-                    to_string(layer->getCompositionType(hwcId)).c_str());
-            if (!clip.isEmpty()) {
-                switch (layer->getCompositionType(hwcId)) {
-                    case HWC2::Composition::Cursor:
-                    case HWC2::Composition::Device:
-                    case HWC2::Composition::Sideband:
-                    case HWC2::Composition::SolidColor: {
-                        const Layer::State& state(layer->getDrawingState());
-                        if (layer->getClearClientTarget(hwcId) && !firstLayer &&
-                                layer->isOpaque(state) && (state.alpha == 1.0f)
-                                && hasClientComposition) {
-                            // never clear the very first layer since we're
-                            // guaranteed the FB is already cleared
-                            layer->clearWithOpenGL(displayDevice);
-                        }
-                        break;
+    bool firstLayer = true;
+    for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        const Region clip(bounds.intersect(
+                displayTransform.transform(layer->visibleRegion)));
+        ALOGV("Layer: %s", layer->getName().string());
+        ALOGV("  Composition type: %s",
+                to_string(layer->getCompositionType(hwcId)).c_str());
+        if (!clip.isEmpty()) {
+            switch (layer->getCompositionType(hwcId)) {
+                case HWC2::Composition::Cursor:
+                case HWC2::Composition::Device:
+                case HWC2::Composition::Sideband:
+                case HWC2::Composition::SolidColor: {
+                    const Layer::State& state(layer->getDrawingState());
+                    if (layer->getClearClientTarget(hwcId) && !firstLayer &&
+                            layer->isOpaque(state) && (state.color.a == 1.0f)
+                            && hasClientComposition) {
+                        // never clear the very first layer since we're
+                        // guaranteed the FB is already cleared
+                        layer->clearWithOpenGL(renderArea);
                     }
-                    case HWC2::Composition::Client: {
-                        layer->draw(displayDevice, clip);
-                        break;
-                    }
-                    default:
-                        break;
+                    break;
                 }
-            } else {
-                ALOGV("  Skipping for empty clip");
+                case HWC2::Composition::Client: {
+                    layer->draw(renderArea, clip);
+                    break;
+                }
+                default:
+                    break;
             }
-            firstLayer = false;
+        } else {
+            ALOGV("  Skipping for empty clip");
         }
-    } else {
-        // we're not using h/w composer
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const Region clip(dirty.intersect(
-                    displayTransform.transform(layer->visibleRegion)));
-            if (!clip.isEmpty()) {
-                layer->draw(displayDevice, clip);
-            }
-        }
+        firstLayer = false;
     }
 
-    if (applyColorMatrix) {
-        getRenderEngine().setupColorTransform(oldColorMatrix);
+    if (applyColorMatrix || needsEnhancedColorMatrix) {
+        getRenderEngine().setupColorTransform(mat4());
     }
 
     // disable scissor at the end of the frame
-    mRenderEngine->disableScissor();
+    getBE().mRenderEngine->disableScissor();
     return true;
 }
 
 void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
     const int32_t height = displayDevice->getHeight();
-    RenderEngine& engine(getRenderEngine());
+    auto& engine(getRenderEngine());
     engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
 
@@ -2775,14 +3148,21 @@
         if (parent == nullptr) {
             mCurrentState.layersSortedByZ.add(lbc);
         } else {
-            if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+            if (parent->isPendingRemoval()) {
                 ALOGE("addClientLayer called with a removed parent");
                 return NAME_NOT_FOUND;
             }
             parent->addChild(lbc);
         }
 
-        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+        if (gbc != nullptr) {
+            mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
+            LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() >
+                                        mMaxGraphicBufferProducerListSize,
+                                "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+                                mGraphicBufferProducerList.size(),
+                                mMaxGraphicBufferProducerListSize, mNumLayers);
+        }
         mLayersAdded = true;
         mNumLayers++;
     }
@@ -2795,6 +3175,14 @@
 
 status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
     Mutex::Autolock _l(mStateLock);
+    return removeLayerLocked(mStateLock, layer, topLevelOnly);
+}
+
+status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
+                                           bool topLevelOnly) {
+    if (layer->isPendingRemoval()) {
+        return NO_ERROR;
+    }
 
     const auto& p = layer->getParent();
     ssize_t index;
@@ -2848,15 +3236,43 @@
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
+    return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
+        VSyncModulator::TransactionStart transactionStart) {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+    mVsyncModulator.setTransactionStart(transactionStart);
     if ((old & flags)==0) { // wake the server up
         signalTransaction();
     }
     return old;
 }
 
+bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
+    for (const ComposerState& state : states) {
+        // Here we need to check that the interface we're given is indeed
+        // one of our own. A malicious client could give us a nullptr
+        // IInterface, or one of its own or even one of our own but a
+        // different type. All these situations would cause us to crash.
+        if (state.client == nullptr) {
+            return true;
+        }
+
+        sp<IBinder> binder = IInterface::asBinder(state.client);
+        if (binder == nullptr) {
+            return true;
+        }
+
+        if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void SurfaceFlinger::setTransactionState(
-        const Vector<ComposerState>& state,
+        const Vector<ComposerState>& states,
         const Vector<DisplayState>& displays,
         uint32_t flags)
 {
@@ -2864,6 +3280,10 @@
     Mutex::Autolock _l(mStateLock);
     uint32_t transactionFlags = 0;
 
+    if (containsAnyInvalidClientState(states)) {
+        return;
+    }
+
     if (flags & eAnimation) {
         // For window updates that are part of an animation we must wait for
         // previous animation "frames" to be handled.
@@ -2880,31 +3300,20 @@
         }
     }
 
-    size_t count = displays.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const DisplayState& s(displays[i]);
-        transactionFlags |= setDisplayStateLocked(s);
+    for (const DisplayState& display : displays) {
+        transactionFlags |= setDisplayStateLocked(display);
     }
 
-    count = state.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const ComposerState& s(state[i]);
-        // Here we need to check that the interface we're given is indeed
-        // one of our own. A malicious client could give us a NULL
-        // IInterface, or one of its own or even one of our own but a
-        // different type. All these situations would cause us to crash.
-        //
-        // NOTE: it would be better to use RTTI as we could directly check
-        // that we have a Client*. however, RTTI is disabled in Android.
-        if (s.client != NULL) {
-            sp<IBinder> binder = IInterface::asBinder(s.client);
-            if (binder != NULL) {
-                if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) {
-                    sp<Client> client( static_cast<Client *>(s.client.get()) );
-                    transactionFlags |= setClientStateLocked(client, s.state);
-                }
-            }
-        }
+    for (const ComposerState& state : states) {
+        transactionFlags |= setClientStateLocked(state);
+    }
+
+    // Iterate through all layers again to determine if any need to be destroyed. Marking layers
+    // as destroyed should only occur after setting all other states. This is to allow for a
+    // child re-parent to happen before marking its original parent as destroyed (which would
+    // then mark the child as destroyed).
+    for (const ComposerState& state : states) {
+        setDestroyStateLocked(state);
     }
 
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -2917,12 +3326,15 @@
     }
 
     if (transactionFlags) {
-        if (mInterceptor.isEnabled()) {
-            mInterceptor.saveTransaction(state, mCurrentState.displays, displays, flags);
+        if (mInterceptor->isEnabled()) {
+            mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
         }
 
         // this triggers the transaction
-        setTransactionFlags(transactionFlags);
+        const auto start = (flags & eEarlyWakeup)
+                ? VSyncModulator::TransactionStart::EARLY
+                : VSyncModulator::TransactionStart::NORMAL;
+        setTransactionFlags(transactionFlags, start);
 
         // if this is a synchronous transaction, wait for it to take effect
         // before returning.
@@ -2995,131 +3407,218 @@
     return flags;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(
-        const sp<Client>& client,
-        const layer_state_t& s)
-{
-    uint32_t flags = 0;
+bool callingThreadHasUnscopedSurfaceFlingerAccess() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+
+    if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
+            !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+        return false;
+    }
+    return true;
+}
+
+uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
+    const layer_state_t& s = composerState.state;
+    sp<Client> client(static_cast<Client*>(composerState.client.get()));
+
     sp<Layer> layer(client->getLayerUser(s.surface));
-    if (layer != 0) {
-        const uint32_t what = s.what;
-        bool geometryAppliesWithResize =
-                what & layer_state_t::eGeometryAppliesWithResize;
-        if (what & layer_state_t::ePositionChanged) {
-            if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
-                flags |= eTraversalNeeded;
-            }
+    if (layer == nullptr) {
+        return 0;
+    }
+
+    if (layer->isPendingRemoval()) {
+        ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
+        return 0;
+    }
+
+    uint32_t flags = 0;
+
+    const uint32_t what = s.what;
+    bool geometryAppliesWithResize =
+            what & layer_state_t::eGeometryAppliesWithResize;
+
+    // If we are deferring transaction, make sure to push the pending state, as otherwise the
+    // pending state will also be deferred.
+    if (what & layer_state_t::eDeferTransaction) {
+        layer->pushPendingState();
+    }
+
+    if (what & layer_state_t::ePositionChanged) {
+        if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
+            flags |= eTraversalNeeded;
         }
-        if (what & layer_state_t::eLayerChanged) {
-            // NOTE: index needs to be calculated before we update the state
-            const auto& p = layer->getParent();
-            if (p == nullptr) {
-                ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-                if (layer->setLayer(s.z) && idx >= 0) {
-                    mCurrentState.layersSortedByZ.removeAt(idx);
-                    mCurrentState.layersSortedByZ.add(layer);
-                    // we need traversal (state changed)
-                    // AND transaction (list changed)
-                    flags |= eTransactionNeeded|eTraversalNeeded;
-                }
-            } else {
-                if (p->setChildLayer(layer, s.z)) {
-                    flags |= eTransactionNeeded|eTraversalNeeded;
-                }
-            }
-        }
-        if (what & layer_state_t::eRelativeLayerChanged) {
-            if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
-                flags |= eTransactionNeeded|eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eSizeChanged) {
-            if (layer->setSize(s.w, s.h)) {
-                flags |= eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eAlphaChanged) {
-            if (layer->setAlpha(s.alpha))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eMatrixChanged) {
-            if (layer->setMatrix(s.matrix))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eTransparentRegionChanged) {
-            if (layer->setTransparentRegionHint(s.transparentRegion))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eFlagsChanged) {
-            if (layer->setFlags(s.flags, s.mask))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eCropChanged) {
-            if (layer->setCrop(s.crop, !geometryAppliesWithResize))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eLayerStackChanged) {
+    }
+    if (what & layer_state_t::eLayerChanged) {
+        // NOTE: index needs to be calculated before we update the state
+        const auto& p = layer->getParent();
+        if (p == nullptr) {
             ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-            // We only allow setting layer stacks for top level layers,
-            // everything else inherits layer stack from its parent.
-            if (layer->hasParent()) {
-                ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
-                        layer->getName().string());
-            } else if (idx < 0) {
-                ALOGE("Attempt to set layer stack on layer without parent (%s) that "
-                        "that also does not appear in the top level layer list. Something"
-                        " has gone wrong.", layer->getName().string());
-            } else if (layer->setLayerStack(s.layerStack)) {
+            if (layer->setLayer(s.z) && idx >= 0) {
                 mCurrentState.layersSortedByZ.removeAt(idx);
                 mCurrentState.layersSortedByZ.add(layer);
                 // we need traversal (state changed)
                 // AND transaction (list changed)
                 flags |= eTransactionNeeded|eTraversalNeeded;
             }
-        }
-        if (what & layer_state_t::eDeferTransaction) {
-            if (s.barrierHandle != nullptr) {
-                layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
-            } else if (s.barrierGbp != nullptr) {
-                const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
-                if (authenticateSurfaceTextureLocked(gbp)) {
-                    const auto& otherLayer =
-                        (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
-                    layer->deferTransactionUntil(otherLayer, s.frameNumber);
-                } else {
-                    ALOGE("Attempt to defer transaction to to an"
-                            " unrecognized GraphicBufferProducer");
-                }
-            }
-            // We don't trigger a traversal here because if no other state is
-            // changed, we don't want this to cause any more work
-        }
-        if (what & layer_state_t::eReparentChildren) {
-            if (layer->reparentChildren(s.reparentHandle)) {
+        } else {
+            if (p->setChildLayer(layer, s.z)) {
                 flags |= eTransactionNeeded|eTraversalNeeded;
             }
         }
-        if (what & layer_state_t::eDetachChildren) {
-            layer->detachChildren();
-        }
-        if (what & layer_state_t::eOverrideScalingModeChanged) {
-            layer->setOverrideScalingMode(s.overrideScalingMode);
-            // We don't trigger a traversal here because if no other state is
-            // changed, we don't want this to cause any more work
+    }
+    if (what & layer_state_t::eRelativeLayerChanged) {
+        // NOTE: index needs to be calculated before we update the state
+        const auto& p = layer->getParent();
+        if (p == nullptr) {
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+            if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
+                // we need traversal (state changed)
+                // AND transaction (list changed)
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        } else {
+            if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) {
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
         }
     }
+    if (what & layer_state_t::eSizeChanged) {
+        if (layer->setSize(s.w, s.h)) {
+            flags |= eTraversalNeeded;
+        }
+    }
+    if (what & layer_state_t::eAlphaChanged) {
+        if (layer->setAlpha(s.alpha))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eColorChanged) {
+        if (layer->setColor(s.color))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eMatrixChanged) {
+        // TODO: b/109894387
+        //
+        // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary
+        // rotation. To see the problem observe that if we have a square parent, and a child
+        // of the same size, then we rotate the child 45 degrees around it's center, the child
+        // must now be cropped to a non rectangular 8 sided region.
+        //
+        // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
+        // private API, and the WindowManager only uses rotation in one case, which is on a top
+        // level layer in which cropping is not an issue.
+        //
+        // However given that abuse of rotation matrices could lead to surfaces extending outside
+        // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
+        // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
+        // transformations.
+        if (layer->setMatrix(s.matrix, callingThreadHasUnscopedSurfaceFlingerAccess()))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eTransparentRegionChanged) {
+        if (layer->setTransparentRegionHint(s.transparentRegion))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eFlagsChanged) {
+        if (layer->setFlags(s.flags, s.mask))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eCropChanged) {
+        if (layer->setCrop(s.crop, !geometryAppliesWithResize))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eFinalCropChanged) {
+        if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eLayerStackChanged) {
+        ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+        // We only allow setting layer stacks for top level layers,
+        // everything else inherits layer stack from its parent.
+        if (layer->hasParent()) {
+            ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
+                    layer->getName().string());
+        } else if (idx < 0) {
+            ALOGE("Attempt to set layer stack on layer without parent (%s) that "
+                    "that also does not appear in the top level layer list. Something"
+                    " has gone wrong.", layer->getName().string());
+        } else if (layer->setLayerStack(s.layerStack)) {
+            mCurrentState.layersSortedByZ.removeAt(idx);
+            mCurrentState.layersSortedByZ.add(layer);
+            // we need traversal (state changed)
+            // AND transaction (list changed)
+            flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
+        }
+    }
+    if (what & layer_state_t::eDeferTransaction) {
+        if (s.barrierHandle != nullptr) {
+            layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
+        } else if (s.barrierGbp != nullptr) {
+            const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
+            if (authenticateSurfaceTextureLocked(gbp)) {
+                const auto& otherLayer =
+                    (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
+                layer->deferTransactionUntil(otherLayer, s.frameNumber);
+            } else {
+                ALOGE("Attempt to defer transaction to to an"
+                        " unrecognized GraphicBufferProducer");
+            }
+        }
+        // We don't trigger a traversal here because if no other state is
+        // changed, we don't want this to cause any more work
+    }
+    if (what & layer_state_t::eReparent) {
+        bool hadParent = layer->hasParent();
+        if (layer->reparent(s.parentHandleForChild)) {
+            if (!hadParent) {
+                mCurrentState.layersSortedByZ.remove(layer);
+            }
+            flags |= eTransactionNeeded|eTraversalNeeded;
+        }
+    }
+    if (what & layer_state_t::eReparentChildren) {
+        if (layer->reparentChildren(s.reparentHandle)) {
+            flags |= eTransactionNeeded|eTraversalNeeded;
+        }
+    }
+    if (what & layer_state_t::eDetachChildren) {
+        layer->detachChildren();
+    }
+    if (what & layer_state_t::eOverrideScalingModeChanged) {
+        layer->setOverrideScalingMode(s.overrideScalingMode);
+        // We don't trigger a traversal here because if no other state is
+        // changed, we don't want this to cause any more work
+    }
     return flags;
 }
 
+void SurfaceFlinger::setDestroyStateLocked(const ComposerState& composerState) {
+    const layer_state_t& state = composerState.state;
+    sp<Client> client(static_cast<Client*>(composerState.client.get()));
+
+    sp<Layer> layer(client->getLayerUser(state.surface));
+    if (layer == nullptr) {
+        return;
+    }
+
+    if (layer->isPendingRemoval()) {
+        ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
+        return;
+    }
+
+    if (state.what & layer_state_t::eDestroySurface) {
+        removeLayerLocked(mStateLock, layer);
+    }
+}
+
 status_t SurfaceFlinger::createLayer(
         const String8& name,
         const sp<Client>& client,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
+        int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
         sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
 {
     if (int32_t(w|h) < 0) {
@@ -3136,14 +3635,15 @@
 
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
-            result = createNormalLayer(client,
+            result = createBufferLayer(client,
                     uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
+
             break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
+        case ISurfaceComposerClient::eFXSurfaceColor:
+            result = createColorLayer(client,
                     uniqueName, w, h, flags,
-                    handle, gbp, &layer);
+                    handle, &layer);
             break;
         default:
             result = BAD_VALUE;
@@ -3167,7 +3667,7 @@
     if (result != NO_ERROR) {
         return result;
     }
-    mInterceptor.saveSurfaceCreation(layer);
+    mInterceptor->saveSurfaceCreation(layer);
 
     setTransactionFlags(eTransactionNeeded);
     return result;
@@ -3181,10 +3681,13 @@
     // Tack on our counter whether there is a hit or not, so everyone gets a tag
     String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
 
+    // Grab the state lock since we're accessing mCurrentState
+    Mutex::Autolock lock(mStateLock);
+
     // Loop over layers until we're sure there is no matching name
     while (matchFound) {
         matchFound = false;
-        mDrawingState.traverseInZOrder([&](Layer* layer) {
+        mCurrentState.traverseInZOrder([&](Layer* layer) {
             if (layer->getName() == uniqueName) {
                 matchFound = true;
                 uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
@@ -3197,7 +3700,7 @@
     return uniqueName;
 }
 
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
 {
@@ -3212,24 +3715,24 @@
         break;
     }
 
-    *outLayer = new Layer(this, client, name, w, h, flags);
-    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+    sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+    status_t err = layer->setBuffers(w, h, format, flags);
     if (err == NO_ERROR) {
-        *handle = (*outLayer)->getHandle();
-        *gbp = (*outLayer)->getProducer();
+        *handle = layer->getHandle();
+        *gbp = layer->getProducer();
+        *outLayer = layer;
     }
 
-    ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+    ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
     return err;
 }
 
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
-        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+        sp<IBinder>* handle, sp<Layer>* outLayer)
 {
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
+    *outLayer = new ColorLayer(this, client, name, w, h, flags);
     *handle = (*outLayer)->getHandle();
-    *gbp = (*outLayer)->getProducer();
     return NO_ERROR;
 }
 
@@ -3238,8 +3741,8 @@
     // called by a client when it wants to remove a Layer
     status_t err = NO_ERROR;
     sp<Layer> l(client->getLayerUser(handle));
-    if (l != NULL) {
-        mInterceptor.saveSurfaceDeletion(l);
+    if (l != nullptr) {
+        mInterceptor->saveSurfaceDeletion(l);
         err = removeLayer(l);
         ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
                 "error removing layer=%p (%s)", l.get(), strerror(-err));
@@ -3281,7 +3784,7 @@
     setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
                          /*stateLockHeld*/ false);
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -3321,14 +3824,14 @@
         return;
     }
 
-    if (mInterceptor.isEnabled()) {
+    if (mInterceptor->isEnabled()) {
         ConditionalLock lock(mStateLock, !stateLockHeld);
         ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
         if (idx < 0) {
             ALOGW("Surface Interceptor SavePowerMode: invalid display token");
             return;
         }
-        mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
+        mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
     }
 
     if (currentMode == HWC_POWER_MODE_OFF) {
@@ -3343,7 +3846,7 @@
 
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
-        repaintEverythingLocked();
+        repaintEverything();
 
         struct sched_param param = {0};
         param.sched_priority = 1;
@@ -3357,7 +3860,8 @@
             ALOGW("Couldn't set SCHED_OTHER on display off");
         }
 
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+            currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
             disableHardwareVsync(true); // also cancels any in-progress resync
 
             // FIXME: eventthread only knows about the main display right now
@@ -3371,7 +3875,8 @@
                mode == HWC_POWER_MODE_NORMAL) {
         // Update display while dozing
         getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+            currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
             resyncToHardwareVsync(true);
@@ -3388,6 +3893,7 @@
         ALOGE("Attempting to set unknown power mode: %d\n", mode);
         getHwComposer().setPowerMode(type, mode);
     }
+    ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
@@ -3401,7 +3907,7 @@
                     mDisplay(disp) { mMode = mode; }
         virtual bool handler() {
             sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == NULL) {
+            if (hw == nullptr) {
                 ALOGE("Attempt to set power mode = %d for null display %p",
                         mMode, mDisplay.get());
             } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -3420,13 +3926,14 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
+        NO_THREAD_SAFETY_ANALYSIS {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
+
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
         result.appendFormat("Permission Denial: "
@@ -3446,6 +3953,7 @@
         bool dumpAll = true;
         size_t index = 0;
         size_t numArgs = args.size();
+
         if (numArgs) {
             if ((index < numArgs) &&
                     (args[index] == String16("--list"))) {
@@ -3494,10 +4002,49 @@
                 dumpWideColorInfo(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--enable-layer-stats"))) {
+                index++;
+                mLayerStats.enable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--disable-layer-stats"))) {
+                index++;
+                mLayerStats.disable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--clear-layer-stats"))) {
+                index++;
+                mLayerStats.clear();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--dump-layer-stats"))) {
+                index++;
+                mLayerStats.dump(result);
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) && (args[index] == String16("--timestats"))) {
+                index++;
+                mTimeStats.parseArgs(asProto, args, index, result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
-            dumpAllLocked(args, index, result);
+            if (asProto) {
+                LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
+                result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+            } else {
+                dumpAllLocked(args, index, result);
+            }
         }
 
         if (locked) {
@@ -3525,7 +4072,7 @@
         index++;
     }
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     result.appendFormat("%" PRId64 "\n", period);
 
@@ -3571,7 +4118,6 @@
 void SurfaceFlinger::appendSfConfigString(String8& result) const
 {
     result.append(" [sf");
-    result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
 
     if (isLayerTripleBufferingDisabled())
         result.append(" DISABLE_TRIPLE_BUFFERING");
@@ -3588,24 +4134,24 @@
 void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
 {
     result.appendFormat("Static screen stats:\n");
-    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
-        float bucketTimeSec = mFrameBuckets[b] / 1e9;
+    for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
+        float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
         float percent = 100.0f *
-                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+                static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
         result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
                 b + 1, bucketTimeSec, percent);
     }
-    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+    float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
     float percent = 100.0f *
-            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+            static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
     result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
-            NUM_BUCKETS - 1, bucketTimeSec, percent);
+            SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent);
 }
 
 void SurfaceFlinger::recordBufferingStats(const char* layerName,
         std::vector<OccupancyTracker::Segment>&& history) {
-    Mutex::Autolock lock(mBufferingStatsMutex);
-    auto& stats = mBufferingStats[layerName];
+    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
+    auto& stats = getBE().mBufferingStats[layerName];
     for (const auto& segment : history) {
         if (!segment.usedThirdBuffer) {
             stats.twoBufferTime += segment.totalTime;
@@ -3634,12 +4180,12 @@
     result.append("Buffering stats:\n");
     result.append("  [Layer name] <Active time> <Two buffer> "
             "<Double buffered> <Triple buffered>\n");
-    Mutex::Autolock lock(mBufferingStatsMutex);
+    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
     typedef std::tuple<std::string, float, float, float> BufferTuple;
     std::map<float, BufferTuple, std::greater<float>> sorted;
-    for (const auto& statsPair : mBufferingStats) {
+    for (const auto& statsPair : getBE().mBufferingStats) {
         const char* name = statsPair.first.c_str();
-        const BufferingStats& stats = statsPair.second;
+        const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
         if (stats.numSegments == 0) {
             continue;
         }
@@ -3666,7 +4212,8 @@
 
 void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
     result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
-    result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
+    result.appendFormat("DisplayColorSetting: %s\n",
+            decodeDisplayColorSetting(mDisplayColorSetting).c_str());
 
     // TODO: print out if wide-color mode is active or not
 
@@ -3678,18 +4225,53 @@
         }
 
         result.appendFormat("Display %d color modes:\n", hwcId);
-        std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(hwcId);
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
         for (auto&& mode : modes) {
             result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
         }
 
-        android_color_mode_t currentMode = displayDevice->getActiveColorMode();
+        ColorMode currentMode = displayDevice->getActiveColorMode();
         result.appendFormat("    Current color mode: %s (%d)\n",
                             decodeColorMode(currentMode).c_str(), currentMode);
     }
     result.append("\n");
 }
 
+LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
+    LayersProto layersProto;
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const State& state = useDrawing ? mDrawingState : mCurrentState;
+    state.traverseInZOrder([&](Layer* layer) {
+        LayerProto* layerProto = layersProto.add_layers();
+        layer->writeToProto(layerProto, stateSet);
+    });
+
+    return layersProto;
+}
+
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+    LayersProto layersProto;
+    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+
+    SizeProto* resolution = layersProto.mutable_resolution();
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
+
+    layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
+    layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
+    layersProto.set_global_transform(
+            static_cast<int32_t>(displayDevice->getOrientationTransform()));
+
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
+        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+            LayerProto* layerProto = layersProto.add_layers();
+            layer->writeToProto(layerProto, hwcId);
+        }
+    });
+
+    return layersProto;
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -3730,14 +4312,27 @@
     result.append(SyncFeatures::getInstance().toString());
     result.append("\n");
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
 
     colorizer.bold(result);
     result.append("DispSync configuration: ");
     colorizer.reset(result);
-    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
-            "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
+    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
+    result.appendFormat(
+        "app phase %" PRId64 " ns, "
+        "sf phase %" PRId64 " ns, "
+        "early app phase %" PRId64 " ns, "
+        "early sf phase %" PRId64 " ns, "
+        "early app gl phase %" PRId64 " ns, "
+        "early sf gl phase %" PRId64 " ns, "
+        "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+        vsyncPhaseOffsetNs,
+        sfVsyncPhaseOffsetNs,
+        appEarlyOffset,
+        sfEarlyOffset,
+        appEarlyGlOffset,
+        sfEarlyOffset,
         dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
     result.append("\n");
 
@@ -3753,10 +4348,14 @@
      */
     colorizer.bold(result);
     result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
+    result.appendFormat("GraphicBufferProducers: %zu, max %zu\n",
+                        mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
     colorizer.reset(result);
-    mCurrentState.traverseInZOrder([&](Layer* layer) {
-        layer->dump(result, colorizer);
-    });
+
+    LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
+    result.append("\n");
 
     /*
      * Dump Display state
@@ -3769,6 +4368,7 @@
         const sp<const DisplayDevice>& hw(mDisplays[dpy]);
         hw->dump(result);
     }
+    result.append("\n");
 
     /*
      * Dump SurfaceFlinger global state
@@ -3781,18 +4381,13 @@
     HWComposer& hwc(getHwComposer());
     sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
-    colorizer.bold(result);
-    result.appendFormat("EGL implementation : %s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
-    colorizer.reset(result);
-    result.appendFormat("%s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
+    getBE().mRenderEngine->dump(result);
 
-    mRenderEngine->dump(result);
-
-    hw->undefinedRegion.dump(result, "undefinedRegion");
-    result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
-            hw->getOrientation(), hw->isDisplayOn());
+    if (hw) {
+        hw->undefinedRegion.dump(result, "undefinedRegion");
+        result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
+                hw->getOrientation(), hw->isDisplayOn());
+    }
     result.appendFormat(
             "  last eglSwapBuffers() time: %f us\n"
             "  last transaction time     : %f us\n"
@@ -3823,6 +4418,12 @@
     result.append("\n");
 
     /*
+     * Tracing state
+     */
+    mTracing.dump(result);
+    result.append("\n");
+
+    /*
      * HWC layer minidump
      */
     for (size_t d = 0; d < mDisplays.size(); d++) {
@@ -3877,7 +4478,7 @@
             break;
         }
     }
-    if (dpy == NULL) {
+    if (dpy == nullptr) {
         ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
         // Just use the primary display so we have something to return
         dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
@@ -3903,6 +4504,30 @@
     return true;
 }
 
+void SurfaceFlinger::updateColorMatrixLocked() {
+    mat4 colorMatrix;
+    if (mGlobalSaturationFactor != 1.0f) {
+        // Rec.709 luma coefficients
+        float3 luminance{0.213f, 0.715f, 0.072f};
+        luminance *= 1.0f - mGlobalSaturationFactor;
+        mat4 saturationMatrix = mat4(
+            vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
+            vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
+            vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
+            vec4{0.0f, 0.0f, 0.0f, 1.0f}
+        );
+        colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer();
+    } else {
+        colorMatrix = mClientColorMatrix * mDaltonizer();
+    }
+
+    if (mCurrentState.colorMatrix != colorMatrix) {
+        mCurrentState.colorMatrix = colorMatrix;
+        mCurrentState.colorMatrixChanged = true;
+        setTransactionFlags(eTransactionNeeded);
+    }
+}
+
 status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
     switch (code) {
         case CREATE_CONNECTION:
@@ -3916,12 +4541,10 @@
         case INJECT_VSYNC:
         {
             // codes that require permission check
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
-                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
-                ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+            if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
+                IPCThreadState* ipc = IPCThreadState::self();
+                ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
+                        ipc->getCallingPid(), ipc->getCallingUid());
                 return PERMISSION_DENIED;
             }
             break;
@@ -3950,6 +4573,17 @@
             }
             break;
         }
+        case CAPTURE_LAYERS: {
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int uid = ipc->getCallingUid();
+            if ((uid != AID_GRAPHICS) &&
+                !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+                ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+                return PERMISSION_DENIED;
+            }
+            break;
+        }
     }
     return OK;
 }
@@ -4026,6 +4660,7 @@
                 return NO_ERROR;
             }
             case 1014: {
+                Mutex::Autolock _l(mStateLock);
                 // daltonize
                 n = data.readInt32();
                 switch (n % 10) {
@@ -4047,33 +4682,33 @@
                 } else {
                     mDaltonizer.setMode(ColorBlindnessMode::Simulation);
                 }
-                invalidateHwcGeometry();
-                repaintEverything();
+
+                updateColorMatrixLocked();
                 return NO_ERROR;
             }
             case 1015: {
+                Mutex::Autolock _l(mStateLock);
                 // apply a color matrix
                 n = data.readInt32();
                 if (n) {
                     // color matrix is sent as a column-major mat4 matrix
                     for (size_t i = 0 ; i < 4; i++) {
                         for (size_t j = 0; j < 4; j++) {
-                            mColorMatrix[i][j] = data.readFloat();
+                            mClientColorMatrix[i][j] = data.readFloat();
                         }
                     }
                 } else {
-                    mColorMatrix = mat4();
+                    mClientColorMatrix = mat4();
                 }
 
                 // Check that supplied matrix's last row is {0,0,0,1} so we can avoid
                 // the division by w in the fragment shader
-                float4 lastRow(transpose(mColorMatrix)[3]);
+                float4 lastRow(transpose(mClientColorMatrix)[3]);
                 if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
                     ALOGE("The color transform's last row must be (0, 0, 0, 1)");
                 }
 
-                invalidateHwcGeometry();
-                repaintEverything();
+                updateColorMatrixLocked();
                 return NO_ERROR;
             }
             // This is an experimental interface
@@ -4102,11 +4737,11 @@
                 n = data.readInt32();
                 if (n) {
                     ALOGV("Interceptor enabled");
-                    mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
+                    mInterceptor->enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
                 }
                 else{
                     ALOGV("Interceptor disabled");
-                    mInterceptor.disable();
+                    mInterceptor->disable();
                 }
                 return NO_ERROR;
             }
@@ -4116,15 +4751,14 @@
                 return NO_ERROR;
             }
             case 1022: { // Set saturation boost
-                mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+                Mutex::Autolock _l(mStateLock);
+                mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));
 
-                invalidateHwcGeometry();
-                repaintEverything();
+                updateColorMatrixLocked();
                 return NO_ERROR;
             }
             case 1023: { // Set native mode
-                mForceNativeColorMode = data.readInt32() == 1;
-
+                mDisplayColorSetting = static_cast<DisplayColorSetting>(data.readInt32());
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
@@ -4133,51 +4767,58 @@
                 reply->writeBool(hasWideColorDisplay);
                 return NO_ERROR;
             }
+            case 1025: { // Set layer tracing
+                n = data.readInt32();
+                if (n) {
+                    ALOGD("LayerTracing enabled");
+                    mTracing.enable();
+                    doTracing("tracing.enable");
+                    reply->writeInt32(NO_ERROR);
+                } else {
+                    ALOGD("LayerTracing disabled");
+                    status_t err = mTracing.disable();
+                    reply->writeInt32(err);
+                }
+                return NO_ERROR;
+            }
+            case 1026: { // Get layer tracing status
+                reply->writeBool(mTracing.isEnabled());
+                return NO_ERROR;
+            }
+            // Is a DisplayColorSetting supported?
+            case 1027: {
+                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+                if (!hw) {
+                    return NAME_NOT_FOUND;
+                }
+
+                DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
+                switch (setting) {
+                    case DisplayColorSetting::MANAGED:
+                        reply->writeBool(hasWideColorDisplay);
+                        break;
+                    case DisplayColorSetting::UNMANAGED:
+                        reply->writeBool(true);
+                        break;
+                    case DisplayColorSetting::ENHANCED:
+                        reply->writeBool(hw->hasRenderIntent(RenderIntent::ENHANCE));
+                        break;
+                    default: // vendor display color setting
+                        reply->writeBool(hw->hasRenderIntent(static_cast<RenderIntent>(setting)));
+                        break;
+                }
+                return NO_ERROR;
+            }
         }
     }
     return err;
 }
 
-void SurfaceFlinger::repaintEverythingLocked() {
+void SurfaceFlinger::repaintEverything() {
     android_atomic_or(1, &mRepaintEverything);
     signalTransaction();
 }
 
-void SurfaceFlinger::repaintEverything() {
-    ConditionalLock _l(mStateLock,
-            std::this_thread::get_id() != mMainThreadId);
-    repaintEverythingLocked();
-}
-
-// Checks that the requested width and height are valid and updates them to the display dimensions
-// if they are set to 0
-static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
-                                       Transform::orientation_flags rotation,
-                                       uint32_t* requestedWidth, uint32_t* requestedHeight) {
-    // get screen geometry
-    uint32_t displayWidth = displayDevice->getWidth();
-    uint32_t displayHeight = displayDevice->getHeight();
-
-    if (rotation & Transform::ROT_90) {
-        std::swap(displayWidth, displayHeight);
-    }
-
-    if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
-        ALOGE("size mismatch (%d, %d) > (%d, %d)",
-                *requestedWidth, *requestedHeight, displayWidth, displayHeight);
-        return BAD_VALUE;
-    }
-
-    if (*requestedWidth == 0) {
-        *requestedWidth = displayWidth;
-    }
-    if (*requestedHeight == 0) {
-        *requestedHeight = displayHeight;
-    }
-
-    return NO_ERROR;
-}
-
 // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
 class WindowDisconnector {
 public:
@@ -4191,112 +4832,162 @@
     const int mApi;
 };
 
-static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
-                                uint32_t requestedHeight, bool hasWideColorDisplay,
-                                bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
-    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-
-    int err = 0;
-    err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
-    err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-    err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
-    err |= native_window_set_usage(window, usage);
-
-    if (hasWideColorDisplay) {
-        err |= native_window_set_buffers_data_space(window,
-                                                    renderEngineUsesWideColor
-                                                            ? HAL_DATASPACE_DISPLAY_P3
-                                                            : HAL_DATASPACE_V0_SRGB);
-    }
-
-    if (err != NO_ERROR) {
-        return BAD_VALUE;
-    }
-
-    /* TODO: Once we have the sync framework everywhere this can use
-     * server-side waits on the fence that dequeueBuffer returns.
-     */
-    err = native_window_dequeue_buffer_and_wait(window, outBuffer);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                       Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                       int32_t minLayerZ, int32_t maxLayerZ,
+                                       bool useIdentityTransform,
+                                       ISurfaceComposer::Rotation rotation) {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(display == 0))
-        return BAD_VALUE;
+    if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
 
-    if (CC_UNLIKELY(producer == 0))
-        return BAD_VALUE;
+    const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+    if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
 
-    // if we have secure windows on this display, never allow the screen capture
-    // unless the producer interface is local (i.e.: we can take a screenshot for
-    // ourselves).
-    bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
-
-    // Convert to surfaceflinger's internal rotation type.
-    Transform::orientation_flags rotationFlags;
-    switch (rotation) {
-        case ISurfaceComposer::eRotateNone:
-            rotationFlags = Transform::ROT_0;
-            break;
-        case ISurfaceComposer::eRotate90:
-            rotationFlags = Transform::ROT_90;
-            break;
-        case ISurfaceComposer::eRotate180:
-            rotationFlags = Transform::ROT_180;
-            break;
-        case ISurfaceComposer::eRotate270:
-            rotationFlags = Transform::ROT_270;
-            break;
-        default:
-            rotationFlags = Transform::ROT_0;
-            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
-            break;
+    const Rect& dispScissor = device->getScissor();
+    if (!dispScissor.isEmpty()) {
+        sourceCrop.set(dispScissor);
+        // adb shell screencap will default reqWidth and reqHeight to zeros.
+        if (reqWidth == 0 || reqHeight == 0) {
+            reqWidth = uint32_t(device->getViewport().width());
+            reqHeight = uint32_t(device->getViewport().height());
+        }
     }
 
-    { // Autolock scope
-        Mutex::Autolock lock(mStateLock);
-        sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
-        updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
+    DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+
+    auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+                                    device, minLayerZ, maxLayerZ, std::placeholders::_1);
+    return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+                                       sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                       float frameScale, bool childrenOnly) {
+    ATRACE_CALL();
+
+    class LayerRenderArea : public RenderArea {
+    public:
+        LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
+                        int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
+              : RenderArea(reqHeight, reqWidth, CaptureFill::CLEAR),
+                mLayer(layer),
+                mCrop(crop),
+                mFlinger(flinger),
+                mChildrenOnly(childrenOnly) {}
+        const Transform& getTransform() const override { return mTransform; }
+        Rect getBounds() const override {
+            const Layer::State& layerState(mLayer->getDrawingState());
+            return Rect(layerState.active.w, layerState.active.h);
+        }
+        int getHeight() const override { return mLayer->getDrawingState().active.h; }
+        int getWidth() const override { return mLayer->getDrawingState().active.w; }
+        bool isSecure() const override { return false; }
+        bool needsFiltering() const override { return false; }
+        Rect getSourceCrop() const override {
+            if (mCrop.isEmpty()) {
+                return getBounds();
+            } else {
+                return mCrop;
+            }
+        }
+        class ReparentForDrawing {
+        public:
+            const sp<Layer>& oldParent;
+            const sp<Layer>& newParent;
+
+            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+                  : oldParent(oldParent), newParent(newParent) {
+                oldParent->setChildrenDrawingParent(newParent);
+            }
+            ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+        };
+
+        void render(std::function<void()> drawLayers) override {
+            if (!mChildrenOnly) {
+                mTransform = mLayer->getTransform().inverse();
+                drawLayers();
+            } else {
+                Rect bounds = getBounds();
+                screenshotParentLayer =
+                        new ContainerLayer(mFlinger, nullptr, String8("Screenshot Parent"),
+                                           bounds.getWidth(), bounds.getHeight(), 0);
+
+                ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+                drawLayers();
+            }
+        }
+
+    private:
+        const sp<Layer> mLayer;
+        const Rect mCrop;
+
+        // In the "childrenOnly" case we reparent the children to a screenshot
+        // layer which has no properties set and which does not draw.
+        sp<ContainerLayer> screenshotParentLayer;
+        Transform mTransform;
+
+        SurfaceFlinger* mFlinger;
+        const bool mChildrenOnly;
+    };
+
+    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+    auto parent = layerHandle->owner.promote();
+
+    if (parent == nullptr || parent->isPendingRemoval()) {
+        ALOGE("captureLayers called with a removed parent");
+        return NAME_NOT_FOUND;
     }
 
-    // create a surface (because we're a producer, and we need to
-    // dequeue/queue a buffer)
-    sp<Surface> surface = new Surface(producer, false);
-
-    // Put the screenshot Surface into async mode so that
-    // Layer::headFenceHasSignaled will always return true and we'll latch the
-    // first buffer regardless of whether or not its acquire fence has
-    // signaled. This is needed to avoid a race condition in the rotation
-    // animation. See b/30209608
-    surface->setAsyncMode(true);
-
-    ANativeWindow* window = surface.get();
-
-    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-    if (result != NO_ERROR) {
-        return result;
+    const int uid = IPCThreadState::self()->getCallingUid();
+    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+    if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+        ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+        return PERMISSION_DENIED;
     }
-    WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
 
-    ANativeWindowBuffer* buffer = nullptr;
-    result = getWindowBuffer(window, reqWidth, reqHeight,
-            hasWideColorDisplay && !mForceNativeColorMode,
-            getRenderEngine().usesWideColor(), &buffer);
-    if (result != NO_ERROR) {
-        return result;
+    Rect crop(sourceCrop);
+    if (sourceCrop.width() <= 0) {
+        crop.left = 0;
+        crop.right = parent->getCurrentState().active.w;
     }
 
+    if (sourceCrop.height() <= 0) {
+        crop.top = 0;
+        crop.bottom = parent->getCurrentState().active.h;
+    }
+
+    int32_t reqWidth = crop.width() * frameScale;
+    int32_t reqHeight = crop.height() * frameScale;
+
+    LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
+
+    auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
+        parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->isVisible()) {
+                return;
+            } else if (childrenOnly && layer == parent.get()) {
+                return;
+            }
+            visitor(layer);
+        });
+    };
+    return captureScreenCommon(renderArea, traverseLayers, outBuffer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+                                             TraverseLayersFunction traverseLayers,
+                                             sp<GraphicBuffer>* outBuffer,
+                                             bool useIdentityTransform) {
+    ATRACE_CALL();
+
+    renderArea.updateDimensions(mPrimaryDisplayOrientation);
+
+    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+                                   HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+
     // This mutex protects syncFd and captureResult for communication of the return values from the
     // main thread back to this Binder thread
     std::mutex captureMutex;
@@ -4305,6 +4996,9 @@
     int syncFd = -1;
     std::optional<status_t> captureResult;
 
+    const int uid = IPCThreadState::self()->getCallingUid();
+    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+
     sp<LambdaMessage> message = new LambdaMessage([&]() {
         // If there is a refresh pending, bug out early and tell the binder thread to try again
         // after the refresh.
@@ -4320,10 +5014,10 @@
         int fd = -1;
         {
             Mutex::Autolock _l(mStateLock);
-            sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
-            result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
-                                             minLayerZ, maxLayerZ, useIdentityTransform,
-                                             rotationFlags, isLocalScreenshot, &fd);
+            renderArea.render([&]() {
+                result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+                                                 useIdentityTransform, forSystem, &fd);
+            });
         }
 
         {
@@ -4334,7 +5028,7 @@
         }
     });
 
-    result = postMessageAsync(message);
+    status_t result = postMessageAsync(message);
     if (result == NO_ERROR) {
         captureCondition.wait(captureLock, [&]() { return captureResult; });
         while (*captureResult == EAGAIN) {
@@ -4349,153 +5043,154 @@
     }
 
     if (result == NO_ERROR) {
-        // queueBuffer takes ownership of syncFd
-        result = window->queueBuffer(window, buffer, syncFd);
+        sync_wait(syncFd, -1);
+        close(syncFd);
     }
 
     return result;
 }
 
-
-void SurfaceFlinger::renderScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
-{
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
+                                            TraverseLayersFunction traverseLayers, bool yswap,
+                                            bool useIdentityTransform) {
     ATRACE_CALL();
-    RenderEngine& engine(getRenderEngine());
+
+    auto& engine(getRenderEngine());
 
     // get screen geometry
-    const int32_t hw_w = hw->getWidth();
-    const int32_t hw_h = hw->getHeight();
-    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
-                           static_cast<int32_t>(reqHeight) != hw_h;
+    const auto raWidth = renderArea.getWidth();
+    const auto raHeight = renderArea.getHeight();
+
+    const auto reqWidth = renderArea.getReqWidth();
+    const auto reqHeight = renderArea.getReqHeight();
+    Rect sourceCrop = renderArea.getSourceCrop();
+
+    bool filtering = false;
+    if (mPrimaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+        filtering = static_cast<int32_t>(reqWidth) != raHeight ||
+                static_cast<int32_t>(reqHeight) != raWidth;
+    } else {
+        filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+                static_cast<int32_t>(reqHeight) != raHeight;
+    }
 
     // if a default or invalid sourceCrop is passed in, set reasonable values
-    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
-            !sourceCrop.isValid()) {
+    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
         sourceCrop.setLeftTop(Point(0, 0));
-        sourceCrop.setRightBottom(Point(hw_w, hw_h));
+        sourceCrop.setRightBottom(Point(raWidth, raHeight));
+    } else if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
+        Transform tr;
+        uint32_t flags = 0x00;
+        switch (mPrimaryDisplayOrientation) {
+            case DisplayState::eOrientation90:
+                flags = Transform::ROT_90;
+                break;
+            case DisplayState::eOrientation180:
+                flags = Transform::ROT_180;
+                break;
+            case DisplayState::eOrientation270:
+                flags = Transform::ROT_270;
+                break;
+        }
+        tr.set(flags, raWidth, raHeight);
+        sourceCrop = tr.transform(sourceCrop);
     }
 
     // ensure that sourceCrop is inside screen
     if (sourceCrop.left < 0) {
         ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
     }
-    if (sourceCrop.right > hw_w) {
-        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+    if (sourceCrop.right > raWidth) {
+        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
     }
     if (sourceCrop.top < 0) {
         ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
     }
-    if (sourceCrop.bottom > hw_h) {
-        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+    if (sourceCrop.bottom > raHeight) {
+        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-#ifdef USE_HWC2
-     engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode);
-     engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode());
-#endif
+    // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
+    engine.setOutputDataSpace(Dataspace::SRGB);
+    engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
 
     // make sure to clear all GL error flags
     engine.checkErrors();
 
+    Transform::orientation_flags rotation = renderArea.getRotationFlags();
+    if (mPrimaryDisplayOrientation != DisplayState::eOrientationDefault) {
+        // convert hw orientation into flag presentation
+        // here inverse transform needed
+        uint8_t hw_rot_90  = 0x00;
+        uint8_t hw_flip_hv = 0x00;
+        switch (mPrimaryDisplayOrientation) {
+            case DisplayState::eOrientation90:
+                hw_rot_90 = Transform::ROT_90;
+                hw_flip_hv = Transform::ROT_180;
+                break;
+            case DisplayState::eOrientation180:
+                hw_flip_hv = Transform::ROT_180;
+                break;
+            case DisplayState::eOrientation270:
+                hw_rot_90  = Transform::ROT_90;
+                break;
+        }
+
+        // transform flags operation
+        // 1) flip H V if both have ROT_90 flag
+        // 2) XOR these flags
+        uint8_t rotation_rot_90  = rotation & Transform::ROT_90;
+        uint8_t rotation_flip_hv = rotation & Transform::ROT_180;
+        if (rotation_rot_90 & hw_rot_90) {
+            rotation_flip_hv = (~rotation_flip_hv) & Transform::ROT_180;
+        }
+        rotation = static_cast<Transform::orientation_flags>
+                   ((rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
+    }
+
     // set-up our viewport
-    engine.setViewportAndProjection(
-        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
+    engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
+                                    rotation);
     engine.disableTexturing();
 
+    const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
     // redraw the screen entirely...
-    engine.clearWithColor(0, 0, 0, 1);
+    engine.clearWithColor(0, 0, 0, alpha);
 
-    // We loop through the first level of layers without traversing,
-    // as we need to interpret min/max layer Z in the top level Z space.
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
-            continue;
-        }
-        const Layer::State& state(layer->getDrawingState());
-        if (state.z < minLayerZ || state.z > maxLayerZ) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->isVisible()) {
-                return;
-            }
-            if (filtering) layer->setFiltering(true);
-            layer->draw(hw, useIdentityTransform);
-            if (filtering) layer->setFiltering(false);
-        });
-    }
-
-    hw->setViewportAndProjection();
+    traverseLayers([&](Layer* layer) {
+        if (filtering) layer->setFiltering(true);
+        layer->draw(renderArea, useIdentityTransform);
+        if (filtering) layer->setFiltering(false);
+    });
 }
 
-// A simple RAII class that holds an EGLImage and destroys it either:
-//   a) When the destroy() method is called
-//   b) When the object goes out of scope
-class ImageHolder {
-public:
-    ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
-    ~ImageHolder() { destroy(); }
-
-    void destroy() {
-        if (mImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, mImage);
-            mImage = EGL_NO_IMAGE_KHR;
-        }
-    }
-
-private:
-    const EGLDisplay mDisplay;
-    EGLImageKHR mImage;
-};
-
-status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
-                                                 ANativeWindowBuffer* buffer, Rect sourceCrop,
-                                                 uint32_t reqWidth, uint32_t reqHeight,
-                                                 int32_t minLayerZ, int32_t maxLayerZ,
+status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
+                                                 TraverseLayersFunction traverseLayers,
+                                                 ANativeWindowBuffer* buffer,
                                                  bool useIdentityTransform,
-                                                 Transform::orientation_flags rotation,
-                                                 bool isLocalScreenshot, int* outSyncFd) {
+                                                 bool forSystem,
+                                                 int* outSyncFd) {
     ATRACE_CALL();
 
     bool secureLayerIsVisible = false;
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        const Layer::State& state(layer->getDrawingState());
-        if (!layer->belongsToDisplay(hw->getLayerStack(), false) ||
-                (state.z < minLayerZ || state.z > maxLayerZ)) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
-            secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
-                    layer->isSecure());
-        });
-    }
 
-    if (!isLocalScreenshot && secureLayerIsVisible) {
+    traverseLayers([&](Layer* layer) {
+        secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
+    });
+
+    // We allow the system server to take screenshots of secure layers for
+    // use in situations like the Screen-rotation animation and place
+    // the impetus on WindowManager to not persist them.
+    if (secureLayerIsVisible && !forSystem) {
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
 
-    int syncFd = -1;
-    // create an EGLImage from the buffer so we can later
-    // turn it into a texture
-    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
-            EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
-    if (image == EGL_NO_IMAGE_KHR) {
-        return BAD_VALUE;
-    }
-
-    // This will automatically destroy the image if we return before calling its destroy method
-    ImageHolder imageHolder(mEGLDisplay, image);
-
     // this binds the given EGLImage as a framebuffer for the
     // duration of this scope.
-    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
-    if (imageBond.getStatus() != NO_ERROR) {
-        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+    RE::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+    if (bufferBond.getStatus() != NO_ERROR) {
+        ALOGE("got ANWB binding error while taking screenshot");
         return INVALID_OPERATION;
     }
 
@@ -4503,89 +5198,50 @@
     // via an FBO, which means we didn't have to create
     // an EGLSurface and therefore we're not
     // dependent on the context's EGLConfig.
-    renderScreenImplLocked(
-        hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
-        useIdentityTransform, rotation);
-
-    // Attempt to create a sync khr object that can produce a sync point. If that
-    // isn't available, create a non-dupable sync object in the fallback path and
-    // wait on it directly.
-    EGLSyncKHR sync = EGL_NO_SYNC_KHR;
-    if (!DEBUG_SCREENSHOTS) {
-       sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
-       // native fence fd will not be populated until flush() is done.
-       getRenderEngine().flush();
-    }
-
-    if (sync != EGL_NO_SYNC_KHR) {
-        // get the sync fd
-        syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
-        if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-            ALOGW("captureScreen: failed to dup sync khr object");
-            syncFd = -1;
-        }
-        eglDestroySyncKHR(mEGLDisplay, sync);
-    } else {
-        // fallback path
-        sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-        if (sync != EGL_NO_SYNC_KHR) {
-            EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
-                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
-            EGLint eglErr = eglGetError();
-            if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                ALOGW("captureScreen: fence wait timed out");
-            } else {
-                ALOGW_IF(eglErr != EGL_SUCCESS,
-                        "captureScreen: error waiting on EGL fence: %#x", eglErr);
-            }
-            eglDestroySyncKHR(mEGLDisplay, sync);
-        } else {
-            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
-        }
-    }
-    *outSyncFd = syncFd;
+    renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
 
     if (DEBUG_SCREENSHOTS) {
+        getRenderEngine().finish();
+        *outSyncFd = -1;
+
+        const auto reqWidth = renderArea.getReqWidth();
+        const auto reqHeight = renderArea.getReqHeight();
+
         uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
         getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
-        checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
-                hw, minLayerZ, maxLayerZ);
+        checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
         delete [] pixels;
+    } else {
+        base::unique_fd syncFd = getRenderEngine().flush();
+        if (syncFd < 0) {
+            getRenderEngine().finish();
+        }
+        *outSyncFd = syncFd.release();
     }
 
-    // destroy our image
-    imageHolder.destroy();
-
     return NO_ERROR;
 }
 
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-        const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+                                     TraverseLayersFunction traverseLayers) {
     if (DEBUG_SCREENSHOTS) {
-        for (size_t y=0 ; y<h ; y++) {
-            uint32_t const * p = (uint32_t const *)vaddr + y*s;
-            for (size_t x=0 ; x<w ; x++) {
+        for (size_t y = 0; y < h; y++) {
+            uint32_t const* p = (uint32_t const*)vaddr + y * s;
+            for (size_t x = 0; x < w; x++) {
                 if (p[x] != 0xFF000000) return;
             }
         }
-        ALOGE("*** we just took a black screenshot ***\n"
-                "requested minz=%d, maxz=%d, layerStack=%d",
-                minLayerZ, maxLayerZ, hw->getLayerStack());
+        ALOGE("*** we just took a black screenshot ***");
 
         size_t i = 0;
-        for (const auto& layer : mDrawingState.layersSortedByZ) {
+        traverseLayers([&](Layer* layer) {
             const Layer::State& state(layer->getDrawingState());
-            if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
-                    state.z <= maxLayerZ) {
-                layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
-                            layer->isVisible() ? '+' : '-',
-                            i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, state.alpha);
-                    i++;
-                });
-            }
-        }
+            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
+                  layer->isVisible() ? '+' : '-', i, layer->getName().string(),
+                  layer->getLayerStack(), state.z, layer->isVisible(), state.flags,
+                  static_cast<float>(state.color.a));
+            i++;
+        });
     }
 }
 
@@ -4599,6 +5255,32 @@
     layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
 }
 
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
+                                             int32_t maxLayerZ,
+                                             const LayerVector::Visitor& visitor) {
+    // We loop through the first level of layers without traversing,
+    // as we need to interpret min/max layer Z in the top level Z space.
+    for (const auto& layer : mDrawingState.layersSortedByZ) {
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+            continue;
+        }
+        const Layer::State& state(layer->getDrawingState());
+        // relative layers are traversed in Layer::traverseInZOrder
+        if (state.zOrderRelativeOf != nullptr || state.z < minLayerZ || state.z > maxLayerZ) {
+            continue;
+        }
+        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+                return;
+            }
+            if (!layer->isVisible()) {
+                return;
+            }
+            visitor(layer);
+        });
+    }
+}
+
 }; // namespace android
 
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 99d4a1a..0148ab6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -21,20 +21,19 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <EGL/egl.h>
-
 /*
  * NOTE: Make sure this file doesn't include  anything from <gl/ > or <gl2/ >
  */
 
 #include <cutils/compiler.h>
+#include <cutils/atomic.h>
 
-#include <utils/Atomic.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
+#include <utils/Trace.h>
 
 #include <ui/FenceTime.h>
 #include <ui/PixelFormat.h>
@@ -43,29 +42,32 @@
 #include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+
 #include <gui/OccupancyTracker.h>
 
 #include <hardware/hwcomposer_defs.h>
 
-#include <system/graphics.h>
+#include <serviceutils/PriorityDumper.h>
 
-#include <private/gui/LayerState.h>
+#include <system/graphics.h>
 
 #include "Barrier.h"
 #include "DisplayDevice.h"
 #include "DispSync.h"
+#include "EventThread.h"
 #include "FrameTracker.h"
+#include "LayerStats.h"
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
+#include "SurfaceTracing.h"
 #include "StartPropertySetThread.h"
+#include "TimeStats/TimeStats.h"
+#include "VSyncModulator.h"
 
-#ifdef USE_HWC2
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
-#else
-#include "DisplayHardware/HWComposer_hwc1.h"
-#endif
 
 #include "Effects/Daltonizer.h"
 
@@ -75,21 +77,38 @@
 #include <string>
 #include <thread>
 #include <utility>
+#include "RenderArea.h"
+
+#include <layerproto/LayerProtoHeader.h>
+
+using namespace android::surfaceflinger;
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
 class Client;
+class ColorLayer;
 class DisplayEventConnection;
-class EventThread;
-class Layer;
-class LayerDim;
-class Surface;
-class RenderEngine;
 class EventControlThread;
-class VSyncSource;
+class EventThread;
+class IGraphicBufferConsumer;
+class IGraphicBufferProducer;
 class InjectVSyncSource;
+class Layer;
+class Surface;
+class SurfaceFlingerBE;
+class VSyncSource;
+
+namespace impl {
+class EventThread;
+} // namespace impl
+
+namespace RE {
+class RenderEngine;
+}
+
+typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction;
 
 namespace dvr {
 class VrFlinger;
@@ -101,18 +120,120 @@
     eTransactionNeeded        = 0x01,
     eTraversalNeeded          = 0x02,
     eDisplayTransactionNeeded = 0x04,
-    eTransactionMask          = 0x07
+    eDisplayLayerStackChanged = 0x08,
+    eTransactionMask          = 0x0f,
 };
 
-class SurfaceFlinger : public BnSurfaceComposer,
-                       private IBinder::DeathRecipient,
-#ifdef USE_HWC2
-                       private HWC2::ComposerCallback
-#else
-                       private HWComposer::EventHandler
-#endif
+enum class DisplayColorSetting : int32_t {
+    MANAGED = 0,
+    UNMANAGED = 1,
+    ENHANCED = 2,
+};
+
+// A thin interface to abstract creating instances of Surface (gui/Surface.h) to
+// use as a NativeWindow.
+class NativeWindowSurface {
+public:
+    virtual ~NativeWindowSurface();
+
+    // Gets the NativeWindow to use for the surface.
+    virtual sp<ANativeWindow> getNativeWindow() const = 0;
+
+    // Indicates that the surface should allocate its buffers now.
+    virtual void preallocateBuffers() = 0;
+};
+
+class SurfaceFlingerBE
 {
 public:
+    SurfaceFlingerBE();
+
+    // The current hardware composer interface.
+    //
+    // The following thread safety rules apply when accessing mHwc, either
+    // directly or via getHwComposer():
+    //
+    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
+    //    only when switching into and out of vr. Recreating mHwc must only be
+    //    done on the main thread.
+    //
+    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
+    //    mStateLock.
+    //
+    // 3. When accessing mHwc on a thread other than the main thread, we always
+    //    need to acquire mStateLock. This is because the main thread could be
+    //    in the process of destroying the current mHwc instance.
+    //
+    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
+    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
+    // destroy it, so it's always safe to access mHwc from any thread without
+    // acquiring mStateLock.
+    std::unique_ptr<HWComposer> mHwc;
+
+    const std::string mHwcServiceName; // "default" for real use, something else for testing.
+
+    // constant members (no synchronization needed for access)
+    std::unique_ptr<RE::RenderEngine> mRenderEngine;
+    EGLContext mEGLContext;
+    EGLDisplay mEGLDisplay;
+
+    FenceTimeline mGlCompositionDoneTimeline;
+    FenceTimeline mDisplayTimeline;
+
+    // protected by mCompositorTimingLock;
+    mutable std::mutex mCompositorTimingLock;
+    CompositorTiming mCompositorTiming;
+
+    // Only accessed from the main thread.
+    struct CompositePresentTime {
+        nsecs_t composite { -1 };
+        std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
+    };
+    std::queue<CompositePresentTime> mCompositePresentTimes;
+
+    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+    nsecs_t mFrameBuckets[NUM_BUCKETS];
+    nsecs_t mTotalTime;
+    std::atomic<nsecs_t> mLastSwapTime;
+
+    // Double- vs. triple-buffering stats
+    struct BufferingStats {
+        BufferingStats()
+          : numSegments(0),
+            totalTime(0),
+            twoBufferTime(0),
+            doubleBufferedTime(0),
+            tripleBufferedTime(0) {}
+
+        size_t numSegments;
+        nsecs_t totalTime;
+
+        // "Two buffer" means that a third buffer was never used, whereas
+        // "double-buffered" means that on average the segment only used two
+        // buffers (though it may have used a third for some part of the
+        // segment)
+        nsecs_t twoBufferTime;
+        nsecs_t doubleBufferedTime;
+        nsecs_t tripleBufferedTime;
+    };
+    mutable Mutex mBufferingStatsMutex;
+    std::unordered_map<std::string, BufferingStats> mBufferingStats;
+
+    // The composer sequence id is a monotonically increasing integer that we
+    // use to differentiate callbacks from different hardware composer
+    // instances. Each hardware composer instance gets a different sequence id.
+    int32_t mComposerSequenceId;
+};
+
+
+class SurfaceFlinger : public BnSurfaceComposer,
+                       public PriorityDumper,
+                       private IBinder::DeathRecipient,
+                       private HWC2::ComposerCallback
+{
+public:
+    SurfaceFlingerBE& getBE() { return mBE; }
+    const SurfaceFlingerBE& getBE() const { return mBE; }
 
     // This is the phase offset in nanoseconds of the software vsync event
     // relative to the vsync event reported by HWComposer.  The software vsync
@@ -140,9 +261,6 @@
     // If fences from sync Framework are supported.
     static bool hasSyncFramework;
 
-    // Instruct the Render Engine to use EGL_IMG_context_priority is available.
-    static bool useContextPriority;
-
     // The offset in nanoseconds to use when DispSync timestamps present fence
     // signaling time.
     static int64_t dispSyncPresentTimeOffset;
@@ -172,6 +290,9 @@
         return "SurfaceFlinger";
     }
 
+    struct SkipInitializationTag {};
+    static constexpr SkipInitializationTag SkipInitialization;
+    explicit SurfaceFlinger(SkipInitializationTag) ANDROID_API;
     SurfaceFlinger() ANDROID_API;
 
     // must be called before clients can connect
@@ -192,8 +313,6 @@
 
     // force full composition on all displays
     void repaintEverything();
-    // Can only be called from the main thread or with mStateLock held
-    void repaintEverythingLocked();
 
     // returns the default Display
     sp<const DisplayDevice> getDefaultDisplayDevice() const {
@@ -201,16 +320,16 @@
         return getDefaultDisplayDeviceLocked();
     }
 
+    // Obtains a name from the texture pool, or, if the pool is empty, posts a
+    // synchronous message to the main thread to obtain one on the fly
+    uint32_t getNewTexture();
+
     // utility function to delete a texture on the main thread
     void deleteTextureAsync(uint32_t texture);
 
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
-#ifdef USE_HWC2
     void setVsyncEnabled(int disp, int enabled);
-#else
-    void eventControl(int disp, int event, int enabled);
-#endif
 
     // called on the main thread by MessageQueue when an internal message
     // is received
@@ -221,20 +340,24 @@
     // TODO: this should be made accessible only to HWComposer
     const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
 
-    RenderEngine& getRenderEngine() const {
-        return *mRenderEngine;
-    }
+    RE::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
 
     bool authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
+    int getPrimaryDisplayOrientation() const { return mPrimaryDisplayOrientation; }
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
-    friend class EventThread;
+    friend class impl::EventThread;
     friend class Layer;
+    friend class BufferLayer;
     friend class MonitoredProducer;
 
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
@@ -250,12 +373,16 @@
 
     class State {
     public:
-        explicit State(LayerVector::StateSet set) : stateSet(set) {}
+        explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
         State& operator=(const State& other) {
             // We explicitly don't copy stateSet so that, e.g., mDrawingState
             // always uses the Drawing StateSet.
             layersSortedByZ = other.layersSortedByZ;
             displays = other.displays;
+            colorMatrixChanged = other.colorMatrixChanged;
+            if (colorMatrixChanged) {
+                colorMatrix = other.colorMatrix;
+            }
             return *this;
         }
 
@@ -263,6 +390,9 @@
         LayerVector layersSortedByZ;
         DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
 
+        bool colorMatrixChanged = true;
+        mat4 colorMatrix;
+
         void traverseInZOrder(const LayerVector::Visitor& visitor) const;
         void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
     };
@@ -272,7 +402,7 @@
      */
     virtual status_t onTransact(uint32_t code, const Parcel& data,
         Parcel* reply, uint32_t flags);
-    virtual status_t dump(int fd, const Vector<String16>& args);
+    virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
@@ -291,20 +421,22 @@
             std::vector<FrameEvent>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
-    virtual status_t captureScreen(const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   ISurfaceComposer::Rotation rotation);
+    virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
+                                   const Rect& sourceCrop, float frameScale, bool childrenOnly);
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats);
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
     virtual status_t getDisplayConfigs(const sp<IBinder>& display,
             Vector<DisplayInfo>* configs);
     virtual int getActiveConfig(const sp<IBinder>& display);
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* configs);
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
-    virtual status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+            Vector<ui::ColorMode>* configs);
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
+    virtual status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode);
     virtual void setPowerMode(const sp<IBinder>& display, int mode);
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
     virtual status_t clearAnimationFrameStats();
@@ -313,6 +445,7 @@
             HdrCapabilities* outCapabilities) const;
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
+    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
 
 
     /* ------------------------------------------------------------------------
@@ -328,18 +461,11 @@
     /* ------------------------------------------------------------------------
      * HWC2::ComposerCallback / HWComposer::EventHandler interface
      */
-#ifdef USE_HWC2
     void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
                          int64_t timestamp) override;
     void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
-                           HWC2::Connection connection,
-                           bool primaryDisplay) override;
+                           HWC2::Connection connection) override;
     void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
-#else
-    void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp) override;
-    void onHotplugReceived(HWComposer* composer, int disp, bool connected) override;
-    void onInvalidateReceived(HWComposer* composer) override;
-#endif
 
     /* ------------------------------------------------------------------------
      * Message handling
@@ -356,18 +482,14 @@
     // called on the main thread in response to setActiveConfig()
     void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode);
     // called on the main thread in response to setPowerMode()
-#ifdef USE_HWC2
     void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode,
                               bool stateLockHeld);
-#else
-    void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode);
-#endif
 
     // Called on the main thread in response to setActiveColorMode()
-    void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode);
-
-    // Called on the main thread in response to enableVSyncInjections()
-    void enableVSyncInjectionsInternal(bool enable);
+    void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
+                                    ui::ColorMode colorMode,
+                                    ui::Dataspace dataSpace,
+                                    ui::RenderIntent renderIntent);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -395,26 +517,29 @@
     uint32_t peekTransactionFlags();
     // Can only be called from the main thread or with mStateLock held
     uint32_t setTransactionFlags(uint32_t flags);
+    uint32_t setTransactionFlags(uint32_t flags, VSyncModulator::TransactionStart transactionStart);
     void commitTransaction();
-    uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
+    bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
+    uint32_t setClientStateLocked(const ComposerState& composerState);
     uint32_t setDisplayStateLocked(const DisplayState& s);
+    void setDestroyStateLocked(const ComposerState& composerState);
 
     /* ------------------------------------------------------------------------
      * Layer management
      */
     status_t createLayer(const String8& name, const sp<Client>& client,
             uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-            uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
+            int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
 
-    status_t createNormalLayer(const sp<Client>& client, const String8& name,
+    status_t createBufferLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
             sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
             sp<Layer>* outLayer);
 
-    status_t createDimLayer(const sp<Client>& client, const String8& name,
+    status_t createColorLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
-            sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+            sp<Layer>* outLayer);
 
     String8 getUniqueLayerName(const String8& name);
 
@@ -429,6 +554,7 @@
 
     // remove a layer from SurfaceFlinger immediately
     status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
+    status_t removeLayerLocked(const Mutex&, const sp<Layer>& layer, bool topLevelOnly = false);
 
     // add a layer to SurfaceFlinger
     status_t addClientLayer(const sp<Client>& client,
@@ -443,28 +569,17 @@
 
     void startBootAnim();
 
-    void renderScreenImplLocked(
-            const sp<const DisplayDevice>& hw,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);
-
-#ifdef USE_HWC2
-    status_t captureScreenImplLocked(const sp<const DisplayDevice>& device,
-                                     ANativeWindowBuffer* buffer, Rect sourceCrop,
-                                     uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
-                                     int32_t maxLayerZ, bool useIdentityTransform,
-                                     Transform::orientation_flags rotation, bool isLocalScreenshot,
-                                     int* outSyncFd);
-#else
-    status_t captureScreenImplLocked(
-            const sp<const DisplayDevice>& hw,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform, Transform::orientation_flags rotation,
-            bool isLocalScreenshot);
-#endif
+    void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                                bool yswap, bool useIdentityTransform);
+    status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                                 sp<GraphicBuffer>* outBuffer,
+                                 bool useIdentityTransform);
+    status_t captureScreenImplLocked(const RenderArea& renderArea,
+                                     TraverseLayersFunction traverseLayers,
+                                     ANativeWindowBuffer* buffer, bool useIdentityTransform,
+                                     bool forSystem, int* outSyncFd);
+    void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+                                 int32_t maxLayerZ, const LayerVector::Visitor& visitor);
 
     sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
 
@@ -485,10 +600,6 @@
     // called when starting, or restarting after system_server death
     void initializeDisplays();
 
-    // Create an IBinder for a builtin display and add it to current state
-    void createBuiltinDisplayLocked(DisplayDevice::DisplayType type);
-
-
     sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) const {
       Mutex::Autolock _l(mStateLock);
       return getDisplayDeviceLocked(dpy);
@@ -513,8 +624,6 @@
         return getDisplayDeviceLocked(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
     }
 
-    void createDefaultDisplayDevice();
-
     int32_t getDisplayType(const sp<IBinder>& display) {
         if (!display.get()) return NAME_NOT_FOUND;
         for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
@@ -529,15 +638,11 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
-#ifndef USE_HWC2
-    int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
-#endif
-
     /* ------------------------------------------------------------------------
      * H/W composer
      */
 
-    HWComposer& getHwComposer() const { return *mHwc; }
+    HWComposer& getHwComposer() const { return *getBE().mHwc; }
 
     /* ------------------------------------------------------------------------
      * Compositing
@@ -556,21 +661,27 @@
             nsecs_t compositeToPresentLatency);
     void rebuildLayerStacks();
 
-    // Given a dataSpace, returns the appropriate color_mode to use
-    // to display that dataSpace.
-    android_color_mode pickColorMode(android_dataspace dataSpace) const;
-    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+    ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice,
+                                   ui::Dataspace* outHdrDataSpace) const;
 
-    mat4 computeSaturationMatrix() const;
+    // Returns the appropriate ColorMode, Dataspace and RenderIntent for the
+    // DisplayDevice. The function only returns the supported ColorMode,
+    // Dataspace and RenderIntent.
+    void pickColorMode(const sp<DisplayDevice>& displayDevice,
+                       ui::ColorMode* outMode,
+                       ui::Dataspace* outDataSpace,
+                       ui::RenderIntent* outRenderIntent) const;
 
     void setUpHWComposer();
     void doComposition();
     void doDebugFlashRegions();
+    void doTracing(const char* where);
+    void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
 
     // compose surfaces for display hw. this fails if using GL and the surface
     // has been destroyed and is no longer valid.
-    bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice, const Region& dirty);
+    bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice);
 
     void postFramebuffer();
     void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const;
@@ -578,6 +689,14 @@
     /* ------------------------------------------------------------------------
      * Display management
      */
+    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
+            HWC2::Connection connection) const;
+    sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+                                                    const DisplayDeviceState& state,
+                                                    const sp<DisplaySurface>& dispSurface,
+                                                    const sp<IGraphicBufferProducer>& producer);
+    void processDisplayChangesLocked();
+    void processDisplayHotplugEventsLocked();
 
     /* ------------------------------------------------------------------------
      * VSync
@@ -594,6 +713,16 @@
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
      */
+public:
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) {
+        return doDump(fd, Vector<String16>(), asProto);
+    }
+
+    status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+        return doDump(fd, args, asProto);
+    }
+
+private:
     void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -601,8 +730,7 @@
     bool startDdmConnection();
     void appendSfConfigString(String8& result) const;
     void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-            const sp<const DisplayDevice>& hw,
-            int32_t minLayerZ, int32_t maxLayerZ);
+                         TraverseLayersFunction traverseLayers);
 
     void logFrameStats();
 
@@ -614,12 +742,14 @@
             std::vector<OccupancyTracker::Segment>&& history);
     void dumpBufferingStats(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
+    LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
     }
+    status_t doDump(int fd, const Vector<String16>& args, bool asProto);
 
-#ifdef USE_HWC2
     /* ------------------------------------------------------------------------
      * VrFlinger
      */
@@ -627,7 +757,8 @@
 
     // Check to see if we should handoff to vr flinger.
     void updateVrFlinger();
-#endif
+
+    void updateColorMatrixLocked();
 
     /* ------------------------------------------------------------------------
      * Attributes
@@ -641,7 +772,15 @@
     bool mTransactionPending;
     bool mAnimTransactionPending;
     SortedVector< sp<Layer> > mLayersPendingRemoval;
-    SortedVector< wp<IBinder> > mGraphicBufferProducerList;
+
+    // global color transform states
+    Daltonizer mDaltonizer;
+    float mGlobalSaturationFactor = 1.0f;
+    mat4 mClientColorMatrix;
+
+    // Can't be unordered_set because wp<> isn't hashable
+    std::set<wp<IBinder>> mGraphicBufferProducerList;
+    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved;
@@ -650,58 +789,43 @@
     // access must be protected by mInvalidateLock
     volatile int32_t mRepaintEverything;
 
-    // The current hardware composer interface.
-    //
-    // The following thread safety rules apply when accessing mHwc, either
-    // directly or via getHwComposer():
-    //
-    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
-    //    only when switching into and out of vr. Recreating mHwc must only be
-    //    done on the main thread.
-    //
-    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
-    //    mStateLock.
-    //
-    // 3. When accessing mHwc on a thread other than the main thread, we always
-    //    need to acquire mStateLock. This is because the main thread could be
-    //    in the process of destroying the current mHwc instance.
-    //
-    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
-    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
-    // destroy it, so it's always safe to access mHwc from any thread without
-    // acquiring mStateLock.
-    std::unique_ptr<HWComposer> mHwc;
-
     // constant members (no synchronization needed for access)
-    RenderEngine* mRenderEngine;
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
-    sp<EventThread> mEventThread;
-    sp<EventThread> mSFEventThread;
-    sp<EventThread> mInjectorEventThread;
-    sp<InjectVSyncSource> mVSyncInjector;
-    sp<EventControlThread> mEventControlThread;
-    EGLContext mEGLContext;
-    EGLDisplay mEGLDisplay;
+    std::unique_ptr<EventThread> mEventThread;
+    std::unique_ptr<EventThread> mSFEventThread;
+    std::unique_ptr<EventThread> mInjectorEventThread;
+    std::unique_ptr<VSyncSource> mEventThreadSource;
+    std::unique_ptr<VSyncSource> mSfEventThreadSource;
+    std::unique_ptr<InjectVSyncSource> mVSyncInjector;
+    std::unique_ptr<EventControlThread> mEventControlThread;
     sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
+    VSyncModulator mVsyncModulator;
+
     // Can only accessed from the main thread, these members
     // don't need synchronization
     State mDrawingState{LayerVector::StateSet::Drawing};
     bool mVisibleRegionsDirty;
-#ifndef USE_HWC2
-    bool mHwWorkListDirty;
-#else
     bool mGeometryInvalid;
-#endif
     bool mAnimCompositionPending;
-#ifdef USE_HWC2
     std::vector<sp<Layer>> mLayersWithQueuedFrames;
     sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
     bool mHadClientComposition = false;
-#endif
-    FenceTimeline mGlCompositionDoneTimeline;
-    FenceTimeline mDisplayTimeline;
+
+    enum class BootStage {
+        BOOTLOADER,
+        BOOTANIMATION,
+        FINISHED,
+    };
+    BootStage mBootStage;
+
+    struct HotplugEvent {
+        hwc2_display_t display;
+        HWC2::Connection connection = HWC2::Connection::Invalid;
+    };
+    // protected by mStateLock
+    std::vector<HotplugEvent> mPendingHotplugEvents;
 
     // this may only be written from the main thread with mStateLock held
     // it may be read from other threads with mStateLock held
@@ -716,21 +840,23 @@
     nsecs_t mLastSwapBufferTime;
     volatile nsecs_t mDebugInTransaction;
     nsecs_t mLastTransactionTime;
-    bool mBootFinished;
     bool mForceFullDamage;
-#ifdef USE_HWC2
     bool mPropagateBackpressure = true;
-#endif
-    SurfaceInterceptor mInterceptor;
+    std::unique_ptr<SurfaceInterceptor> mInterceptor =
+            std::make_unique<impl::SurfaceInterceptor>(this);
+    SurfaceTracing mTracing;
+    LayerStats mLayerStats;
+    TimeStats& mTimeStats = TimeStats::getInstance();
     bool mUseHwcVirtualDisplays = false;
 
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
 
     // these are thread safe
-    mutable MessageQueue mEventQueue;
+    mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
     FrameTracker mAnimFrameTracker;
     DispSync mPrimaryDispSync;
+    int mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
 
     // protected by mDestroyedLayerLock;
     mutable Mutex mDestroyedLayerLock;
@@ -741,83 +867,50 @@
     bool mPrimaryHWVsyncEnabled;
     bool mHWVsyncAvailable;
 
-    // protected by mCompositorTimingLock;
-    mutable std::mutex mCompositorTimingLock;
-    CompositorTiming mCompositorTiming;
-
-    // Only accessed from the main thread.
-    struct CompositePresentTime {
-        nsecs_t composite { -1 };
-        std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
-    };
-    std::queue<CompositePresentTime> mCompositePresentTimes;
-
     std::atomic<bool> mRefreshPending{false};
 
+    // We maintain a pool of pre-generated texture names to hand out to avoid
+    // layer creation needing to run on the main thread (which it would
+    // otherwise need to do to access RenderEngine).
+    std::mutex mTexturePoolMutex;
+    uint32_t mTexturePoolSize = 0;
+    std::vector<uint32_t> mTexturePool;
+
     /* ------------------------------------------------------------------------
      * Feature prototyping
      */
 
     bool mInjectVSyncs;
 
-    Daltonizer mDaltonizer;
-#ifndef USE_HWC2
-    bool mDaltonize;
-#endif
-
-    mat4 mPreviousColorMatrix;
-    mat4 mColorMatrix;
-    bool mHasColorMatrix;
-
     // Static screen stats
     bool mHasPoweredOff;
-    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
-    nsecs_t mFrameBuckets[NUM_BUCKETS];
-    nsecs_t mTotalTime;
-    std::atomic<nsecs_t> mLastSwapTime;
 
     size_t mNumLayers;
 
-    // Double- vs. triple-buffering stats
-    struct BufferingStats {
-        BufferingStats()
-          : numSegments(0),
-            totalTime(0),
-            twoBufferTime(0),
-            doubleBufferedTime(0),
-            tripleBufferedTime(0) {}
-
-        size_t numSegments;
-        nsecs_t totalTime;
-
-        // "Two buffer" means that a third buffer was never used, whereas
-        // "double-buffered" means that on average the segment only used two
-        // buffers (though it may have used a third for some part of the
-        // segment)
-        nsecs_t twoBufferTime;
-        nsecs_t doubleBufferedTime;
-        nsecs_t tripleBufferedTime;
-    };
-    mutable Mutex mBufferingStatsMutex;
-    std::unordered_map<std::string, BufferingStats> mBufferingStats;
-
     // Verify that transaction is being called by an approved process:
     // either AID_GRAPHICS or AID_SYSTEM.
     status_t CheckTransactCodeCredentials(uint32_t code);
 
-#ifdef USE_HWC2
     std::unique_ptr<dvr::VrFlinger> mVrFlinger;
     std::atomic<bool> mVrFlingerRequestsDisplay;
     static bool useVrFlinger;
     std::thread::id mMainThreadId;
-    // The composer sequence id is a monotonically increasing integer that we
-    // use to differentiate callbacks from different hardware composer
-    // instances. Each hardware composer instance gets a different sequence id.
-    int32_t mComposerSequenceId;
-#endif
 
-    float mSaturation = 1.0f;
-    bool mForceNativeColorMode = false;
+    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
+    // Applied on Display P3 layers when the render intent is non-colorimetric.
+    mat4 mEnhancedSaturationMatrix;
+
+    using CreateBufferQueueFunction =
+            std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
+                               sp<IGraphicBufferConsumer>* /* outConsumer */,
+                               bool /* consumerIsSurfaceFlinger */)>;
+    CreateBufferQueueFunction mCreateBufferQueue;
+
+    using CreateNativeWindowSurfaceFunction =
+            std::function<std::unique_ptr<NativeWindowSurface>(const sp<IGraphicBufferProducer>&)>;
+    CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+
+    SurfaceFlingerBE mBE;
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
deleted file mode 100644
index abc8fde..0000000
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-
-#include "SurfaceFlingerConsumer.h"
-#include "Layer.h"
-
-#include <private/gui/SyncFeatures.h>
-
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-
-#include <utils/Errors.h>
-#include <utils/NativeHandle.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
-        const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
-        uint64_t maxFrameNumber)
-{
-    ATRACE_CALL();
-    ALOGV("updateTexImage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ALOGE("updateTexImage: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-
-    // Make sure the EGL state is the same as in previous calls.
-    status_t err = checkAndUpdateEglStateLocked();
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    BufferItem item;
-
-    // Acquire the next buffer.
-    // In asynchronous mode the list is guaranteed to be one buffer
-    // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
-            maxFrameNumber);
-    if (err != NO_ERROR) {
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            err = NO_ERROR;
-        } else if (err == BufferQueue::PRESENT_LATER) {
-            // return the error, without logging
-        } else {
-            ALOGE("updateTexImage: acquire failed: %s (%d)",
-                strerror(-err), err);
-        }
-        return err;
-    }
-
-    if (autoRefresh) {
-        *autoRefresh = item.mAutoRefresh;
-    }
-
-    if (queuedBuffer) {
-        *queuedBuffer = item.mQueuedBuffer;
-    }
-
-    // We call the rejecter here, in case the caller has a reason to
-    // not accept this buffer.  This is used by SurfaceFlinger to
-    // reject buffers which have the wrong size
-    int slot = item.mSlot;
-    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
-        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
-        return BUFFER_REJECTED;
-    }
-
-    // Release the previous buffer.
-#ifdef USE_HWC2
-    err = updateAndReleaseLocked(item, &mPendingRelease);
-#else
-    err = updateAndReleaseLocked(item);
-#endif
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
-        // Bind the new buffer to the GL texture.
-        //
-        // Older devices require the "implicit" synchronization provided
-        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
-        // devices will either call this in Layer::onDraw, or (if it's not
-        // a GL-composited layer) not at all.
-        err = bindTextureImageLocked();
-    }
-
-    return err;
-}
-
-status_t SurfaceFlingerConsumer::bindTextureImage()
-{
-    Mutex::Autolock lock(mMutex);
-
-    return bindTextureImageLocked();
-}
-
-status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
-        nsecs_t presentWhen, uint64_t maxFrameNumber) {
-    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
-            maxFrameNumber);
-    if (result == NO_ERROR) {
-        mTransformToDisplayInverse = item->mTransformToDisplayInverse;
-        mSurfaceDamage = item->mSurfaceDamage;
-    }
-    return result;
-}
-
-bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
-    Mutex::Autolock lock(mMutex);
-    return mTransformToDisplayInverse;
-}
-
-const Region& SurfaceFlingerConsumer::getSurfaceDamage() const {
-    return mSurfaceDamage;
-}
-
-sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
-    sp<NativeHandle> stream;
-    mConsumer->getSidebandStream(&stream);
-    return stream;
-}
-
-// We need to determine the time when a buffer acquired now will be
-// displayed.  This can be calculated:
-//   time when previous buffer's actual-present fence was signaled
-//    + current display refresh rate * HWC latency
-//    + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing.  If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it.  We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss.  We want to do it here, not in every app.  A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
-nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
-{
-    // The HWC doesn't currently have a way to report additional latency.
-    // Assume that whatever we submit now will appear right after the flip.
-    // For a smart panel this might be 1.  This is expressed in frames,
-    // rather than time, because we expect to have a constant frame delay
-    // regardless of the refresh rate.
-    const uint32_t hwcLatency = 0;
-
-    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
-
-    // The DispSync time is already adjusted for the difference between
-    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
-    // we don't need to factor that in here.  Pad a little to avoid
-    // weird effects if apps might be requesting times right on the edge.
-    nsecs_t extraPadding = 0;
-    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
-        extraPadding = 1000000;        // 1ms (6% of 60Hz)
-    }
-
-    return nextRefresh + extraPadding;
-}
-
-sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const {
-    Mutex::Autolock lock(mMutex);
-    return ConsumerBase::mPrevFinalReleaseFence;
-}
-
-#ifdef USE_HWC2
-void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
-{
-    if (!mPendingRelease.isPending) {
-        GLConsumer::setReleaseFence(fence);
-        return;
-    }
-    auto currentTexture = mPendingRelease.currentTexture;
-    if (fence->isValid() &&
-            currentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        status_t result = addReleaseFence(currentTexture,
-                mPendingRelease.graphicBuffer, fence);
-        ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the"
-                " fence: %s (%d)", strerror(-result), result);
-    }
-}
-
-bool SurfaceFlingerConsumer::releasePendingBuffer()
-{
-    if (!mPendingRelease.isPending) {
-        ALOGV("Pending buffer already released");
-        return false;
-    }
-    ALOGV("Releasing pending buffer");
-    Mutex::Autolock lock(mMutex);
-    status_t result = releaseBufferLocked(mPendingRelease.currentTexture,
-            mPendingRelease.graphicBuffer, mPendingRelease.display,
-            mPendingRelease.fence);
-    ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)",
-            strerror(-result), result);
-    mPendingRelease = PendingRelease();
-    return true;
-}
-#endif
-
-void SurfaceFlingerConsumer::setContentsChangedListener(
-        const wp<ContentsChangedListener>& listener) {
-    setFrameAvailableListener(listener);
-    Mutex::Autolock lock(mMutex);
-    mContentsChangedListener = listener;
-}
-
-void SurfaceFlingerConsumer::onSidebandStreamChanged() {
-    FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
-    {
-        Mutex::Autolock lock(mFrameAvailableMutex);
-        unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
-    }
-    sp<ContentsChangedListener> listener;
-    {   // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
-        listener = mContentsChangedListener.promote();
-    }
-
-    if (listener != NULL) {
-        listener->onSidebandStreamChanged();
-    }
-}
-
-void SurfaceFlingerConsumer::onDisconnect() {
-    sp<Layer> l = mLayer.promote();
-    if (l.get()) {
-        l->onDisconnect();
-    }
-}
-
-void SurfaceFlingerConsumer::addAndGetFrameTimestamps(
-        const NewFrameEventsEntry* newTimestamps,
-        FrameEventHistoryDelta *outDelta) {
-    sp<Layer> l = mLayer.promote();
-    if (l.get()) {
-        l->addAndGetFrameTimestamps(newTimestamps, outDelta);
-    }
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
deleted file mode 100644
index 1126233..0000000
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 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 ANDROID_SURFACEFLINGERCONSUMER_H
-#define ANDROID_SURFACEFLINGERCONSUMER_H
-
-#include "DispSync.h"
-
-#include <ui/Region.h>
-#include <gui/GLConsumer.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class Layer;
-
-/*
- * This is a thin wrapper around GLConsumer.
- */
-class SurfaceFlingerConsumer : public GLConsumer {
-public:
-    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
-
-    struct ContentsChangedListener: public FrameAvailableListener {
-        virtual void onSidebandStreamChanged() = 0;
-    };
-
-    SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
-            uint32_t tex, Layer* layer)
-        : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
-          mTransformToDisplayInverse(false), mSurfaceDamage(), mLayer(layer)
-    {}
-
-    class BufferRejecter {
-        friend class SurfaceFlingerConsumer;
-        virtual bool reject(const sp<GraphicBuffer>& buf,
-                const BufferItem& item) = 0;
-
-    protected:
-        virtual ~BufferRejecter() { }
-    };
-
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
-            uint64_t maxFrameNumber = 0) override;
-
-    // This version of updateTexImage() takes a functor that may be used to
-    // reject the newly acquired buffer.  Unlike the GLConsumer version,
-    // this does not guarantee that the buffer has been bound to the GL
-    // texture.
-    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
-            bool* autoRefresh, bool* queuedBuffer,
-            uint64_t maxFrameNumber);
-
-    // See GLConsumer::bindTextureImageLocked().
-    status_t bindTextureImage();
-
-    bool getTransformToDisplayInverse() const;
-
-    // must be called from SF main thread
-    const Region& getSurfaceDamage() const;
-
-    // Sets the contents changed listener. This should be used instead of
-    // ConsumerBase::setFrameAvailableListener().
-    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
-
-    sp<NativeHandle> getSidebandStream() const;
-
-    nsecs_t computeExpectedPresent(const DispSync& dispSync);
-
-    sp<Fence> getPrevFinalReleaseFence() const;
-#ifdef USE_HWC2
-    virtual void setReleaseFence(const sp<Fence>& fence) override;
-    bool releasePendingBuffer();
-#endif
-
-    void onDisconnect() override;
-    void addAndGetFrameTimestamps(
-            const NewFrameEventsEntry* newTimestamps,
-            FrameEventHistoryDelta* outDelta) override;
-
-private:
-    virtual void onSidebandStreamChanged();
-
-    wp<ContentsChangedListener> mContentsChangedListener;
-
-    // Indicates this buffer must be transformed by the inverse transform of the screen
-    // it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
-    // This must be set/read from SurfaceFlinger's main thread.
-    bool mTransformToDisplayInverse;
-
-    // The portion of this surface that has changed since the previous frame
-    Region mSurfaceDamage;
-
-#ifdef USE_HWC2
-    // A release that is pending on the receipt of a new release fence from
-    // presentDisplay
-    PendingRelease mPendingRelease;
-#endif
-
-    // The layer for this SurfaceFlingerConsumer
-    const wp<Layer> mLayer;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SURFACEFLINGERCONSUMER_H
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
deleted file mode 100644
index b28fe68..0000000
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ /dev/null
@@ -1,4078 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <math.h>
-#include <stdatomic.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <mutex>
-
-#include <EGL/egl.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-
-#include <ui/DisplayInfo.h>
-#include <ui/DisplayStatInfo.h>
-
-#include <gui/BufferQueue.h>
-#include <gui/GuiConfig.h>
-#include <gui/IDisplayEventConnection.h>
-#include <gui/Surface.h>
-
-#include <ui/GraphicBufferAllocator.h>
-#include <ui/HdrCapabilities.h>
-#include <ui/PixelFormat.h>
-#include <ui/UiConfig.h>
-
-#include <utils/misc.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-#include <utils/StopWatch.h>
-#include <utils/Timers.h>
-#include <utils/Trace.h>
-
-#include <private/android_filesystem_config.h>
-#include <private/gui/SyncFeatures.h>
-
-#include <set>
-
-#include "Client.h"
-#include "clz.h"
-#include "Colorizer.h"
-#include "DdmConnection.h"
-#include "DisplayDevice.h"
-#include "DispSync.h"
-#include "EventControlThread.h"
-#include "EventThread.h"
-#include "Layer.h"
-#include "LayerVector.h"
-#include "LayerDim.h"
-#include "MonitoredProducer.h"
-#include "SurfaceFlinger.h"
-
-#include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/VirtualDisplaySurface.h"
-
-#include "Effects/Daltonizer.h"
-
-#include "RenderEngine/RenderEngine.h"
-#include <cutils/compiler.h>
-
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
-#define DISPLAY_COUNT       1
-
-/*
- * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all
- * black pixels.
- */
-#define DEBUG_SCREENSHOTS   false
-
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-
-const String16 sHardwareTest("android.permission.HARDWARE_TEST");
-const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
-const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
-const String16 sDump("android.permission.DUMP");
-
-// ---------------------------------------------------------------------------
-int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
-int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
-bool SurfaceFlinger::useContextPriority;
-int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
-bool SurfaceFlinger::useHwcForRgbToYuv;
-uint64_t SurfaceFlinger::maxVirtualDisplaySize;
-bool SurfaceFlinger::hasSyncFramework;
-int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-
-SurfaceFlinger::SurfaceFlinger()
-    :   BnSurfaceComposer(),
-        mTransactionFlags(0),
-        mTransactionPending(false),
-        mAnimTransactionPending(false),
-        mLayersRemoved(false),
-        mLayersAdded(false),
-        mRepaintEverything(0),
-        mRenderEngine(NULL),
-        mBootTime(systemTime()),
-        mVisibleRegionsDirty(false),
-        mHwWorkListDirty(false),
-        mAnimCompositionPending(false),
-        mDebugRegion(0),
-        mDebugDDMS(0),
-        mDebugDisableHWC(0),
-        mDebugDisableTransformHint(0),
-        mDebugInSwapBuffers(0),
-        mLastSwapBufferTime(0),
-        mDebugInTransaction(0),
-        mLastTransactionTime(0),
-        mBootFinished(false),
-        mForceFullDamage(false),
-        mInterceptor(this),
-        mPrimaryDispSync("PrimaryDispSync"),
-        mPrimaryHWVsyncEnabled(false),
-        mHWVsyncAvailable(false),
-        mDaltonize(false),
-        mHasColorMatrix(false),
-        mHasPoweredOff(false),
-        mFrameBuckets(),
-        mTotalTime(0),
-        mLastSwapTime(0),
-        mNumLayers(0)
-{
-    ALOGI("SurfaceFlinger is starting");
-
-    vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
-
-    sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
-
-    maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
-
-    hasSyncFramework = getBool< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::hasSyncFramework>(true);
-
-    useContextPriority = getBool< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::useContextPriority>(false);
-
-    dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
-
-    useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
-
-    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
-
-    char value[PROPERTY_VALUE_MAX];
-
-    property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
-    mGpuToCpuSupported = !atoi(value);
-
-    property_get("debug.sf.showupdates", value, "0");
-    mDebugRegion = atoi(value);
-
-    property_get("debug.sf.ddms", value, "0");
-    mDebugDDMS = atoi(value);
-    if (mDebugDDMS) {
-        if (!startDdmConnection()) {
-            // start failed, and DDMS debugging not enabled
-            mDebugDDMS = 0;
-        }
-    }
-    ALOGI_IF(mDebugRegion, "showupdates enabled");
-    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
-
-    property_get("debug.sf.enable_hwc_vds", value, "0");
-    mUseHwcVirtualDisplays = atoi(value);
-    ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
-
-    property_get("ro.sf.disable_triple_buffer", value, "1");
-    mLayerTripleBufferingDisabled = atoi(value);
-    ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
-}
-
-void SurfaceFlinger::onFirstRef()
-{
-    mEventQueue.init(this);
-}
-
-SurfaceFlinger::~SurfaceFlinger()
-{
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglTerminate(display);
-}
-
-void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
-{
-    // the window manager died on us. prepare its eulogy.
-
-    // restore initial conditions (default device unblank, etc)
-    initializeDisplays();
-
-    // restart the boot-animation
-    startBootAnim();
-}
-
-static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
-    status_t err = client->initCheck();
-    if (err == NO_ERROR) {
-        return client;
-    }
-    return nullptr;
-}
-
-sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
-    return initClient(new Client(this));
-}
-
-sp<ISurfaceComposerClient> SurfaceFlinger::createScopedConnection(
-        const sp<IGraphicBufferProducer>& gbp) {
-    if (authenticateSurfaceTexture(gbp) == false) {
-        return nullptr;
-    }
-    const auto& layer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
-    if (layer == nullptr) {
-        return nullptr;
-    }
-
-   return initClient(new Client(this, layer));
-}
-
-sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
-        bool secure)
-{
-    class DisplayToken : public BBinder {
-        sp<SurfaceFlinger> flinger;
-        virtual ~DisplayToken() {
-             // no more references, this display must be terminated
-             Mutex::Autolock _l(flinger->mStateLock);
-             flinger->mCurrentState.displays.removeItem(this);
-             flinger->setTransactionFlags(eDisplayTransactionNeeded);
-         }
-     public:
-        explicit DisplayToken(const sp<SurfaceFlinger>& flinger)
-            : flinger(flinger) {
-        }
-    };
-
-    sp<BBinder> token = new DisplayToken(this);
-
-    Mutex::Autolock _l(mStateLock);
-    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
-    info.displayName = displayName;
-    mCurrentState.displays.add(token, info);
-    mInterceptor.saveDisplayCreation(info);
-    return token;
-}
-
-void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
-    Mutex::Autolock _l(mStateLock);
-
-    ssize_t idx = mCurrentState.displays.indexOfKey(display);
-    if (idx < 0) {
-        ALOGW("destroyDisplay: invalid display token");
-        return;
-    }
-
-    const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-    if (!info.isVirtualDisplay()) {
-        ALOGE("destroyDisplay called for non-virtual display");
-        return;
-    }
-    mInterceptor.saveDisplayDeletion(info.displayId);
-    mCurrentState.displays.removeItemsAt(idx);
-    setTransactionFlags(eDisplayTransactionNeeded);
-}
-
-void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
-    ALOGW_IF(mBuiltinDisplays[type],
-            "Overwriting display token for display type %d", type);
-    mBuiltinDisplays[type] = new BBinder();
-    // All non-virtual displays are currently considered secure.
-    DisplayDeviceState info(type, true);
-    mCurrentState.displays.add(mBuiltinDisplays[type], info);
-    mInterceptor.saveDisplayCreation(info);
-}
-
-sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
-    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
-        return NULL;
-    }
-    return mBuiltinDisplays[id];
-}
-
-void SurfaceFlinger::bootFinished()
-{
-    if (mStartPropertySetThread->join() != NO_ERROR) {
-        ALOGE("Join StartPropertySetThread failed!");
-    }
-    const nsecs_t now = systemTime();
-    const nsecs_t duration = now - mBootTime;
-    ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
-    mBootFinished = true;
-
-    // wait patiently for the window manager death
-    const String16 name("window");
-    sp<IBinder> window(defaultServiceManager()->getService(name));
-    if (window != 0) {
-        window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
-    }
-
-    // stop boot animation
-    // formerly we would just kill the process, but we now ask it to exit so it
-    // can choose where to stop the animation.
-    property_set("service.bootanim.exit", "1");
-
-    const int LOGTAG_SF_STOP_BOOTANIM = 60110;
-    LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
-                   ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-}
-
-void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
-    class MessageDestroyGLTexture : public MessageBase {
-        RenderEngine& engine;
-        uint32_t texture;
-    public:
-        MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
-            : engine(engine), texture(texture) {
-        }
-        virtual bool handler() {
-            engine.deleteTextures(1, &texture);
-            return true;
-        }
-    };
-    postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
-}
-
-class DispSyncSource : public VSyncSource, private DispSync::Callback {
-public:
-    DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
-        const char* name) :
-            mName(name),
-            mValue(0),
-            mTraceVsync(traceVsync),
-            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
-            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
-            mDispSync(dispSync),
-            mCallbackMutex(),
-            mCallback(),
-            mVsyncMutex(),
-            mPhaseOffset(phaseOffset),
-            mEnabled(false) {}
-
-    virtual ~DispSyncSource() {}
-
-    virtual void setVSyncEnabled(bool enable) {
-        Mutex::Autolock lock(mVsyncMutex);
-        if (enable) {
-            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
-                    static_cast<DispSync::Callback*>(this));
-            if (err != NO_ERROR) {
-                ALOGE("error registering vsync callback: %s (%d)",
-                        strerror(-err), err);
-            }
-            //ATRACE_INT(mVsyncOnLabel.string(), 1);
-        } else {
-            status_t err = mDispSync->removeEventListener(
-                    static_cast<DispSync::Callback*>(this));
-            if (err != NO_ERROR) {
-                ALOGE("error unregistering vsync callback: %s (%d)",
-                        strerror(-err), err);
-            }
-            //ATRACE_INT(mVsyncOnLabel.string(), 0);
-        }
-        mEnabled = enable;
-    }
-
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
-        Mutex::Autolock lock(mCallbackMutex);
-        mCallback = callback;
-    }
-
-    virtual void setPhaseOffset(nsecs_t phaseOffset) {
-        Mutex::Autolock lock(mVsyncMutex);
-
-        // Normalize phaseOffset to [0, period)
-        auto period = mDispSync->getPeriod();
-        phaseOffset %= period;
-        if (phaseOffset < 0) {
-            // If we're here, then phaseOffset is in (-period, 0). After this
-            // operation, it will be in (0, period)
-            phaseOffset += period;
-        }
-        mPhaseOffset = phaseOffset;
-
-        // If we're not enabled, we don't need to mess with the listeners
-        if (!mEnabled) {
-            return;
-        }
-
-        // Remove the listener with the old offset
-        status_t err = mDispSync->removeEventListener(
-                static_cast<DispSync::Callback*>(this));
-        if (err != NO_ERROR) {
-            ALOGE("error unregistering vsync callback: %s (%d)",
-                    strerror(-err), err);
-        }
-
-        // Add a listener with the new offset
-        err = mDispSync->addEventListener(mName, mPhaseOffset,
-                static_cast<DispSync::Callback*>(this));
-        if (err != NO_ERROR) {
-            ALOGE("error registering vsync callback: %s (%d)",
-                    strerror(-err), err);
-        }
-    }
-
-private:
-    virtual void onDispSyncEvent(nsecs_t when) {
-        sp<VSyncSource::Callback> callback;
-        {
-            Mutex::Autolock lock(mCallbackMutex);
-            callback = mCallback;
-
-            if (mTraceVsync) {
-                mValue = (mValue + 1) % 2;
-                ATRACE_INT(mVsyncEventLabel.string(), mValue);
-            }
-        }
-
-        if (callback != NULL) {
-            callback->onVSyncEvent(when);
-        }
-    }
-
-    const char* const mName;
-
-    int mValue;
-
-    const bool mTraceVsync;
-    const String8 mVsyncOnLabel;
-    const String8 mVsyncEventLabel;
-
-    DispSync* mDispSync;
-
-    Mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
-
-    Mutex mVsyncMutex; // Protects the following
-    nsecs_t mPhaseOffset;
-    bool mEnabled;
-};
-
-class InjectVSyncSource : public VSyncSource {
-public:
-    InjectVSyncSource() {}
-
-    virtual ~InjectVSyncSource() {}
-
-    virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
-        std::lock_guard<std::mutex> lock(mCallbackMutex);
-        mCallback = callback;
-    }
-
-    virtual void onInjectSyncEvent(nsecs_t when) {
-        std::lock_guard<std::mutex> lock(mCallbackMutex);
-        mCallback->onVSyncEvent(when);
-    }
-
-    virtual void setVSyncEnabled(bool) {}
-    virtual void setPhaseOffset(nsecs_t) {}
-
-private:
-    std::mutex mCallbackMutex; // Protects the following
-    sp<VSyncSource::Callback> mCallback;
-};
-
-// Do not call property_set on main thread which will be blocked by init
-// Use StartPropertySetThread instead.
-void SurfaceFlinger::init() {
-    ALOGI(  "SurfaceFlinger's main thread ready to run. "
-            "Initializing graphics H/W...");
-
-    Mutex::Autolock _l(mStateLock);
-
-    // initialize EGL for the default display
-    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(mEGLDisplay, NULL, NULL);
-
-    // start the EventThread
-    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            vsyncPhaseOffsetNs, true, "app");
-    mEventThread = new EventThread(vsyncSrc, *this, false);
-    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            sfVsyncPhaseOffsetNs, true, "sf");
-    mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
-    mEventQueue.setEventThread(mSFEventThread);
-
-    // set EventThread and SFEventThread to SCHED_FIFO to minimize jitter
-    struct sched_param param = {0};
-    param.sched_priority = 2;
-    if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
-    }
-    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for EventThread");
-    }
-
-    // Initialize the H/W composer object.  There may or may not be an
-    // actual hardware composer underneath.
-    mHwc.reset(new HWComposer(this,
-            *static_cast<HWComposer::EventHandler *>(this)));
-
-    // get a RenderEngine for the given display / config (can't fail)
-    mRenderEngine = RenderEngine::create(mEGLDisplay,
-            mHwc->getVisualID(), 0);
-
-    // retrieve the EGL context that was selected/created
-    mEGLContext = mRenderEngine->getEGLContext();
-
-    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
-            "couldn't create EGLContext");
-
-    // initialize our non-virtual displays
-    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
-        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
-        // set-up the displays that are already connected
-        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
-            // All non-virtual displays are currently considered secure.
-            bool isSecure = true;
-            createBuiltinDisplayLocked(type);
-            wp<IBinder> token = mBuiltinDisplays[i];
-
-            sp<IGraphicBufferProducer> producer;
-            sp<IGraphicBufferConsumer> consumer;
-            BufferQueue::createBufferQueue(&producer, &consumer);
-
-            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
-                    consumer);
-            int32_t hwcId = allocateHwcDisplayId(type);
-            sp<DisplayDevice> hw = new DisplayDevice(this,
-                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
-                    fbs, producer,
-                    mRenderEngine->getEGLConfig(), false);
-            if (i > DisplayDevice::DISPLAY_PRIMARY) {
-                // FIXME: currently we don't get blank/unblank requests
-                // for displays other than the main display, so we always
-                // assume a connected display is unblanked.
-                ALOGD("marking display %zu as acquired/unblanked", i);
-                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
-            }
-            mDisplays.add(token, hw);
-        }
-    }
-
-    // make the GLContext current so that we can create textures when creating Layers
-    // (which may happens before we render something)
-    getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext);
-
-    mEventControlThread = new EventControlThread(this);
-    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
-
-    // set a fake vsync period if there is no HWComposer
-    if (mHwc->initCheck() != NO_ERROR) {
-        mPrimaryDispSync.setPeriod(16666667);
-    }
-
-    // initialize our drawing state
-    mDrawingState = mCurrentState;
-
-    // set initial conditions (e.g. unblank default device)
-    initializeDisplays();
-
-    mRenderEngine->primeCache();
-
-    // Inform native graphics APIs that the present timestamp is NOT supported:
-    mStartPropertySetThread = new StartPropertySetThread(false);
-    if (mStartPropertySetThread->Start() != NO_ERROR) {
-        ALOGE("Run StartPropertySetThread failed!");
-    }
-
-    ALOGV("Done initializing");
-}
-
-int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
-    return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
-            type : mHwc->allocateDisplayId();
-}
-
-void SurfaceFlinger::startBootAnim() {
-    // Start boot animation service by setting a property mailbox
-    // if property setting thread is already running, Start() will be just a NOP
-    mStartPropertySetThread->Start();
-    // Wait until property was set
-    if (mStartPropertySetThread->join() != NO_ERROR) {
-        ALOGE("Join StartPropertySetThread failed!");
-    }
-}
-
-size_t SurfaceFlinger::getMaxTextureSize() const {
-    return mRenderEngine->getMaxTextureSize();
-}
-
-size_t SurfaceFlinger::getMaxViewportDims() const {
-    return mRenderEngine->getMaxViewportDims();
-}
-
-// ----------------------------------------------------------------------------
-
-bool SurfaceFlinger::authenticateSurfaceTexture(
-        const sp<IGraphicBufferProducer>& bufferProducer) const {
-    Mutex::Autolock _l(mStateLock);
-    return authenticateSurfaceTextureLocked(bufferProducer);
-}
-
-bool SurfaceFlinger::authenticateSurfaceTextureLocked(
-        const sp<IGraphicBufferProducer>& bufferProducer) const {
-    sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
-    return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
-}
-
-status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<FrameEvent>* outSupported) const {
-    *outSupported = {
-        FrameEvent::REQUESTED_PRESENT,
-        FrameEvent::ACQUIRE,
-        FrameEvent::LATCH,
-        FrameEvent::FIRST_REFRESH_START,
-        FrameEvent::LAST_REFRESH_START,
-        FrameEvent::GPU_COMPOSITION_DONE,
-        FrameEvent::DEQUEUE_READY,
-        FrameEvent::RELEASE,
-    };
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
-        Vector<DisplayInfo>* configs) {
-    if ((configs == NULL) || (display.get() == NULL)) {
-        return BAD_VALUE;
-    }
-
-    int32_t type = getDisplayType(display);
-    if (type < 0) return type;
-
-    // TODO: Not sure if display density should handled by SF any longer
-    class Density {
-        static int getDensityFromProperty(char const* propName) {
-            char property[PROPERTY_VALUE_MAX];
-            int density = 0;
-            if (property_get(propName, property, NULL) > 0) {
-                density = atoi(property);
-            }
-            return density;
-        }
-    public:
-        static int getEmuDensity() {
-            return getDensityFromProperty("qemu.sf.lcd_density"); }
-        static int getBuildDensity()  {
-            return getDensityFromProperty("ro.sf.lcd_density"); }
-    };
-
-    configs->clear();
-
-    const Vector<HWComposer::DisplayConfig>& hwConfigs =
-            getHwComposer().getConfigs(type);
-    for (size_t c = 0; c < hwConfigs.size(); ++c) {
-        const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
-        DisplayInfo info = DisplayInfo();
-
-        float xdpi = hwConfig.xdpi;
-        float ydpi = hwConfig.ydpi;
-
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
-            // The density of the device is provided by a build property
-            float density = Density::getBuildDensity() / 160.0f;
-            if (density == 0) {
-                // the build doesn't provide a density -- this is wrong!
-                // use xdpi instead
-                ALOGE("ro.sf.lcd_density must be defined as a build property");
-                density = xdpi / 160.0f;
-            }
-            if (Density::getEmuDensity()) {
-                // if "qemu.sf.lcd_density" is specified, it overrides everything
-                xdpi = ydpi = density = Density::getEmuDensity();
-                density /= 160.0f;
-            }
-            info.density = density;
-
-            // TODO: this needs to go away (currently needed only by webkit)
-            sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-            info.orientation = hw->getOrientation();
-        } else {
-            // TODO: where should this value come from?
-            static const int TV_DENSITY = 213;
-            info.density = TV_DENSITY / 160.0f;
-            info.orientation = 0;
-        }
-
-        info.w = hwConfig.width;
-        info.h = hwConfig.height;
-        info.xdpi = xdpi;
-        info.ydpi = ydpi;
-        info.fps = float(1e9 / hwConfig.refresh);
-        info.appVsyncOffset = vsyncPhaseOffsetNs;
-
-        // This is how far in advance a buffer must be queued for
-        // presentation at a given time.  If you want a buffer to appear
-        // on the screen at time N, you must submit the buffer before
-        // (N - presentationDeadline).
-        //
-        // Normally it's one full refresh period (to give SF a chance to
-        // latch the buffer), but this can be reduced by configuring a
-        // DispSync offset.  Any additional delays introduced by the hardware
-        // composer or panel must be accounted for here.
-        //
-        // We add an additional 1ms to allow for processing time and
-        // differences between the ideal and actual refresh rate.
-        info.presentationDeadline =
-                hwConfig.refresh - sfVsyncPhaseOffsetNs + 1000000;
-
-        // All non-virtual displays are currently considered secure.
-        info.secure = true;
-
-        configs->push_back(info);
-    }
-
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
-        DisplayStatInfo* stats) {
-    if (stats == NULL) {
-        return BAD_VALUE;
-    }
-
-    // FIXME for now we always return stats for the primary display
-    memset(stats, 0, sizeof(*stats));
-    stats->vsyncTime   = mPrimaryDispSync.computeNextRefresh(0);
-    stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
-    return NO_ERROR;
-}
-
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
-    sp<const DisplayDevice> device(getDisplayDevice(display));
-    if (device != NULL) {
-        return device->getActiveConfig();
-    }
-    return BAD_VALUE;
-}
-
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
-    ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
-          this);
-    int32_t type = hw->getDisplayType();
-    int currentMode = hw->getActiveConfig();
-
-    if (mode == currentMode) {
-        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
-        return;
-    }
-
-    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        ALOGW("Trying to set config for virtual display");
-        return;
-    }
-
-    hw->setActiveConfig(mode);
-    getHwComposer().setActiveConfig(type, mode);
-}
-
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
-    class MessageSetActiveConfig: public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-        int mMode;
-    public:
-        MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
-                               int mode) :
-            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
-        virtual bool handler() {
-            Vector<DisplayInfo> configs;
-            mFlinger.getDisplayConfigs(mDisplay, &configs);
-            if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
-                ALOGE("Attempt to set active config = %d for display with %zu configs",
-                        mMode, configs.size());
-            }
-            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == NULL) {
-                ALOGE("Attempt to set active config = %d for null display %p",
-                        mMode, mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set active config = %d for virtual display",
-                        mMode);
-            } else {
-                mFlinger.setActiveConfigInternal(hw, mMode);
-            }
-            return true;
-        }
-    };
-    sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
-    postMessageSync(msg);
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
-    if (outColorModes == nullptr || display.get() == nullptr) {
-        return BAD_VALUE;
-    }
-
-    int32_t type = getDisplayType(display);
-    if (type < 0) return type;
-
-    std::set<android_color_mode_t> colorModes;
-    for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) {
-        colorModes.insert(hwConfig.colorMode);
-    }
-
-    outColorModes->clear();
-    std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes));
-
-    return NO_ERROR;
-}
-
-android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
-    if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE);
-
-    int32_t type = getDisplayType(display);
-    if (type < 0) return static_cast<android_color_mode_t>(type);
-
-    return getHwComposer().getColorMode(type);
-}
-
-status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
-    if (display.get() == nullptr || colorMode < 0) {
-        return BAD_VALUE;
-    }
-
-    int32_t type = getDisplayType(display);
-    if (type < 0) return type;
-    const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type);
-    HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)];
-    desiredConfig.colorMode = colorMode;
-    for (size_t c = 0; c < hwConfigs.size(); ++c) {
-        const HWComposer::DisplayConfig config = hwConfigs[c];
-        if (config == desiredConfig) {
-            return setActiveConfig(display, c);
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t SurfaceFlinger::clearAnimationFrameStats() {
-    Mutex::Autolock _l(mStateLock);
-    mAnimFrameTracker.clearStats();
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
-    Mutex::Autolock _l(mStateLock);
-    mAnimFrameTracker.getStats(outStats);
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/,
-        HdrCapabilities* outCapabilities) const {
-    // HWC1 does not provide HDR capabilities
-    *outCapabilities = HdrCapabilities();
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    if (enable == mInjectVSyncs) {
-        return NO_ERROR;
-    }
-
-    if (enable) {
-        mInjectVSyncs = enable;
-        ALOGV("VSync Injections enabled");
-        if (mVSyncInjector.get() == nullptr) {
-            mVSyncInjector = new InjectVSyncSource();
-            mInjectorEventThread = new EventThread(mVSyncInjector, *this, false);
-        }
-        mEventQueue.setEventThread(mInjectorEventThread);
-    } else {
-        mInjectVSyncs = enable;
-        ALOGV("VSync Injections disabled");
-        mEventQueue.setEventThread(mSFEventThread);
-        mVSyncInjector.clear();
-    }
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::injectVSync(nsecs_t when) {
-    if (!mInjectVSyncs) {
-        ALOGE("VSync Injections not enabled");
-        return BAD_VALUE;
-    }
-    if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) {
-        ALOGV("Injecting VSync inside SurfaceFlinger");
-        mVSyncInjector->onInjectSyncEvent(when);
-    }
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
-        ISurfaceComposer::VsyncSource vsyncSource) {
-    if (vsyncSource == eVsyncSourceSurfaceFlinger) {
-        return mSFEventThread->createEventConnection();
-    } else {
-        return mEventThread->createEventConnection();
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-void SurfaceFlinger::waitForEvent() {
-    mEventQueue.waitMessage();
-}
-
-void SurfaceFlinger::signalTransaction() {
-    mEventQueue.invalidate();
-}
-
-void SurfaceFlinger::signalLayerUpdate() {
-    mEventQueue.invalidate();
-}
-
-void SurfaceFlinger::signalRefresh() {
-    mEventQueue.refresh();
-}
-
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t /* flags */) {
-    return mEventQueue.postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t /* flags */) {
-    status_t res = mEventQueue.postMessage(msg, reltime);
-    if (res == NO_ERROR) {
-        msg->wait();
-    }
-    return res;
-}
-
-void SurfaceFlinger::run() {
-    do {
-        waitForEvent();
-    } while (true);
-}
-
-void SurfaceFlinger::enableHardwareVsync() {
-    Mutex::Autolock _l(mHWVsyncLock);
-    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
-        mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
-        mEventControlThread->setVsyncEnabled(true);
-        mPrimaryHWVsyncEnabled = true;
-    }
-}
-
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
-    Mutex::Autolock _l(mHWVsyncLock);
-
-    if (makeAvailable) {
-        mHWVsyncAvailable = true;
-    } else if (!mHWVsyncAvailable) {
-        // Hardware vsync is not currently available, so abort the resync
-        // attempt for now
-        return;
-    }
-
-    const nsecs_t period =
-            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-
-    mPrimaryDispSync.reset();
-    mPrimaryDispSync.setPeriod(period);
-
-    if (!mPrimaryHWVsyncEnabled) {
-        mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
-        mEventControlThread->setVsyncEnabled(true);
-        mPrimaryHWVsyncEnabled = true;
-    }
-}
-
-void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
-    Mutex::Autolock _l(mHWVsyncLock);
-    if (mPrimaryHWVsyncEnabled) {
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
-        mEventControlThread->setVsyncEnabled(false);
-        mPrimaryDispSync.endResync();
-        mPrimaryHWVsyncEnabled = false;
-    }
-    if (makeUnavailable) {
-        mHWVsyncAvailable = false;
-    }
-}
-
-void SurfaceFlinger::resyncWithRateLimit() {
-    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
-        resyncToHardwareVsync(false);
-    }
-}
-
-void SurfaceFlinger::onVSyncReceived(HWComposer* /*composer*/, int type,
-                                     nsecs_t timestamp) {
-    bool needsHwVsync = false;
-
-    { // Scope for the lock
-        Mutex::Autolock _l(mHWVsyncLock);
-        if (type == 0 && mPrimaryHWVsyncEnabled) {
-            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
-        }
-    }
-
-    if (needsHwVsync) {
-        enableHardwareVsync();
-    } else {
-        disableHardwareVsync(false);
-    }
-}
-
-void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    *compositorTiming = mCompositorTiming;
-}
-
-void SurfaceFlinger::onHotplugReceived(HWComposer* /*composer*/, int type, bool connected) {
-    if (mEventThread == NULL) {
-        // This is a temporary workaround for b/7145521.  A non-null pointer
-        // does not mean EventThread has finished initializing, so this
-        // is not a correct fix.
-        ALOGW("WARNING: EventThread not started, ignoring hotplug");
-        return;
-    }
-
-    if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        Mutex::Autolock _l(mStateLock);
-        if (connected) {
-            createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
-        } else {
-            mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
-            mBuiltinDisplays[type].clear();
-        }
-        setTransactionFlags(eDisplayTransactionNeeded);
-
-        // Defer EventThread notification until SF has updated mDisplays.
-    }
-}
-
-void SurfaceFlinger::onInvalidateReceived(HWComposer* /*composer*/) {
-    repaintEverything();
-}
-
-void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
-    ATRACE_CALL();
-    getHwComposer().eventControl(disp, event, enabled);
-}
-
-void SurfaceFlinger::onMessageReceived(int32_t what) {
-    ATRACE_CALL();
-    switch (what) {
-        case MessageQueue::INVALIDATE: {
-            bool refreshNeeded = handleMessageTransaction();
-            refreshNeeded |= handleMessageInvalidate();
-            refreshNeeded |= mRepaintEverything;
-            if (refreshNeeded) {
-                // Signal a refresh if a transaction modified the window state,
-                // a new buffer was latched, or if HWC has requested a full
-                // repaint
-                signalRefresh();
-            }
-            break;
-        }
-        case MessageQueue::REFRESH: {
-            handleMessageRefresh();
-            break;
-        }
-    }
-}
-
-bool SurfaceFlinger::handleMessageTransaction() {
-    uint32_t transactionFlags = peekTransactionFlags();
-    if (transactionFlags) {
-        handleTransaction(transactionFlags);
-        return true;
-    }
-    return false;
-}
-
-bool SurfaceFlinger::handleMessageInvalidate() {
-    ATRACE_CALL();
-    return handlePageFlip();
-}
-
-void SurfaceFlinger::handleMessageRefresh() {
-    ATRACE_CALL();
-
-    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
-    preComposition(refreshStartTime);
-    rebuildLayerStacks();
-    setUpHWComposer();
-    doDebugFlashRegions();
-    doComposition();
-    postComposition(refreshStartTime);
-}
-
-void SurfaceFlinger::doDebugFlashRegions()
-{
-    // is debugging enabled
-    if (CC_LIKELY(!mDebugRegion))
-        return;
-
-    const bool repaintEverything = mRepaintEverything;
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->isDisplayOn()) {
-            // transform the dirty region into this screen's coordinate space
-            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
-            if (!dirtyRegion.isEmpty()) {
-                // redraw the whole screen
-                doComposeSurfaces(hw, Region(hw->bounds()));
-
-                // and draw the dirty region
-                const int32_t height = hw->getHeight();
-                RenderEngine& engine(getRenderEngine());
-                engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
-
-                hw->compositionComplete();
-                hw->swapBuffers(getHwComposer());
-            }
-        }
-    }
-
-    postFramebuffer();
-
-    if (mDebugRegion > 1) {
-        usleep(mDebugRegion * 1000);
-    }
-
-    HWComposer& hwc(getHwComposer());
-    if (hwc.initCheck() == NO_ERROR) {
-        status_t err = hwc.prepare();
-        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-    }
-}
-
-void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
-{
-    bool needExtraInvalidate = false;
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (layer->onPreComposition(refreshStartTime)) {
-            needExtraInvalidate = true;
-        }
-    });
-
-    if (needExtraInvalidate) {
-        signalLayerUpdate();
-    }
-}
-
-void SurfaceFlinger::updateCompositorTiming(
-        nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
-        std::shared_ptr<FenceTime>& presentFenceTime) {
-    // Update queue of past composite+present times and determine the
-    // most recently known composite to present latency.
-    mCompositePresentTimes.push({compositeTime, presentFenceTime});
-    nsecs_t compositeToPresentLatency = -1;
-    while (!mCompositePresentTimes.empty()) {
-        CompositePresentTime& cpt = mCompositePresentTimes.front();
-        // Cached values should have been updated before calling this method,
-        // which helps avoid duplicate syscalls.
-        nsecs_t displayTime = cpt.display->getCachedSignalTime();
-        if (displayTime == Fence::SIGNAL_TIME_PENDING) {
-            break;
-        }
-        compositeToPresentLatency = displayTime - cpt.composite;
-        mCompositePresentTimes.pop();
-    }
-
-    // Don't let mCompositePresentTimes grow unbounded, just in case.
-    while (mCompositePresentTimes.size() > 16) {
-        mCompositePresentTimes.pop();
-    }
-
-    setCompositorTimingSnapped(
-            vsyncPhase, vsyncInterval, compositeToPresentLatency);
-}
-
-void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
-        nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
-    // Integer division and modulo round toward 0 not -inf, so we need to
-    // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
-            (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
-            ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
-
-    // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
-    if (idealLatency <= 0) {
-        idealLatency = vsyncInterval;
-    }
-
-    // Snap the latency to a value that removes scheduling jitter from the
-    // composition and present times, which often have >1ms of jitter.
-    // Reducing jitter is important if an app attempts to extrapolate
-    // something (such as user input) to an accurate diasplay time.
-    // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
-    // with (presentLatency % interval).
-    nsecs_t bias = vsyncInterval / 2;
-    int64_t extraVsyncs =
-            (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
-    nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
-            idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
-
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    mCompositorTiming.deadline = vsyncPhase - idealLatency;
-    mCompositorTiming.interval = vsyncInterval;
-    mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
-}
-
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
-{
-    const HWComposer& hwc = getHwComposer();
-    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-
-    mGlCompositionDoneTimeline.updateSignalTimes();
-    std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (getHwComposer().hasGlesComposition(hw->getHwcDisplayId())) {
-        glCompositionDoneFenceTime =
-                std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
-        mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
-    } else {
-        glCompositionDoneFenceTime = FenceTime::NO_FENCE;
-    }
-
-    mDisplayTimeline.updateSignalTimes();
-    sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
-    auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
-    mDisplayTimeline.push(retireFenceTime);
-
-    nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
-    nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
-
-    // We use the refreshStartTime which might be sampled a little later than
-    // when we started doing work for this frame, but that should be okay
-    // since updateCompositorTiming has snapping logic.
-    updateCompositorTiming(
-        vsyncPhase, vsyncInterval, refreshStartTime, retireFenceTime);
-    CompositorTiming compositorTiming;
-    {
-        std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-        compositorTiming = mCompositorTiming;
-    }
-
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        // TODO(brianderson): The retire fence is incorrectly passed in as the
-        // present fence. Fix this if this file lives on.
-        bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                retireFenceTime, compositorTiming);
-        if (frameLatched) {
-            recordBufferingStats(layer->getName().string(),
-                    layer->getOccupancyHistory(false));
-        }
-    });
-
-    if (retireFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(retireFenceTime)) {
-            enableHardwareVsync();
-        } else {
-            disableHardwareVsync(false);
-        }
-    }
-
-    if (!hasSyncFramework) {
-        if (hw->isDisplayOn()) {
-            enableHardwareVsync();
-        }
-    }
-
-    if (mAnimCompositionPending) {
-        mAnimCompositionPending = false;
-
-        if (retireFenceTime->isValid()) {
-            mAnimFrameTracker.setActualPresentFence(std::move(retireFenceTime));
-        } else {
-            // The HWC doesn't support present fences, so use the refresh
-            // timestamp instead.
-            nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
-            mAnimFrameTracker.setActualPresentTime(presentTime);
-        }
-        mAnimFrameTracker.advanceFrame();
-    }
-
-    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
-        return;
-    }
-
-    nsecs_t currentTime = systemTime();
-    if (mHasPoweredOff) {
-        mHasPoweredOff = false;
-    } else {
-        nsecs_t period = mPrimaryDispSync.getPeriod();
-        nsecs_t elapsedTime = currentTime - mLastSwapTime;
-        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
-        if (numPeriods < NUM_BUCKETS - 1) {
-            mFrameBuckets[numPeriods] += elapsedTime;
-        } else {
-            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
-        }
-        mTotalTime += elapsedTime;
-    }
-    mLastSwapTime = currentTime;
-}
-
-void SurfaceFlinger::rebuildLayerStacks() {
-    // rebuild the visible layer list per screen
-    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
-        ATRACE_CALL();
-        mVisibleRegionsDirty = false;
-        invalidateHwcGeometry();
-
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-            Region opaqueRegion;
-            Region dirtyRegion;
-            Vector< sp<Layer> > layersSortedByZ;
-            const sp<DisplayDevice>& hw(mDisplays[dpy]);
-            const Transform& tr(hw->getTransform());
-            const Rect bounds(hw->getBounds());
-            if (hw->isDisplayOn()) {
-                computeVisibleRegions(hw, dirtyRegion, opaqueRegion);
-
-                mDrawingState.traverseInZOrder([&](Layer* layer) {
-                    if (layer->getLayerStack() == hw->getLayerStack()) {
-                        Region drawRegion(tr.transform(
-                                layer->visibleNonTransparentRegion));
-                        drawRegion.andSelf(bounds);
-                        if (!drawRegion.isEmpty()) {
-                            layersSortedByZ.add(layer);
-                        }
-                    }
-                });
-            }
-            hw->setVisibleLayersSortedByZ(layersSortedByZ);
-            hw->undefinedRegion.set(bounds);
-            hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
-            hw->dirtyRegion.orSelf(dirtyRegion);
-        }
-    }
-}
-
-void SurfaceFlinger::setUpHWComposer() {
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
-        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
-        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
-
-        // If nothing has changed (!dirty), don't recompose.
-        // If something changed, but we don't currently have any visible layers,
-        //   and didn't when we last did a composition, then skip it this time.
-        // The second rule does two things:
-        // - When all layers are removed from a display, we'll emit one black
-        //   frame, then nothing more until we get new layers.
-        // - When a display is created with a private layer stack, we won't
-        //   emit any black frames until a layer is added to the layer stack.
-        bool mustRecompose = dirty && !(empty && wasEmpty);
-
-        ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
-                "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
-                mustRecompose ? "doing" : "skipping",
-                dirty ? "+" : "-",
-                empty ? "+" : "-",
-                wasEmpty ? "+" : "-");
-
-        mDisplays[dpy]->beginFrame(mustRecompose);
-
-        if (mustRecompose) {
-            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
-        }
-    }
-
-    HWComposer& hwc(getHwComposer());
-    if (hwc.initCheck() == NO_ERROR) {
-        // build the h/w work list
-        if (CC_UNLIKELY(mHwWorkListDirty)) {
-            mHwWorkListDirty = false;
-            for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-                sp<const DisplayDevice> hw(mDisplays[dpy]);
-                const int32_t id = hw->getHwcDisplayId();
-                if (id >= 0) {
-                    const Vector< sp<Layer> >& currentLayers(
-                        hw->getVisibleLayersSortedByZ());
-                    const size_t count = currentLayers.size();
-                    if (hwc.createWorkList(id, count) == NO_ERROR) {
-                        HWComposer::LayerListIterator cur = hwc.begin(id);
-                        const HWComposer::LayerListIterator end = hwc.end(id);
-                        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-                            const sp<Layer>& layer(currentLayers[i]);
-                            layer->setGeometry(hw, *cur);
-                            if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
-                                cur->setSkip(true);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // set the per-frame data
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-            sp<const DisplayDevice> hw(mDisplays[dpy]);
-            const int32_t id = hw->getHwcDisplayId();
-            if (id >= 0) {
-                const Vector< sp<Layer> >& currentLayers(
-                    hw->getVisibleLayersSortedByZ());
-                const size_t count = currentLayers.size();
-                HWComposer::LayerListIterator cur = hwc.begin(id);
-                const HWComposer::LayerListIterator end = hwc.end(id);
-                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-                    /*
-                     * update the per-frame h/w composer data for each layer
-                     * and build the transparent region of the FB
-                     */
-                    const sp<Layer>& layer(currentLayers[i]);
-                    layer->setPerFrameData(hw, *cur);
-                }
-            }
-        }
-
-        // If possible, attempt to use the cursor overlay on each display.
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-            sp<const DisplayDevice> hw(mDisplays[dpy]);
-            const int32_t id = hw->getHwcDisplayId();
-            if (id >= 0) {
-                const Vector< sp<Layer> >& currentLayers(
-                    hw->getVisibleLayersSortedByZ());
-                const size_t count = currentLayers.size();
-                HWComposer::LayerListIterator cur = hwc.begin(id);
-                const HWComposer::LayerListIterator end = hwc.end(id);
-                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-                    const sp<Layer>& layer(currentLayers[i]);
-                    if (layer->isPotentialCursor()) {
-                        cur->setIsCursorLayerHint();
-                        break;
-                    }
-                }
-            }
-        }
-
-        status_t err = hwc.prepare();
-        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-            sp<const DisplayDevice> hw(mDisplays[dpy]);
-            hw->prepareFrame(hwc);
-        }
-    }
-}
-
-void SurfaceFlinger::doComposition() {
-    ATRACE_CALL();
-    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->isDisplayOn()) {
-            // transform the dirty region into this screen's coordinate space
-            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
-
-            // repaint the framebuffer (if needed)
-            doDisplayComposition(hw, dirtyRegion);
-
-            hw->dirtyRegion.clear();
-            hw->flip(hw->swapRegion);
-            hw->swapRegion.clear();
-        }
-        // inform the h/w that we're done compositing
-        hw->compositionComplete();
-    }
-    postFramebuffer();
-}
-
-void SurfaceFlinger::postFramebuffer()
-{
-    ATRACE_CALL();
-
-    const nsecs_t now = systemTime();
-    mDebugInSwapBuffers = now;
-
-    HWComposer& hwc(getHwComposer());
-    if (hwc.initCheck() == NO_ERROR) {
-        if (!hwc.supportsFramebufferTarget()) {
-            // EGL spec says:
-            //   "surface must be bound to the calling thread's current context,
-            //    for the current rendering API."
-            getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
-        }
-        hwc.commit();
-    }
-
-    // make the default display current because the VirtualDisplayDevice code cannot
-    // deal with dequeueBuffer() being called outside of the composition loop; however
-    // the code below can call glFlush() which is allowed (and does in some case) call
-    // dequeueBuffer().
-    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
-
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        sp<const DisplayDevice> hw(mDisplays[dpy]);
-        const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
-        hw->onSwapBuffersCompleted(hwc);
-        const size_t count = currentLayers.size();
-        int32_t id = hw->getHwcDisplayId();
-        if (id >=0 && hwc.initCheck() == NO_ERROR) {
-            HWComposer::LayerListIterator cur = hwc.begin(id);
-            const HWComposer::LayerListIterator end = hwc.end(id);
-            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
-                currentLayers[i]->onLayerDisplayed(hw, &*cur);
-            }
-        } else {
-            for (size_t i = 0; i < count; i++) {
-                currentLayers[i]->onLayerDisplayed(hw, NULL);
-            }
-        }
-    }
-
-    mLastSwapBufferTime = systemTime() - now;
-    mDebugInSwapBuffers = 0;
-
-    uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
-    if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
-        logFrameStats();
-    }
-}
-
-void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
-{
-    ATRACE_CALL();
-
-    // here we keep a copy of the drawing state (that is the state that's
-    // going to be overwritten by handleTransactionLocked()) outside of
-    // mStateLock so that the side-effects of the State assignment
-    // don't happen with mStateLock held (which can cause deadlocks).
-    State drawingState(mDrawingState);
-
-    Mutex::Autolock _l(mStateLock);
-    const nsecs_t now = systemTime();
-    mDebugInTransaction = now;
-
-    // Here we're guaranteed that some transaction flags are set
-    // so we can call handleTransactionLocked() unconditionally.
-    // We call getTransactionFlags(), which will also clear the flags,
-    // with mStateLock held to guarantee that mCurrentState won't change
-    // until the transaction is committed.
-
-    transactionFlags = getTransactionFlags(eTransactionMask);
-    handleTransactionLocked(transactionFlags);
-
-    mLastTransactionTime = systemTime() - now;
-    mDebugInTransaction = 0;
-    invalidateHwcGeometry();
-    // here the transaction has been committed
-}
-
-void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
-{
-    // Notify all layers of available frames
-    mCurrentState.traverseInZOrder([](Layer* layer) {
-        layer->notifyAvailableFrames();
-    });
-
-    /*
-     * Traversal of the children
-     * (perform the transaction for each of them if needed)
-     */
-
-    if (transactionFlags & eTraversalNeeded) {
-        mCurrentState.traverseInZOrder([&](Layer* layer) {
-            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
-            if (!trFlags) return;
-
-            const uint32_t flags = layer->doTransaction(0);
-            if (flags & Layer::eVisibleRegion)
-                mVisibleRegionsDirty = true;
-        });
-    }
-
-    /*
-     * Perform display own transactions if needed
-     */
-
-    if (transactionFlags & eDisplayTransactionNeeded) {
-        // here we take advantage of Vector's copy-on-write semantics to
-        // improve performance by skipping the transaction entirely when
-        // know that the lists are identical
-        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
-        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
-        if (!curr.isIdenticalTo(draw)) {
-            mVisibleRegionsDirty = true;
-            const size_t cc = curr.size();
-                  size_t dc = draw.size();
-
-            // find the displays that were removed
-            // (ie: in drawing state but not in current state)
-            // also handle displays that changed
-            // (ie: displays that are in both lists)
-            for (size_t i=0 ; i<dc ; i++) {
-                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
-                if (j < 0) {
-                    // in drawing state but not in current state
-                    if (!draw[i].isMainDisplay()) {
-                        // Call makeCurrent() on the primary display so we can
-                        // be sure that nothing associated with this display
-                        // is current.
-                        const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
-                        defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
-                        sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
-                        if (hw != NULL)
-                            hw->disconnect(getHwComposer());
-                        if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
-                            mEventThread->onHotplugReceived(draw[i].type, false);
-                        mDisplays.removeItem(draw.keyAt(i));
-                    } else {
-                        ALOGW("trying to remove the main display");
-                    }
-                } else {
-                    // this display is in both lists. see if something changed.
-                    const DisplayDeviceState& state(curr[j]);
-                    const wp<IBinder>& display(curr.keyAt(j));
-                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
-                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
-                    if (state_binder != draw_binder) {
-                        // changing the surface is like destroying and
-                        // recreating the DisplayDevice, so we just remove it
-                        // from the drawing state, so that it get re-added
-                        // below.
-                        sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
-                        if (hw != NULL)
-                            hw->disconnect(getHwComposer());
-                        mDisplays.removeItem(display);
-                        mDrawingState.displays.removeItemsAt(i);
-                        dc--; i--;
-                        // at this point we must loop to the next item
-                        continue;
-                    }
-
-                    const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
-                    if (disp != NULL) {
-                        if (state.layerStack != draw[i].layerStack) {
-                            disp->setLayerStack(state.layerStack);
-                        }
-                        if ((state.orientation != draw[i].orientation)
-                                || (state.viewport != draw[i].viewport)
-                                || (state.frame != draw[i].frame))
-                        {
-                            disp->setProjection(state.orientation,
-                                    state.viewport, state.frame);
-                        }
-                        if (state.width != draw[i].width || state.height != draw[i].height) {
-                            disp->setDisplaySize(state.width, state.height);
-                        }
-                    }
-                }
-            }
-
-            // find displays that were added
-            // (ie: in current state but not in drawing state)
-            for (size_t i=0 ; i<cc ; i++) {
-                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
-                    const DisplayDeviceState& state(curr[i]);
-
-                    sp<DisplaySurface> dispSurface;
-                    sp<IGraphicBufferProducer> producer;
-                    sp<IGraphicBufferProducer> bqProducer;
-                    sp<IGraphicBufferConsumer> bqConsumer;
-                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
-
-                    int32_t hwcDisplayId = -1;
-                    if (state.isVirtualDisplay()) {
-                        // Virtual displays without a surface are dormant:
-                        // they have external state (layer stack, projection,
-                        // etc.) but no internal state (i.e. a DisplayDevice).
-                        if (state.surface != NULL) {
-
-                            int width = 0;
-                            int status = state.surface->query(
-                                    NATIVE_WINDOW_WIDTH, &width);
-                            ALOGE_IF(status != NO_ERROR,
-                                    "Unable to query width (%d)", status);
-                            int height = 0;
-                            status = state.surface->query(
-                                    NATIVE_WINDOW_HEIGHT, &height);
-                            ALOGE_IF(status != NO_ERROR,
-                                    "Unable to query height (%d)", status);
-                            if (mUseHwcVirtualDisplays &&
-                                    (SurfaceFlinger::maxVirtualDisplaySize == 0 ||
-                                    (width <= static_cast<int>(SurfaceFlinger::maxVirtualDisplaySize) &&
-                                     height <= static_cast<int>(SurfaceFlinger::maxVirtualDisplaySize)))) {
-                                hwcDisplayId = allocateHwcDisplayId(state.type);
-                            }
-
-                            sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
-                                    *mHwc, hwcDisplayId, state.surface,
-                                    bqProducer, bqConsumer, state.displayName);
-
-                            dispSurface = vds;
-                            producer = vds;
-                        }
-                    } else {
-                        ALOGE_IF(state.surface!=NULL,
-                                "adding a supported display, but rendering "
-                                "surface is provided (%p), ignoring it",
-                                state.surface.get());
-                        hwcDisplayId = allocateHwcDisplayId(state.type);
-                        // for supported (by hwc) displays we provide our
-                        // own rendering surface
-                        dispSurface = new FramebufferSurface(*mHwc, state.type,
-                                bqConsumer);
-                        producer = bqProducer;
-                    }
-
-                    const wp<IBinder>& display(curr.keyAt(i));
-                    if (dispSurface != NULL) {
-                        sp<DisplayDevice> hw = new DisplayDevice(this,
-                                state.type, hwcDisplayId,
-                                mHwc->getFormat(hwcDisplayId), state.isSecure,
-                                display, dispSurface, producer,
-                                mRenderEngine->getEGLConfig(), false);
-                        hw->setLayerStack(state.layerStack);
-                        hw->setProjection(state.orientation,
-                                state.viewport, state.frame);
-                        hw->setDisplayName(state.displayName);
-                        mDisplays.add(display, hw);
-                        if (state.isVirtualDisplay()) {
-                            if (hwcDisplayId >= 0) {
-                                mHwc->setVirtualDisplayProperties(hwcDisplayId,
-                                        hw->getWidth(), hw->getHeight(),
-                                        hw->getFormat());
-                            }
-                        } else {
-                            mEventThread->onHotplugReceived(state.type, true);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
-        // The transform hint might have changed for some layers
-        // (either because a display has changed, or because a layer
-        // as changed).
-        //
-        // Walk through all the layers in currentLayers,
-        // and update their transform hint.
-        //
-        // If a layer is visible only on a single display, then that
-        // display is used to calculate the hint, otherwise we use the
-        // default display.
-        //
-        // NOTE: we do this here, rather than in rebuildLayerStacks() so that
-        // the hint is set before we acquire a buffer from the surface texture.
-        //
-        // NOTE: layer transactions have taken place already, so we use their
-        // drawing state. However, SurfaceFlinger's own transaction has not
-        // happened yet, so we must use the current state layer list
-        // (soon to become the drawing state list).
-        //
-        sp<const DisplayDevice> disp;
-        uint32_t currentlayerStack = 0;
-        bool first = true;
-        mCurrentState.traverseInZOrder([&](Layer* layer) {
-            // NOTE: we rely on the fact that layers are sorted by
-            // layerStack first (so we don't have to traverse the list
-            // of displays for every layer).
-            uint32_t layerStack = layer->getLayerStack();
-            if (first || currentlayerStack != layerStack) {
-                currentlayerStack = layerStack;
-                // figure out if this layerstack is mirrored
-                // (more than one display) if so, pick the default display,
-                // if not, pick the only display it's on.
-                disp.clear();
-                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-                    sp<const DisplayDevice> hw(mDisplays[dpy]);
-                    if (hw->getLayerStack() == currentlayerStack) {
-                        if (disp == NULL) {
-                            disp = hw;
-                        } else {
-                            disp = NULL;
-                            break;
-                        }
-                    }
-                }
-            }
-            if (disp == NULL) {
-                // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
-                // redraw after transform hint changes. See bug 8508397.
-
-                // could be null when this layer is using a layerStack
-                // that is not visible on any display. Also can occur at
-                // screen off/on times.
-                disp = getDefaultDisplayDeviceLocked();
-            }
-            layer->updateTransformHint(disp);
-
-            first = false;
-        });
-    }
-
-
-    /*
-     * Perform our own transaction if needed
-     */
-
-    if (mLayersAdded) {
-        mLayersAdded = false;
-        // Layers have been added.
-        mVisibleRegionsDirty = true;
-    }
-
-    // some layers might have been removed, so
-    // we need to update the regions they're exposing.
-    if (mLayersRemoved) {
-        mLayersRemoved = false;
-        mVisibleRegionsDirty = true;
-        mDrawingState.traverseInZOrder([&](Layer* layer) {
-            if (mLayersPendingRemoval.indexOf(layer) >= 0) {
-                // this layer is not visible anymore
-                // TODO: we could traverse the tree from front to back and
-                //       compute the actual visible region
-                // TODO: we could cache the transformed region
-                Region visibleReg;
-                visibleReg.set(layer->computeScreenBounds());
-                invalidateLayerStack(layer, visibleReg);
-            }
-        });
-    }
-
-    commitTransaction();
-
-    updateCursorAsync();
-}
-
-void SurfaceFlinger::updateCursorAsync()
-{
-    HWComposer& hwc(getHwComposer());
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        sp<const DisplayDevice> hw(mDisplays[dpy]);
-        const int32_t id = hw->getHwcDisplayId();
-        if (id < 0) {
-            continue;
-        }
-        const Vector< sp<Layer> >& currentLayers(
-            hw->getVisibleLayersSortedByZ());
-        const size_t count = currentLayers.size();
-        HWComposer::LayerListIterator cur = hwc.begin(id);
-        const HWComposer::LayerListIterator end = hwc.end(id);
-        for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-            if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
-                continue;
-            }
-            const sp<Layer>& layer(currentLayers[i]);
-            Rect cursorPos = layer->getPosition(hw);
-            hwc.setCursorPositionAsync(id, cursorPos);
-            break;
-        }
-    }
-}
-
-void SurfaceFlinger::commitTransaction()
-{
-    if (!mLayersPendingRemoval.isEmpty()) {
-        // Notify removed layers now that they can't be drawn from
-        for (const auto& l : mLayersPendingRemoval) {
-            recordBufferingStats(l->getName().string(),
-                    l->getOccupancyHistory(true));
-            l->onRemoved();
-        }
-        mLayersPendingRemoval.clear();
-    }
-
-    // If this transaction is part of a window animation then the next frame
-    // we composite should be considered an animation as well.
-    mAnimCompositionPending = mAnimTransactionPending;
-
-    mDrawingState = mCurrentState;
-    mDrawingState.traverseInZOrder([](Layer* layer) {
-        layer->commitChildList();
-    });
-    mTransactionPending = false;
-    mAnimTransactionPending = false;
-    mTransactionCV.broadcast();
-}
-
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
-        Region& outDirtyRegion, Region& outOpaqueRegion)
-{
-    ATRACE_CALL();
-
-    Region aboveOpaqueLayers;
-    Region aboveCoveredLayers;
-    Region dirty;
-
-    outDirtyRegion.clear();
-
-    mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
-        // start with the whole surface at its current location
-        const Layer::State& s(layer->getDrawingState());
-
-        // only consider the layers on the given layer stack
-        if (layer->getLayerStack() != displayDevice->getLayerStack())
-            return;
-
-        /*
-         * opaqueRegion: area of a surface that is fully opaque.
-         */
-        Region opaqueRegion;
-
-        /*
-         * visibleRegion: area of a surface that is visible on screen
-         * and not fully transparent. This is essentially the layer's
-         * footprint minus the opaque regions above it.
-         * Areas covered by a translucent surface are considered visible.
-         */
-        Region visibleRegion;
-
-        /*
-         * coveredRegion: area of a surface that is covered by all
-         * visible regions above it (which includes the translucent areas).
-         */
-        Region coveredRegion;
-
-        /*
-         * transparentRegion: area of a surface that is hinted to be completely
-         * transparent. This is only used to tell when the layer has no visible
-         * non-transparent regions and can be removed from the layer list. It
-         * does not affect the visibleRegion of this layer or any layers
-         * beneath it. The hint may not be correct if apps don't respect the
-         * SurfaceView restrictions (which, sadly, some don't).
-         */
-        Region transparentRegion;
-
-
-        // handle hidden surfaces by setting the visible region to empty
-        if (CC_LIKELY(layer->isVisible())) {
-            const bool translucent = !layer->isOpaque(s);
-            Rect bounds(layer->computeScreenBounds());
-            visibleRegion.set(bounds);
-            Transform tr = layer->getTransform();
-            if (!visibleRegion.isEmpty()) {
-                // Remove the transparent area from the visible region
-                if (translucent) {
-                    if (tr.preserveRects()) {
-                        // transform the transparent region
-                        transparentRegion = tr.transform(s.activeTransparentRegion);
-                    } else {
-                        // transformation too complex, can't do the
-                        // transparent region optimization.
-                        transparentRegion.clear();
-                    }
-                }
-
-                // compute the opaque region
-                const int32_t layerOrientation = tr.getOrientation();
-                if (s.alpha==255 && !translucent &&
-                        ((layerOrientation & Transform::ROT_INVALID) == false)) {
-                    // the opaque region is the layer's footprint
-                    opaqueRegion = visibleRegion;
-                }
-            }
-        }
-
-        // Clip the covered region to the visible region
-        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
-
-        // Update aboveCoveredLayers for next (lower) layer
-        aboveCoveredLayers.orSelf(visibleRegion);
-
-        // subtract the opaque region covered by the layers above us
-        visibleRegion.subtractSelf(aboveOpaqueLayers);
-
-        // compute this layer's dirty region
-        if (layer->contentDirty) {
-            // we need to invalidate the whole region
-            dirty = visibleRegion;
-            // as well, as the old visible region
-            dirty.orSelf(layer->visibleRegion);
-            layer->contentDirty = false;
-        } else {
-            /* compute the exposed region:
-             *   the exposed region consists of two components:
-             *   1) what's VISIBLE now and was COVERED before
-             *   2) what's EXPOSED now less what was EXPOSED before
-             *
-             * note that (1) is conservative, we start with the whole
-             * visible region but only keep what used to be covered by
-             * something -- which mean it may have been exposed.
-             *
-             * (2) handles areas that were not covered by anything but got
-             * exposed because of a resize.
-             */
-            const Region newExposed = visibleRegion - coveredRegion;
-            const Region oldVisibleRegion = layer->visibleRegion;
-            const Region oldCoveredRegion = layer->coveredRegion;
-            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
-            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
-        }
-        dirty.subtractSelf(aboveOpaqueLayers);
-
-        // accumulate to the screen dirty region
-        outDirtyRegion.orSelf(dirty);
-
-        // Update aboveOpaqueLayers for next (lower) layer
-        aboveOpaqueLayers.orSelf(opaqueRegion);
-
-        // Store the visible region in screen space
-        layer->setVisibleRegion(visibleRegion);
-        layer->setCoveredRegion(coveredRegion);
-        layer->setVisibleNonTransparentRegion(
-                visibleRegion.subtract(transparentRegion));
-    });
-
-    outOpaqueRegion = aboveOpaqueLayers;
-}
-
-void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
-    uint32_t layerStack = layer->getLayerStack();
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->getLayerStack() == layerStack) {
-            hw->dirtyRegion.orSelf(dirty);
-        }
-    }
-}
-
-bool SurfaceFlinger::handlePageFlip()
-{
-    nsecs_t latchTime = systemTime();
-    Region dirtyRegion;
-
-    bool visibleRegions = false;
-    bool frameQueued = false;
-
-    // Store the set of layers that need updates. This set must not change as
-    // buffers are being latched, as this could result in a deadlock.
-    // Example: Two producers share the same command stream and:
-    // 1.) Layer 0 is latched
-    // 2.) Layer 0 gets a new frame
-    // 2.) Layer 1 gets a new frame
-    // 3.) Layer 1 is latched.
-    // Display is now waiting on Layer 1's frame, which is behind layer 0's
-    // second frame. But layer 0's second frame could be waiting on display.
-    Vector<Layer*> layersWithQueuedFrames;
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (layer->hasQueuedFrame()) {
-            frameQueued = true;
-            if (layer->shouldPresentNow(mPrimaryDispSync)) {
-                layersWithQueuedFrames.push_back(layer);
-            } else {
-                layer->useEmptyDamage();
-            }
-        } else {
-            layer->useEmptyDamage();
-        }
-    });
-    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
-        Layer* layer = layersWithQueuedFrames[i];
-        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
-        layer->useSurfaceDamage();
-        invalidateLayerStack(layer, dirty);
-    }
-
-    mVisibleRegionsDirty |= visibleRegions;
-
-    // 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.
-    if (frameQueued && layersWithQueuedFrames.empty()) {
-        signalLayerUpdate();
-    }
-
-    // Only continue with the refresh if there is actually new work to do
-    return !layersWithQueuedFrames.empty();
-}
-
-void SurfaceFlinger::invalidateHwcGeometry()
-{
-    mHwWorkListDirty = true;
-}
-
-
-void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
-        const Region& inDirtyRegion)
-{
-    // We only need to actually compose the display if:
-    // 1) It is being handled by hardware composer, which may need this to
-    //    keep its virtual display state machine in sync, or
-    // 2) There is work to be done (the dirty region isn't empty)
-    bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
-    if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
-        return;
-    }
-
-    Region dirtyRegion(inDirtyRegion);
-
-    // compute the invalid region
-    hw->swapRegion.orSelf(dirtyRegion);
-
-    uint32_t flags = hw->getFlags();
-    if (flags & DisplayDevice::SWAP_RECTANGLE) {
-        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
-        // takes a rectangle, we must make sure to update that whole
-        // rectangle in that case
-        dirtyRegion.set(hw->swapRegion.bounds());
-    } else {
-        if (flags & DisplayDevice::PARTIAL_UPDATES) {
-            // We need to redraw the rectangle that will be updated
-            // (pushed to the framebuffer).
-            // This is needed because PARTIAL_UPDATES only takes one
-            // rectangle instead of a region (see DisplayDevice::flip())
-            dirtyRegion.set(hw->swapRegion.bounds());
-        } else {
-            // we need to redraw everything (the whole screen)
-            dirtyRegion.set(hw->bounds());
-            hw->swapRegion = dirtyRegion;
-        }
-    }
-
-    if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
-        if (!doComposeSurfaces(hw, dirtyRegion)) return;
-    } else {
-        RenderEngine& engine(getRenderEngine());
-        mat4 colorMatrix = mColorMatrix;
-        if (mDaltonize) {
-            colorMatrix = colorMatrix * mDaltonizer();
-        }
-        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
-        doComposeSurfaces(hw, dirtyRegion);
-        engine.setupColorTransform(oldMatrix);
-    }
-
-    // update the swap region and clear the dirty region
-    hw->swapRegion.orSelf(dirtyRegion);
-
-    // swap buffers (presentation)
-    hw->swapBuffers(getHwComposer());
-}
-
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
-{
-    RenderEngine& engine(getRenderEngine());
-    const int32_t id = hw->getHwcDisplayId();
-    HWComposer& hwc(getHwComposer());
-    HWComposer::LayerListIterator cur = hwc.begin(id);
-    const HWComposer::LayerListIterator end = hwc.end(id);
-
-    bool hasGlesComposition = hwc.hasGlesComposition(id);
-    if (hasGlesComposition) {
-        if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
-            ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
-                  hw->getDisplayName().string());
-            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
-              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
-            }
-            return false;
-        }
-
-        // Never touch the framebuffer if we don't have any framebuffer layers
-        const bool hasHwcComposition = hwc.hasHwcComposition(id);
-        if (hasHwcComposition) {
-            // when using overlays, we assume a fully transparent framebuffer
-            // NOTE: we could reduce how much we need to clear, for instance
-            // remove where there are opaque FB layers. however, on some
-            // GPUs doing a "clean slate" clear might be more efficient.
-            // We'll revisit later if needed.
-            engine.clearWithColor(0, 0, 0, 0);
-        } else {
-            // we start with the whole screen area
-            const Region bounds(hw->getBounds());
-
-            // we remove the scissor part
-            // we're left with the letterbox region
-            // (common case is that letterbox ends-up being empty)
-            const Region letterbox(bounds.subtract(hw->getScissor()));
-
-            // compute the area to clear
-            Region region(hw->undefinedRegion.merge(letterbox));
-
-            // but limit it to the dirty region
-            region.andSelf(dirty);
-
-            // screen is already cleared here
-            if (!region.isEmpty()) {
-                // can happen with SurfaceView
-                drawWormhole(hw, region);
-            }
-        }
-
-        if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
-            // just to be on the safe side, we don't set the
-            // scissor on the main display. It should never be needed
-            // anyways (though in theory it could since the API allows it).
-            const Rect& bounds(hw->getBounds());
-            const Rect& scissor(hw->getScissor());
-            if (scissor != bounds) {
-                // scissor doesn't match the screen's dimensions, so we
-                // need to clear everything outside of it and enable
-                // the GL scissor so we don't draw anything where we shouldn't
-
-                // enable scissor for this frame
-                const uint32_t height = hw->getHeight();
-                engine.setScissor(scissor.left, height - scissor.bottom,
-                        scissor.getWidth(), scissor.getHeight());
-            }
-        }
-    }
-
-    /*
-     * and then, render the layers targeted at the framebuffer
-     */
-
-    const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
-    const size_t count = layers.size();
-    const Transform& tr = hw->getTransform();
-    if (cur != end) {
-        // we're using h/w composer
-        for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
-            const sp<Layer>& layer(layers[i]);
-            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
-            if (!clip.isEmpty()) {
-                switch (cur->getCompositionType()) {
-                    case HWC_CURSOR_OVERLAY:
-                    case HWC_OVERLAY: {
-                        const Layer::State& state(layer->getDrawingState());
-                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)
-                                && i
-                                && layer->isOpaque(state) && (state.alpha == 0xFF)
-                                && hasGlesComposition) {
-                            // never clear the very first layer since we're
-                            // guaranteed the FB is already cleared
-                            layer->clearWithOpenGL(hw);
-                        }
-                        break;
-                    }
-                    case HWC_FRAMEBUFFER: {
-                        layer->draw(hw, clip);
-                        break;
-                    }
-                    case HWC_FRAMEBUFFER_TARGET: {
-                        // this should not happen as the iterator shouldn't
-                        // let us get there.
-                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
-                        break;
-                    }
-                }
-            }
-            layer->setAcquireFence(hw, *cur);
-        }
-    } else {
-        // we're not using h/w composer
-        for (size_t i=0 ; i<count ; ++i) {
-            const sp<Layer>& layer(layers[i]);
-            const Region clip(dirty.intersect(
-                    tr.transform(layer->visibleRegion)));
-            if (!clip.isEmpty()) {
-                layer->draw(hw, clip);
-            }
-        }
-    }
-
-    // disable scissor at the end of the frame
-    engine.disableScissor();
-    return true;
-}
-
-void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const {
-    const int32_t height = hw->getHeight();
-    RenderEngine& engine(getRenderEngine());
-    engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
-}
-
-status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
-        const sp<IBinder>& handle,
-        const sp<IGraphicBufferProducer>& gbc,
-        const sp<Layer>& lbc,
-        const sp<Layer>& parent)
-{
-    // add this layer to the current state list
-    {
-        Mutex::Autolock _l(mStateLock);
-        if (mNumLayers >= MAX_LAYERS) {
-            return NO_MEMORY;
-        }
-        if (parent == nullptr) {
-            mCurrentState.layersSortedByZ.add(lbc);
-        } else {
-            if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
-                ALOGE("addClientLayer called with a removed parent");
-                return NAME_NOT_FOUND;
-            }
-            parent->addChild(lbc);
-        }
-
-        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
-        mLayersAdded = true;
-        mNumLayers++;
-    }
-
-    // attach this layer to the client
-    client->attachLayer(handle, lbc);
-
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
-    Mutex::Autolock _l(mStateLock);
-
-    const auto& p = layer->getParent();
-    ssize_t index;
-    if (p != nullptr) {
-        if (topLevelOnly) {
-            return NO_ERROR;
-        }
-
-        sp<Layer> ancestor = p;
-        while (ancestor->getParent() != nullptr) {
-            ancestor = ancestor->getParent();
-        }
-        if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
-            ALOGE("removeLayer called with a layer whose parent has been removed");
-            return NAME_NOT_FOUND;
-        }
-
-        index = p->removeChild(layer);
-    } else {
-        index = mCurrentState.layersSortedByZ.remove(layer);
-    }
-
-    // As a matter of normal operation, the LayerCleaner will produce a second
-    // attempt to remove the surface. The Layer will be kept alive in mDrawingState
-    // so we will succeed in promoting it, but it's already been removed
-    // from mCurrentState. As long as we can find it in mDrawingState we have no problem
-    // otherwise something has gone wrong and we are leaking the layer.
-    if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
-        ALOGE("Failed to find layer (%s) in layer parent (%s).",
-                layer->getName().string(),
-                (p != nullptr) ? p->getName().string() : "no-parent");
-        return BAD_VALUE;
-    } else if (index < 0) {
-        return NO_ERROR;
-    }
-
-    layer->onRemovedFromCurrentState();
-    mLayersPendingRemoval.add(layer);
-    mLayersRemoved = true;
-    mNumLayers -= 1 + layer->getChildrenCount();
-    setTransactionFlags(eTransactionNeeded);
-    return NO_ERROR;
-}
-
-uint32_t SurfaceFlinger::peekTransactionFlags() {
-    return android_atomic_release_load(&mTransactionFlags);
-}
-
-uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
-    return android_atomic_and(~flags, &mTransactionFlags) & flags;
-}
-
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
-    uint32_t old = android_atomic_or(flags, &mTransactionFlags);
-    if ((old & flags)==0) { // wake the server up
-        signalTransaction();
-    }
-    return old;
-}
-
-void SurfaceFlinger::setTransactionState(
-        const Vector<ComposerState>& state,
-        const Vector<DisplayState>& displays,
-        uint32_t flags)
-{
-    ATRACE_CALL();
-    Mutex::Autolock _l(mStateLock);
-    uint32_t transactionFlags = 0;
-
-    if (flags & eAnimation) {
-        // For window updates that are part of an animation we must wait for
-        // previous animation "frames" to be handled.
-        while (mAnimTransactionPending) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                // just in case something goes wrong in SF, return to the
-                // caller after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
-                        "waiting for previous animation frame");
-                mAnimTransactionPending = false;
-                break;
-            }
-        }
-    }
-
-    size_t count = displays.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const DisplayState& s(displays[i]);
-        transactionFlags |= setDisplayStateLocked(s);
-    }
-
-    count = state.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const ComposerState& s(state[i]);
-        // Here we need to check that the interface we're given is indeed
-        // one of our own. A malicious client could give us a NULL
-        // IInterface, or one of its own or even one of our own but a
-        // different type. All these situations would cause us to crash.
-        //
-        // NOTE: it would be better to use RTTI as we could directly check
-        // that we have a Client*. however, RTTI is disabled in Android.
-        if (s.client != NULL) {
-            sp<IBinder> binder = IInterface::asBinder(s.client);
-            if (binder != NULL) {
-                if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) {
-                    sp<Client> client( static_cast<Client *>(s.client.get()) );
-                    transactionFlags |= setClientStateLocked(client, s.state);
-                }
-            }
-        }
-    }
-
-    // If a synchronous transaction is explicitly requested without any changes,
-    // force a transaction anyway. This can be used as a flush mechanism for
-    // previous async transactions.
-    if (transactionFlags == 0 && (flags & eSynchronous)) {
-        transactionFlags = eTransactionNeeded;
-    }
-
-    if (transactionFlags) {
-        if (mInterceptor.isEnabled()) {
-            mInterceptor.saveTransaction(state, mCurrentState.displays, displays, flags);
-        }
-
-        // this triggers the transaction
-        setTransactionFlags(transactionFlags);
-
-        // if this is a synchronous transaction, wait for it to take effect
-        // before returning.
-        if (flags & eSynchronous) {
-            mTransactionPending = true;
-        }
-        if (flags & eAnimation) {
-            mAnimTransactionPending = true;
-        }
-        while (mTransactionPending) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                // just in case something goes wrong in SF, return to the
-                // called after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
-                mTransactionPending = false;
-                break;
-            }
-        }
-    }
-}
-
-uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
-{
-    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
-    if (dpyIdx < 0)
-        return 0;
-
-    uint32_t flags = 0;
-    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
-    if (disp.isValid()) {
-        const uint32_t what = s.what;
-        if (what & DisplayState::eSurfaceChanged) {
-            if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
-                disp.surface = s.surface;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eLayerStackChanged) {
-            if (disp.layerStack != s.layerStack) {
-                disp.layerStack = s.layerStack;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplayProjectionChanged) {
-            if (disp.orientation != s.orientation) {
-                disp.orientation = s.orientation;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.frame != s.frame) {
-                disp.frame = s.frame;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.viewport != s.viewport) {
-                disp.viewport = s.viewport;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplaySizeChanged) {
-            if (disp.width != s.width) {
-                disp.width = s.width;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.height != s.height) {
-                disp.height = s.height;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-    }
-    return flags;
-}
-
-uint32_t SurfaceFlinger::setClientStateLocked(
-        const sp<Client>& client,
-        const layer_state_t& s)
-{
-    uint32_t flags = 0;
-    sp<Layer> layer(client->getLayerUser(s.surface));
-    if (layer != 0) {
-        const uint32_t what = s.what;
-        bool geometryAppliesWithResize =
-                what & layer_state_t::eGeometryAppliesWithResize;
-        if (what & layer_state_t::ePositionChanged) {
-            if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
-                flags |= eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eLayerChanged) {
-            // NOTE: index needs to be calculated before we update the state
-            const auto& p = layer->getParent();
-            if (p == nullptr) {
-                ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-                if (layer->setLayer(s.z) && idx >= 0) {
-                    mCurrentState.layersSortedByZ.removeAt(idx);
-                    mCurrentState.layersSortedByZ.add(layer);
-                    // we need traversal (state changed)
-                    // AND transaction (list changed)
-                    flags |= eTransactionNeeded|eTraversalNeeded;
-                }
-            } else {
-                if (p->setChildLayer(layer, s.z)) {
-                    flags |= eTransactionNeeded|eTraversalNeeded;
-                }
-            }
-        }
-        if (what & layer_state_t::eSizeChanged) {
-            if (layer->setSize(s.w, s.h)) {
-                flags |= eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eAlphaChanged) {
-            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eMatrixChanged) {
-            if (layer->setMatrix(s.matrix))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eTransparentRegionChanged) {
-            if (layer->setTransparentRegionHint(s.transparentRegion))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eFlagsChanged) {
-            if (layer->setFlags(s.flags, s.mask))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eCropChanged) {
-            if (layer->setCrop(s.crop, !geometryAppliesWithResize))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
-                flags |= eTraversalNeeded;
-        }
-        if (what & layer_state_t::eLayerStackChanged) {
-            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-            // We only allow setting layer stacks for top level layers,
-            // everything else inherits layer stack from its parent.
-            if (layer->hasParent()) {
-                ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
-                        layer->getName().string());
-            } else if (idx < 0) {
-                ALOGE("Attempt to set layer stack on layer without parent (%s) that "
-                        "that also does not appear in the top level layer list. Something"
-                        " has gone wrong.", layer->getName().string());
-            } else if (layer->setLayerStack(s.layerStack)) {
-                mCurrentState.layersSortedByZ.removeAt(idx);
-                mCurrentState.layersSortedByZ.add(layer);
-                // we need traversal (state changed)
-                // AND transaction (list changed)
-                flags |= eTransactionNeeded|eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eDeferTransaction) {
-            if (s.barrierHandle != nullptr) {
-                layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
-            } else if (s.barrierGbp != nullptr) {
-                const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
-                if (authenticateSurfaceTextureLocked(gbp)) {
-                    const auto& otherLayer =
-                        (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
-                    layer->deferTransactionUntil(otherLayer, s.frameNumber);
-                } else {
-                    ALOGE("Attempt to defer transaction to to an"
-                            " unrecognized GraphicBufferProducer");
-                }
-            }
-            // We don't trigger a traversal here because if no other state is
-            // changed, we don't want this to cause any more work
-        }
-        if (what & layer_state_t::eReparentChildren) {
-            if (layer->reparentChildren(s.reparentHandle)) {
-                flags |= eTransactionNeeded|eTraversalNeeded;
-            }
-        }
-        if (what & layer_state_t::eDetachChildren) {
-            layer->detachChildren();
-        }
-        if (what & layer_state_t::eOverrideScalingModeChanged) {
-            layer->setOverrideScalingMode(s.overrideScalingMode);
-            // We don't trigger a traversal here because if no other state is
-            // changed, we don't want this to cause any more work
-        }
-    }
-    return flags;
-}
-
-status_t SurfaceFlinger::createLayer(
-        const String8& name,
-        const sp<Client>& client,
-        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
-        sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
-{
-    if (int32_t(w|h) < 0) {
-        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
-                int(w), int(h));
-        return BAD_VALUE;
-    }
-
-    status_t result = NO_ERROR;
-
-    sp<Layer> layer;
-
-    String8 uniqueName = getUniqueLayerName(name);
-
-    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
-        case ISurfaceComposerClient::eFXSurfaceNormal:
-            result = createNormalLayer(client,
-                    uniqueName, w, h, flags, format,
-                    handle, gbp, &layer);
-            break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
-                    uniqueName, w, h, flags,
-                    handle, gbp, &layer);
-            break;
-        default:
-            result = BAD_VALUE;
-            break;
-    }
-
-    if (result != NO_ERROR) {
-        return result;
-    }
-
-    layer->setInfo(windowType, ownerUid);
-
-    result = addClientLayer(client, *handle, *gbp, layer, *parent);
-    if (result != NO_ERROR) {
-        return result;
-    }
-    mInterceptor.saveSurfaceCreation(layer);
-
-    setTransactionFlags(eTransactionNeeded);
-    return result;
-}
-
-String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
-{
-    bool matchFound = true;
-    uint32_t dupeCounter = 0;
-
-    // Tack on our counter whether there is a hit or not, so everyone gets a tag
-    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
-
-    // Loop over layers until we're sure there is no matching name
-    while (matchFound) {
-        matchFound = false;
-        mDrawingState.traverseInZOrder([&](Layer* layer) {
-            if (layer->getName() == uniqueName) {
-                matchFound = true;
-                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
-            }
-        });
-    }
-
-    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
-
-    return uniqueName;
-}
-
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
-        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
-        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
-{
-    // initialize the surfaces
-    switch (format) {
-    case PIXEL_FORMAT_TRANSPARENT:
-    case PIXEL_FORMAT_TRANSLUCENT:
-        format = PIXEL_FORMAT_RGBA_8888;
-        break;
-    case PIXEL_FORMAT_OPAQUE:
-        format = PIXEL_FORMAT_RGBX_8888;
-        break;
-    }
-
-    *outLayer = new Layer(this, client, name, w, h, flags);
-    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
-    if (err == NO_ERROR) {
-        *handle = (*outLayer)->getHandle();
-        *gbp = (*outLayer)->getProducer();
-    }
-
-    ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
-    return err;
-}
-
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
-        const String8& name, uint32_t w, uint32_t h, uint32_t flags,
-        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
-{
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
-    *handle = (*outLayer)->getHandle();
-    *gbp = (*outLayer)->getProducer();
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
-{
-    // called by a client when it wants to remove a Layer
-    status_t err = NO_ERROR;
-    sp<Layer> l(client->getLayerUser(handle));
-    if (l != NULL) {
-        mInterceptor.saveSurfaceDeletion(l);
-        err = removeLayer(l);
-        ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
-                "error removing layer=%p (%s)", l.get(), strerror(-err));
-    }
-    return err;
-}
-
-status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
-{
-    // called by ~LayerCleaner() when all references to the IBinder (handle)
-    // are gone
-    sp<Layer> l = layer.promote();
-    if (l == nullptr) {
-        // The layer has already been removed, carry on
-        return NO_ERROR;
-    }
-    // If we have a parent, then we can continue to live as long as it does.
-    return removeLayer(l, true);
-}
-
-// ---------------------------------------------------------------------------
-
-void SurfaceFlinger::onInitializeDisplays() {
-    // reset screen orientation and use primary layer stack
-    Vector<ComposerState> state;
-    Vector<DisplayState> displays;
-    DisplayState d;
-    d.what = DisplayState::eDisplayProjectionChanged |
-             DisplayState::eLayerStackChanged;
-    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
-    d.layerStack = 0;
-    d.orientation = DisplayState::eOrientationDefault;
-    d.frame.makeInvalid();
-    d.viewport.makeInvalid();
-    d.width = 0;
-    d.height = 0;
-    displays.add(d);
-    setTransactionState(state, displays, 0);
-    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
-
-    const nsecs_t period =
-            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-    mAnimFrameTracker.setDisplayRefreshPeriod(period);
-
-    // Use phase of 0 since phase is not known.
-    // Use latency of 0, which will snap to the ideal latency.
-    setCompositorTimingSnapped(0, period, 0);
-}
-
-void SurfaceFlinger::initializeDisplays() {
-    class MessageScreenInitialized : public MessageBase {
-        SurfaceFlinger* flinger;
-    public:
-        explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
-        virtual bool handler() {
-            flinger->onInitializeDisplays();
-            return true;
-        }
-    };
-    sp<MessageBase> msg = new MessageScreenInitialized(this);
-    postMessageAsync(msg);  // we may be called from main thread, use async message
-}
-
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
-        int mode) {
-    ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
-            this);
-    int32_t type = hw->getDisplayType();
-    int currentMode = hw->getPowerMode();
-
-    if (mode == currentMode) {
-        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
-        return;
-    }
-
-    hw->setPowerMode(mode);
-    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        ALOGW("Trying to set power mode for virtual display");
-        return;
-    }
-
-    if (mInterceptor.isEnabled()) {
-        Mutex::Autolock _l(mStateLock);
-        ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
-        if (idx < 0) {
-            ALOGW("Surface Interceptor SavePowerMode: invalid display token");
-            return;
-        }
-        mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
-    }
-
-    if (currentMode == HWC_POWER_MODE_OFF) {
-        // Turn on the display
-        getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY &&
-            mode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            // FIXME: eventthread only knows about the main display right now
-            mEventThread->onScreenAcquired();
-            resyncToHardwareVsync(true);
-        }
-
-        mVisibleRegionsDirty = true;
-        mHasPoweredOff = true;
-        repaintEverything();
-
-        struct sched_param param = {0};
-        param.sched_priority = 1;
-        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
-            ALOGW("Couldn't set SCHED_FIFO on display on");
-        }
-    } else if (mode == HWC_POWER_MODE_OFF) {
-        // Turn off the display
-        struct sched_param param = {0};
-        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {
-            ALOGW("Couldn't set SCHED_OTHER on display off");
-        }
-
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
-            disableHardwareVsync(true); // also cancels any in-progress resync
-
-            // FIXME: eventthread only knows about the main display right now
-            mEventThread->onScreenReleased();
-        }
-
-        getHwComposer().setPowerMode(type, mode);
-        mVisibleRegionsDirty = true;
-        // from this point on, SF will stop drawing on this display
-    } else if (mode == HWC_POWER_MODE_DOZE ||
-               mode == HWC_POWER_MODE_NORMAL) {
-        // Update display while dozing
-        getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
-            // FIXME: eventthread only knows about the main display right now
-            mEventThread->onScreenAcquired();
-            resyncToHardwareVsync(true);
-        }
-    } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
-        // Leave display going to doze
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
-            disableHardwareVsync(true); // also cancels any in-progress resync
-            // FIXME: eventthread only knows about the main display right now
-            mEventThread->onScreenReleased();
-        }
-        getHwComposer().setPowerMode(type, mode);
-    } else {
-        ALOGE("Attempting to set unknown power mode: %d\n", mode);
-        getHwComposer().setPowerMode(type, mode);
-    }
-}
-
-void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
-    class MessageSetPowerMode: public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-        int mMode;
-    public:
-        MessageSetPowerMode(SurfaceFlinger& flinger,
-                const sp<IBinder>& disp, int mode) : mFlinger(flinger),
-                    mDisplay(disp) { mMode = mode; }
-        virtual bool handler() {
-            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == NULL) {
-                ALOGE("Attempt to set power mode = %d for null display %p",
-                        mMode, mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set power mode = %d for virtual display",
-                        mMode);
-            } else {
-                mFlinger.setPowerModeInternal(hw, mMode);
-            }
-            return true;
-        }
-    };
-    sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
-    postMessageSync(msg);
-}
-
-// ---------------------------------------------------------------------------
-
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
-    String8 result;
-
-    IPCThreadState* ipc = IPCThreadState::self();
-    const int pid = ipc->getCallingPid();
-    const int uid = ipc->getCallingUid();
-    if ((uid != AID_SHELL) &&
-            !PermissionCache::checkPermission(sDump, pid, uid)) {
-        result.appendFormat("Permission Denial: "
-                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
-    } else {
-        // Try to get the main lock, but give up after one second
-        // (this would indicate SF is stuck, but we want to be able to
-        // print something in dumpsys).
-        status_t err = mStateLock.timedLock(s2ns(1));
-        bool locked = (err == NO_ERROR);
-        if (!locked) {
-            result.appendFormat(
-                    "SurfaceFlinger appears to be unresponsive (%s [%d]), "
-                    "dumping anyways (no locks held)\n", strerror(-err), err);
-        }
-
-        bool dumpAll = true;
-        size_t index = 0;
-        size_t numArgs = args.size();
-        if (numArgs) {
-            if ((index < numArgs) &&
-                    (args[index] == String16("--list"))) {
-                index++;
-                listLayersLocked(args, index, result);
-                dumpAll = false;
-            }
-
-            if ((index < numArgs) &&
-                    (args[index] == String16("--latency"))) {
-                index++;
-                dumpStatsLocked(args, index, result);
-                dumpAll = false;
-            }
-
-            if ((index < numArgs) &&
-                    (args[index] == String16("--latency-clear"))) {
-                index++;
-                clearStatsLocked(args, index, result);
-                dumpAll = false;
-            }
-
-            if ((index < numArgs) &&
-                    (args[index] == String16("--dispsync"))) {
-                index++;
-                mPrimaryDispSync.dump(result);
-                dumpAll = false;
-            }
-
-            if ((index < numArgs) &&
-                    (args[index] == String16("--static-screen"))) {
-                index++;
-                dumpStaticScreenStats(result);
-                dumpAll = false;
-            }
-
-            if ((index < numArgs) &&
-                    (args[index] == String16("--frame-events"))) {
-                index++;
-                dumpFrameEventsLocked(result);
-                dumpAll = false;
-            }
-        }
-
-        if (dumpAll) {
-            dumpAllLocked(args, index, result);
-        }
-
-        if (locked) {
-            mStateLock.unlock();
-        }
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
-        size_t& /* index */, String8& result) const
-{
-    mCurrentState.traverseInZOrder([&](Layer* layer) {
-        result.appendFormat("%s\n", layer->getName().string());
-    });
-}
-
-void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const
-{
-    String8 name;
-    if (index < args.size()) {
-        name = String8(args[index]);
-        index++;
-    }
-
-    const nsecs_t period =
-            getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-    result.appendFormat("%" PRId64 "\n", period);
-
-    if (name.isEmpty()) {
-        mAnimFrameTracker.dumpStats(result);
-    } else {
-        mCurrentState.traverseInZOrder([&](Layer* layer) {
-            if (name == layer->getName()) {
-                layer->dumpFrameStats(result);
-            }
-        });
-    }
-}
-
-void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& /* result */)
-{
-    String8 name;
-    if (index < args.size()) {
-        name = String8(args[index]);
-        index++;
-    }
-
-    mCurrentState.traverseInZOrder([&](Layer* layer) {
-        if (name.isEmpty() || (name == layer->getName())) {
-            layer->clearFrameStats();
-        }
-    });
-
-    mAnimFrameTracker.clearStats();
-}
-
-// This should only be called from the main thread.  Otherwise it would need
-// the lock and should use mCurrentState rather than mDrawingState.
-void SurfaceFlinger::logFrameStats() {
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        layer->logFrameStats();
-    });
-
-    mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
-}
-
-void SurfaceFlinger::appendSfConfigString(String8& result) const
-{
-    result.append(" [sf");
-    result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
-
-    if (isLayerTripleBufferingDisabled())
-        result.append(" DISABLE_TRIPLE_BUFFERING");
-
-    result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
-    result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
-    result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
-    result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
-    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
-                        maxFrameBufferAcquiredBuffers);
-    result.append("]");
-}
-
-void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
-{
-    result.appendFormat("Static screen stats:\n");
-    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
-        float bucketTimeSec = mFrameBuckets[b] / 1e9;
-        float percent = 100.0f *
-                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
-        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
-                b + 1, bucketTimeSec, percent);
-    }
-    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
-    float percent = 100.0f *
-            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
-    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
-            NUM_BUCKETS - 1, bucketTimeSec, percent);
-}
-
-void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
-    result.appendFormat("Layer frame timestamps:\n");
-
-    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        currentLayers[i]->dumpFrameEvents(result);
-    }
-}
-
-void SurfaceFlinger::recordBufferingStats(const char* layerName,
-        std::vector<OccupancyTracker::Segment>&& history) {
-    Mutex::Autolock lock(mBufferingStatsMutex);
-    auto& stats = mBufferingStats[layerName];
-    for (const auto& segment : history) {
-        if (!segment.usedThirdBuffer) {
-            stats.twoBufferTime += segment.totalTime;
-        }
-        if (segment.occupancyAverage < 1.0f) {
-            stats.doubleBufferedTime += segment.totalTime;
-        } else if (segment.occupancyAverage < 2.0f) {
-            stats.tripleBufferedTime += segment.totalTime;
-        }
-        ++stats.numSegments;
-        stats.totalTime += segment.totalTime;
-    }
-}
-
-void SurfaceFlinger::dumpBufferingStats(String8& result) const {
-    result.append("Buffering stats:\n");
-    result.append("  [Layer name] <Active time> <Two buffer> "
-            "<Double buffered> <Triple buffered>\n");
-    Mutex::Autolock lock(mBufferingStatsMutex);
-    typedef std::tuple<std::string, float, float, float> BufferTuple;
-    std::map<float, BufferTuple, std::greater<float>> sorted;
-    for (const auto& statsPair : mBufferingStats) {
-        const char* name = statsPair.first.c_str();
-        const BufferingStats& stats = statsPair.second;
-        if (stats.numSegments == 0) {
-            continue;
-        }
-        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
-        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
-                stats.totalTime;
-        float doubleBufferRatio = static_cast<float>(
-                stats.doubleBufferedTime) / stats.totalTime;
-        float tripleBufferRatio = static_cast<float>(
-                stats.tripleBufferedTime) / stats.totalTime;
-        sorted.insert({activeTime, {name, twoBufferRatio,
-                doubleBufferRatio, tripleBufferRatio}});
-    }
-    for (const auto& sortedPair : sorted) {
-        float activeTime = sortedPair.first;
-        const BufferTuple& values = sortedPair.second;
-        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
-                std::get<0>(values).c_str(), activeTime,
-                std::get<1>(values), std::get<2>(values),
-                std::get<3>(values));
-    }
-    result.append("\n");
-}
-
-void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const
-{
-    bool colorize = false;
-    if (index < args.size()
-            && (args[index] == String16("--color"))) {
-        colorize = true;
-        index++;
-    }
-
-    Colorizer colorizer(colorize);
-
-    // figure out if we're stuck somewhere
-    const nsecs_t now = systemTime();
-    const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
-    const nsecs_t inTransaction(mDebugInTransaction);
-    nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
-    nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
-
-    /*
-     * Dump library configuration.
-     */
-
-    colorizer.bold(result);
-    result.append("Build configuration:");
-    colorizer.reset(result);
-    appendSfConfigString(result);
-    appendUiConfigString(result);
-    appendGuiConfigString(result);
-    result.append("\n");
-
-    colorizer.bold(result);
-    result.append("Sync configuration: ");
-    colorizer.reset(result);
-    result.append(SyncFeatures::getInstance().toString());
-    result.append("\n");
-
-    colorizer.bold(result);
-    result.append("DispSync configuration: ");
-    colorizer.reset(result);
-    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
-            "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, dispSyncPresentTimeOffset,
-        mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
-    result.append("\n");
-
-    // Dump static screen stats
-    result.append("\n");
-    dumpStaticScreenStats(result);
-    result.append("\n");
-
-    dumpBufferingStats(result);
-
-    /*
-     * Dump the visible layer list
-     */
-    colorizer.bold(result);
-    result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
-    colorizer.reset(result);
-    mCurrentState.traverseInZOrder([&](Layer* layer) {
-        layer->dump(result, colorizer);
-    });
-
-    /*
-     * Dump Display state
-     */
-
-    colorizer.bold(result);
-    result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
-    colorizer.reset(result);
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
-        hw->dump(result);
-    }
-
-    /*
-     * Dump SurfaceFlinger global state
-     */
-
-    colorizer.bold(result);
-    result.append("SurfaceFlinger global state:\n");
-    colorizer.reset(result);
-
-    HWComposer& hwc(getHwComposer());
-    sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
-
-    colorizer.bold(result);
-    result.appendFormat("EGL implementation : %s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
-    colorizer.reset(result);
-    result.appendFormat("%s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
-
-    mRenderEngine->dump(result);
-
-    hw->undefinedRegion.dump(result, "undefinedRegion");
-    result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
-            hw->getOrientation(), hw->isDisplayOn());
-    result.appendFormat(
-            "  last eglSwapBuffers() time: %f us\n"
-            "  last transaction time     : %f us\n"
-            "  transaction-flags         : %08x\n"
-            "  refresh-rate              : %f fps\n"
-            "  x-dpi                     : %f\n"
-            "  y-dpi                     : %f\n"
-            "  gpu_to_cpu_unsupported    : %d\n"
-            ,
-            mLastSwapBufferTime/1000.0,
-            mLastTransactionTime/1000.0,
-            mTransactionFlags,
-            1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
-            hwc.getDpiX(HWC_DISPLAY_PRIMARY),
-            hwc.getDpiY(HWC_DISPLAY_PRIMARY),
-            !mGpuToCpuSupported);
-
-    result.appendFormat("  eglSwapBuffers time: %f us\n",
-            inSwapBuffersDuration/1000.0);
-
-    result.appendFormat("  transaction time: %f us\n",
-            inTransactionDuration/1000.0);
-
-    /*
-     * VSYNC state
-     */
-    mEventThread->dump(result);
-
-    /*
-     * Dump HWComposer state
-     */
-    colorizer.bold(result);
-    result.append("h/w composer state:\n");
-    colorizer.reset(result);
-    result.appendFormat("  h/w composer %s and %s\n",
-            hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                    (mDebugDisableHWC || mDebugRegion || mDaltonize
-                            || mHasColorMatrix) ? "disabled" : "enabled");
-    hwc.dump(result);
-
-    /*
-     * Dump gralloc state
-     */
-    const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
-    alloc.dump(result);
-}
-
-const Vector< sp<Layer> >&
-SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
-    // Note: mStateLock is held here
-    wp<IBinder> dpy;
-    for (size_t i=0 ; i<mDisplays.size() ; i++) {
-        if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
-            dpy = mDisplays.keyAt(i);
-            break;
-        }
-    }
-    if (dpy == NULL) {
-        ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
-        // Just use the primary display so we have something to return
-        dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
-    }
-    return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ();
-}
-
-bool SurfaceFlinger::startDdmConnection()
-{
-    void* libddmconnection_dso =
-            dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
-    if (!libddmconnection_dso) {
-        return false;
-    }
-    void (*DdmConnection_start)(const char* name);
-    DdmConnection_start =
-            (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
-    if (!DdmConnection_start) {
-        dlclose(libddmconnection_dso);
-        return false;
-    }
-    (*DdmConnection_start)(getServiceName());
-    return true;
-}
-
-status_t SurfaceFlinger::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case CREATE_CONNECTION:
-        case CREATE_DISPLAY:
-        case BOOT_FINISHED:
-        case CLEAR_ANIMATION_FRAME_STATS:
-        case GET_ANIMATION_FRAME_STATS:
-        case SET_POWER_MODE:
-        case GET_HDR_CAPABILITIES:
-        {
-            // codes that require permission check
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
-                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
-                ALOGE("Permission Denial: "
-                        "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            break;
-        }
-        /*
-         * Calling setTransactionState is safe, because you need to have been
-         * granted a reference to Client* and Handle* to do anything with it.
-         *
-         * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
-         */
-        case SET_TRANSACTION_STATE:
-        case CREATE_SCOPED_CONNECTION:
-        {
-            break;
-        }
-        case CAPTURE_SCREEN:
-        {
-            // codes that require permission check
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) &&
-                    !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
-                ALOGE("Permission Denial: "
-                        "can't read framebuffer pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            break;
-        }
-    }
-
-    status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
-    if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
-        CHECK_INTERFACE(ISurfaceComposer, data, reply);
-        if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            ALOGE("Permission Denial: "
-                    "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
-            return PERMISSION_DENIED;
-        }
-        int n;
-        switch (code) {
-            case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
-            case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
-                return NO_ERROR;
-            case 1002:  // SHOW_UPDATES
-                n = data.readInt32();
-                mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
-                invalidateHwcGeometry();
-                repaintEverything();
-                return NO_ERROR;
-            case 1004:{ // repaint everything
-                repaintEverything();
-                return NO_ERROR;
-            }
-            case 1005:{ // force transaction
-                setTransactionFlags(
-                        eTransactionNeeded|
-                        eDisplayTransactionNeeded|
-                        eTraversalNeeded);
-                return NO_ERROR;
-            }
-            case 1006:{ // send empty update
-                signalRefresh();
-                return NO_ERROR;
-            }
-            case 1008:  // toggle use of hw composer
-                n = data.readInt32();
-                mDebugDisableHWC = n ? 1 : 0;
-                invalidateHwcGeometry();
-                repaintEverything();
-                return NO_ERROR;
-            case 1009:  // toggle use of transform hint
-                n = data.readInt32();
-                mDebugDisableTransformHint = n ? 1 : 0;
-                invalidateHwcGeometry();
-                repaintEverything();
-                return NO_ERROR;
-            case 1010:  // interrogate.
-                reply->writeInt32(0);
-                reply->writeInt32(0);
-                reply->writeInt32(mDebugRegion);
-                reply->writeInt32(0);
-                reply->writeInt32(mDebugDisableHWC);
-                return NO_ERROR;
-            case 1013: {
-                Mutex::Autolock _l(mStateLock);
-                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-                reply->writeInt32(hw->getPageFlipCount());
-                return NO_ERROR;
-            }
-            case 1014: {
-                // daltonize
-                n = data.readInt32();
-                switch (n % 10) {
-                    case 1:
-                        mDaltonizer.setType(ColorBlindnessType::Protanomaly);
-                        break;
-                    case 2:
-                        mDaltonizer.setType(ColorBlindnessType::Deuteranomaly);
-                        break;
-                    case 3:
-                        mDaltonizer.setType(ColorBlindnessType::Tritanomaly);
-                        break;
-                }
-                if (n >= 10) {
-                    mDaltonizer.setMode(ColorBlindnessMode::Correction);
-                } else {
-                    mDaltonizer.setMode(ColorBlindnessMode::Simulation);
-                }
-                mDaltonize = n > 0;
-                invalidateHwcGeometry();
-                repaintEverything();
-                return NO_ERROR;
-            }
-            case 1015: {
-                // apply a color matrix
-                n = data.readInt32();
-                mHasColorMatrix = n ? 1 : 0;
-                if (n) {
-                    // color matrix is sent as mat3 matrix followed by vec3
-                    // offset, then packed into a mat4 where the last row is
-                    // the offset and extra values are 0
-                    for (size_t i = 0 ; i < 4; i++) {
-                      for (size_t j = 0; j < 4; j++) {
-                          mColorMatrix[i][j] = data.readFloat();
-                      }
-                    }
-                } else {
-                    mColorMatrix = mat4();
-                }
-                invalidateHwcGeometry();
-                repaintEverything();
-                return NO_ERROR;
-            }
-            // This is an experimental interface
-            // Needs to be shifted to proper binder interface when we productize
-            case 1016: {
-                n = data.readInt32();
-                mPrimaryDispSync.setRefreshSkipCount(n);
-                return NO_ERROR;
-            }
-            case 1017: {
-                n = data.readInt32();
-                mForceFullDamage = static_cast<bool>(n);
-                return NO_ERROR;
-            }
-            case 1018: { // Modify Choreographer's phase offset
-                n = data.readInt32();
-                mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
-                return NO_ERROR;
-            }
-            case 1019: { // Modify SurfaceFlinger's phase offset
-                n = data.readInt32();
-                mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
-                return NO_ERROR;
-            }
-            case 1020: { // Layer updates interceptor
-                n = data.readInt32();
-                if (n) {
-                    ALOGV("Interceptor enabled");
-                    mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
-                }
-                else{
-                    ALOGV("Interceptor disabled");
-                    mInterceptor.disable();
-                }
-                return NO_ERROR;
-            }
-            case 1021: { // Disable HWC virtual displays
-                n = data.readInt32();
-                mUseHwcVirtualDisplays = !n;
-                return NO_ERROR;
-            }
-        }
-    }
-    return err;
-}
-
-void SurfaceFlinger::repaintEverything() {
-    android_atomic_or(1, &mRepaintEverything);
-    signalTransaction();
-}
-
-// ---------------------------------------------------------------------------
-// Capture screen into an IGraphiBufferProducer
-// ---------------------------------------------------------------------------
-
-/* The code below is here to handle b/8734824
- *
- * We create a IGraphicBufferProducer wrapper that forwards all calls
- * from the surfaceflinger thread to the calling binder thread, where they
- * are executed. This allows the calling thread in the calling process to be
- * reused and not depend on having "enough" binder threads to handle the
- * requests.
- */
-class GraphicProducerWrapper : public BBinder, public MessageHandler {
-    /* Parts of GraphicProducerWrapper are run on two different threads,
-     * communicating by sending messages via Looper but also by shared member
-     * data. Coherence maintenance is subtle and in places implicit (ugh).
-     *
-     * Don't rely on Looper's sendMessage/handleMessage providing
-     * release/acquire semantics for any data not actually in the Message.
-     * Data going from surfaceflinger to binder threads needs to be
-     * synchronized explicitly.
-     *
-     * Barrier open/wait do provide release/acquire semantics. This provides
-     * implicit synchronization for data coming back from binder to
-     * surfaceflinger threads.
-     */
-
-    sp<IGraphicBufferProducer> impl;
-    sp<Looper> looper;
-    status_t result;
-    bool exitPending;
-    bool exitRequested;
-    Barrier barrier;
-    uint32_t code;
-    Parcel const* data;
-    Parcel* reply;
-
-    enum {
-        MSG_API_CALL,
-        MSG_EXIT
-    };
-
-    /*
-     * Called on surfaceflinger thread. This is called by our "fake"
-     * BpGraphicBufferProducer. We package the data and reply Parcel and
-     * forward them to the binder thread.
-     */
-    virtual status_t transact(uint32_t code,
-            const Parcel& data, Parcel* reply, uint32_t /* flags */) {
-        this->code = code;
-        this->data = &data;
-        this->reply = reply;
-        if (exitPending) {
-            // if we've exited, we run the message synchronously right here.
-            // note (JH): as far as I can tell from looking at the code, this
-            // never actually happens. if it does, i'm not sure if it happens
-            // on the surfaceflinger or binder thread.
-            handleMessage(Message(MSG_API_CALL));
-        } else {
-            barrier.close();
-            // Prevent stores to this->{code, data, reply} from being
-            // reordered later than the construction of Message.
-            atomic_thread_fence(memory_order_release);
-            looper->sendMessage(this, Message(MSG_API_CALL));
-            barrier.wait();
-        }
-        return result;
-    }
-
-    /*
-     * here we run on the binder thread. All we've got to do is
-     * call the real BpGraphicBufferProducer.
-     */
-    virtual void handleMessage(const Message& message) {
-        int what = message.what;
-        // Prevent reads below from happening before the read from Message
-        atomic_thread_fence(memory_order_acquire);
-        if (what == MSG_API_CALL) {
-            result = IInterface::asBinder(impl)->transact(code, data[0], reply);
-            barrier.open();
-        } else if (what == MSG_EXIT) {
-            exitRequested = true;
-        }
-    }
-
-public:
-    explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
-    :   impl(impl),
-        looper(new Looper(true)),
-        result(NO_ERROR),
-        exitPending(false),
-        exitRequested(false),
-        code(0),
-        data(NULL),
-        reply(NULL)
-    {}
-
-    // Binder thread
-    status_t waitForResponse() {
-        do {
-            looper->pollOnce(-1);
-        } while (!exitRequested);
-        return result;
-    }
-
-    // Client thread
-    void exit(status_t result) {
-        this->result = result;
-        exitPending = true;
-        // Ensure this->result is visible to the binder thread before it
-        // handles the message.
-        atomic_thread_fence(memory_order_release);
-        looper->sendMessage(this, Message(MSG_EXIT));
-    }
-};
-
-
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
-
-    if (CC_UNLIKELY(display == 0))
-        return BAD_VALUE;
-
-    if (CC_UNLIKELY(producer == 0))
-        return BAD_VALUE;
-
-    // if we have secure windows on this display, never allow the screen capture
-    // unless the producer interface is local (i.e.: we can take a screenshot for
-    // ourselves).
-    bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
-
-    // Convert to surfaceflinger's internal rotation type.
-    Transform::orientation_flags rotationFlags;
-    switch (rotation) {
-        case ISurfaceComposer::eRotateNone:
-            rotationFlags = Transform::ROT_0;
-            break;
-        case ISurfaceComposer::eRotate90:
-            rotationFlags = Transform::ROT_90;
-            break;
-        case ISurfaceComposer::eRotate180:
-            rotationFlags = Transform::ROT_180;
-            break;
-        case ISurfaceComposer::eRotate270:
-            rotationFlags = Transform::ROT_270;
-            break;
-        default:
-            rotationFlags = Transform::ROT_0;
-            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
-            break;
-    }
-
-    class MessageCaptureScreen : public MessageBase {
-        SurfaceFlinger* flinger;
-        sp<IBinder> display;
-        sp<IGraphicBufferProducer> producer;
-        Rect sourceCrop;
-        uint32_t reqWidth, reqHeight;
-        int32_t minLayerZ,maxLayerZ;
-        bool useIdentityTransform;
-        Transform::orientation_flags rotation;
-        status_t result;
-        bool isLocalScreenshot;
-    public:
-        MessageCaptureScreen(SurfaceFlinger* flinger,
-                const sp<IBinder>& display,
-                const sp<IGraphicBufferProducer>& producer,
-                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                int32_t minLayerZ, int32_t maxLayerZ,
-                bool useIdentityTransform,
-                Transform::orientation_flags rotation,
-                bool isLocalScreenshot)
-            : flinger(flinger), display(display), producer(producer),
-              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
-              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
-              useIdentityTransform(useIdentityTransform),
-              rotation(rotation), result(PERMISSION_DENIED),
-              isLocalScreenshot(isLocalScreenshot)
-        {
-        }
-        status_t getResult() const {
-            return result;
-        }
-        virtual bool handler() {
-            Mutex::Autolock _l(flinger->mStateLock);
-            sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
-            result = flinger->captureScreenImplLocked(hw, producer,
-                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform, rotation, isLocalScreenshot);
-            static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
-            return true;
-        }
-    };
-
-    // this creates a "fake" BBinder which will serve as a "fake" remote
-    // binder to receive the marshaled calls and forward them to the
-    // real remote (a BpGraphicBufferProducer)
-    sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
-
-    // the asInterface() call below creates our "fake" BpGraphicBufferProducer
-    // which does the marshaling work forwards to our "fake remote" above.
-    sp<MessageBase> msg = new MessageCaptureScreen(this,
-            display, IGraphicBufferProducer::asInterface( wrapper ),
-            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-            useIdentityTransform, rotationFlags, isLocalScreenshot);
-
-    status_t res = postMessageAsync(msg);
-    if (res == NO_ERROR) {
-        res = wrapper->waitForResponse();
-    }
-    return res;
-}
-
-
-void SurfaceFlinger::renderScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
-{
-    ATRACE_CALL();
-    RenderEngine& engine(getRenderEngine());
-
-    // get screen geometry
-    const int32_t hw_w = hw->getWidth();
-    const int32_t hw_h = hw->getHeight();
-    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
-                           static_cast<int32_t>(reqHeight) != hw_h;
-
-    // if a default or invalid sourceCrop is passed in, set reasonable values
-    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
-            !sourceCrop.isValid()) {
-        sourceCrop.setLeftTop(Point(0, 0));
-        sourceCrop.setRightBottom(Point(hw_w, hw_h));
-    }
-
-    // ensure that sourceCrop is inside screen
-    if (sourceCrop.left < 0) {
-        ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
-    }
-    if (sourceCrop.right > hw_w) {
-        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
-    }
-    if (sourceCrop.top < 0) {
-        ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
-    }
-    if (sourceCrop.bottom > hw_h) {
-        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
-    }
-
-    // make sure to clear all GL error flags
-    engine.checkErrors();
-
-    // set-up our viewport
-    engine.setViewportAndProjection(
-        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
-    engine.disableTexturing();
-
-    // redraw the screen entirely...
-    engine.clearWithColor(0, 0, 0, 1);
-
-    // We loop through the first level of layers without traversing,
-    // as we need to interpret min/max layer Z in the top level Z space.
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (layer->getLayerStack() != hw->getLayerStack()) {
-            continue;
-        }
-        const Layer::State& state(layer->getDrawingState());
-        if (state.z < minLayerZ || state.z > maxLayerZ) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->isVisible()) {
-                return;
-            }
-            if (filtering) layer->setFiltering(true);
-            layer->draw(hw, useIdentityTransform);
-            if (filtering) layer->setFiltering(false);
-        });
-    }
-
-    // compositionComplete is needed for older driver
-    hw->compositionComplete();
-    hw->setViewportAndProjection();
-}
-
-
-status_t SurfaceFlinger::captureScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, Transform::orientation_flags rotation,
-        bool isLocalScreenshot)
-{
-    ATRACE_CALL();
-
-    // get screen geometry
-    uint32_t hw_w = hw->getWidth();
-    uint32_t hw_h = hw->getHeight();
-
-    if (rotation & Transform::ROT_90) {
-        std::swap(hw_w, hw_h);
-    }
-
-    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
-        ALOGE("size mismatch (%d, %d) > (%d, %d)",
-                reqWidth, reqHeight, hw_w, hw_h);
-        return BAD_VALUE;
-    }
-
-    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
-    reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
-    bool secureLayerIsVisible = false;
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        const Layer::State& state(layer->getDrawingState());
-        if ((layer->getLayerStack() != hw->getLayerStack()) ||
-                (state.z < minLayerZ || state.z > maxLayerZ)) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
-            secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
-                    layer->isSecure());
-        });
-    }
-
-    if (!isLocalScreenshot && secureLayerIsVisible) {
-        ALOGW("FB is protected: PERMISSION_DENIED");
-        return PERMISSION_DENIED;
-    }
-
-    // create a surface (because we're a producer, and we need to
-    // dequeue/queue a buffer)
-    sp<Surface> sur = new Surface(producer, false);
-    ANativeWindow* window = sur.get();
-
-    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-    if (result == NO_ERROR) {
-        uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-                        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-
-        int err = 0;
-        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
-        err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
-        err |= native_window_set_usage(window, usage);
-
-        if (err == NO_ERROR) {
-            ANativeWindowBuffer* buffer;
-            /* TODO: Once we have the sync framework everywhere this can use
-             * server-side waits on the fence that dequeueBuffer returns.
-             */
-            result = native_window_dequeue_buffer_and_wait(window,  &buffer);
-            if (result == NO_ERROR) {
-                int syncFd = -1;
-                // create an EGLImage from the buffer so we can later
-                // turn it into a texture
-                EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
-                        EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
-                if (image != EGL_NO_IMAGE_KHR) {
-                    // this binds the given EGLImage as a framebuffer for the
-                    // duration of this scope.
-                    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
-                    if (imageBond.getStatus() == NO_ERROR) {
-                        // this will in fact render into our dequeued buffer
-                        // via an FBO, which means we didn't have to create
-                        // an EGLSurface and therefore we're not
-                        // dependent on the context's EGLConfig.
-                        renderScreenImplLocked(
-                            hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
-                            useIdentityTransform, rotation);
-
-                        // Attempt to create a sync khr object that can produce a sync point. If that
-                        // isn't available, create a non-dupable sync object in the fallback path and
-                        // wait on it directly.
-                        EGLSyncKHR sync;
-                        if (!DEBUG_SCREENSHOTS) {
-                           sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
-                           // native fence fd will not be populated until flush() is done.
-                           getRenderEngine().flush();
-                        } else {
-                            sync = EGL_NO_SYNC_KHR;
-                        }
-                        if (sync != EGL_NO_SYNC_KHR) {
-                            // get the sync fd
-                            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
-                            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-                                ALOGW("captureScreen: failed to dup sync khr object");
-                                syncFd = -1;
-                            }
-                            eglDestroySyncKHR(mEGLDisplay, sync);
-                        } else {
-                            // fallback path
-                            sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-                            if (sync != EGL_NO_SYNC_KHR) {
-                                EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
-                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
-                                EGLint eglErr = eglGetError();
-                                if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                                    ALOGW("captureScreen: fence wait timed out");
-                                } else {
-                                    ALOGW_IF(eglErr != EGL_SUCCESS,
-                                            "captureScreen: error waiting on EGL fence: %#x", eglErr);
-                                }
-                                eglDestroySyncKHR(mEGLDisplay, sync);
-                            } else {
-                                ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
-                            }
-                        }
-                        if (DEBUG_SCREENSHOTS) {
-                            uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
-                            getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
-                            checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
-                                    hw, minLayerZ, maxLayerZ);
-                            delete [] pixels;
-                        }
-
-                    } else {
-                        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
-                        result = INVALID_OPERATION;
-                        window->cancelBuffer(window, buffer, syncFd);
-                        buffer = NULL;
-                    }
-                    // destroy our image
-                    eglDestroyImageKHR(mEGLDisplay, image);
-                } else {
-                    result = BAD_VALUE;
-                }
-                if (buffer) {
-                    // queueBuffer takes ownership of syncFd
-                    result = window->queueBuffer(window, buffer, syncFd);
-                }
-            }
-        } else {
-            result = BAD_VALUE;
-        }
-        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-    }
-
-    return result;
-}
-
-void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-        const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
-    if (DEBUG_SCREENSHOTS) {
-        for (size_t y=0 ; y<h ; y++) {
-            uint32_t const * p = (uint32_t const *)vaddr + y*s;
-            for (size_t x=0 ; x<w ; x++) {
-                if (p[x] != 0xFF000000) return;
-            }
-        }
-        ALOGE("*** we just took a black screenshot ***\n"
-                "requested minz=%d, maxz=%d, layerStack=%d",
-                minLayerZ, maxLayerZ, hw->getLayerStack());
-        size_t i = 0;
-        for (const auto& layer : mDrawingState.layersSortedByZ) {
-            const Layer::State& state(layer->getDrawingState());
-            if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
-                    state.z <= maxLayerZ) {
-                layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
-                            layer->isVisible() ? '+' : '-',
-                            i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, state.alpha);
-                    i++;
-                });
-            }
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
-    layersSortedByZ.traverseInZOrder(stateSet, visitor);
-}
-
-void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& visitor) const {
-    layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
-}
-
-}; // namespace android
-
-
-#if defined(__gl_h_)
-#error "don't include gl/gl.h in this file"
-#endif
-
-#if defined(__gl2_h_)
-#error "don't include gl2/gl2.h in this file"
-#endif
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index db489b2..4596a21 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -31,6 +31,10 @@
 
 // ----------------------------------------------------------------------------
 
+SurfaceInterceptor::~SurfaceInterceptor() = default;
+
+namespace impl {
+
 SurfaceInterceptor::SurfaceInterceptor(SurfaceFlinger* flinger)
     :   mFlinger(flinger)
 {
@@ -98,7 +102,7 @@
     addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
             layer->mCurrentState.active.transform.ty());
     addDepthLocked(transaction, layerId, layer->mCurrentState.z);
-    addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha);
+    addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
     addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
     addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
     addCropLocked(transaction, layerId, layer->mCurrentState.crop);
@@ -593,5 +597,5 @@
     addPowerModeUpdateLocked(createTraceIncrementLocked(), displayId, mode);
 }
 
-
+} // namespace impl
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 30ebcc6..96defcc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -21,48 +21,89 @@
 
 #include <mutex>
 
+#include <gui/LayerState.h>
+
+#include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
+#include "DisplayDevice.h"
+
 namespace android {
 
 class BufferItem;
 class Layer;
 class SurfaceFlinger;
+struct ComposerState;
+struct DisplayDeviceState;
 struct DisplayState;
 struct layer_state_t;
 
 constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
 
+class SurfaceInterceptor {
+public:
+    virtual ~SurfaceInterceptor();
+
+    // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
+    virtual void enable(const SortedVector<sp<Layer>>& layers,
+                        const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) = 0;
+    virtual void disable() = 0;
+    virtual bool isEnabled() = 0;
+
+    // Intercept display and surface transactions
+    virtual void saveTransaction(
+            const Vector<ComposerState>& stateUpdates,
+            const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+            const Vector<DisplayState>& changedDisplays, uint32_t flags) = 0;
+
+    // Intercept surface data
+    virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
+    virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0;
+    virtual void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+                                  uint64_t frameNumber) = 0;
+
+    // Intercept display data
+    virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0;
+    virtual void saveDisplayDeletion(int32_t displayId) = 0;
+    virtual void savePowerModeUpdate(int32_t displayId, int32_t mode) = 0;
+    virtual void saveVSyncEvent(nsecs_t timestamp) = 0;
+};
+
+namespace impl {
+
 /*
  * SurfaceInterceptor intercepts and stores incoming streams of window
  * properties on SurfaceFlinger.
  */
-class SurfaceInterceptor {
+class SurfaceInterceptor final : public android::SurfaceInterceptor {
 public:
-    SurfaceInterceptor(SurfaceFlinger* const flinger);
+    explicit SurfaceInterceptor(SurfaceFlinger* const flinger);
+    ~SurfaceInterceptor() override = default;
+
     // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
     void enable(const SortedVector<sp<Layer>>& layers,
-            const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays);
-    void disable();
-    bool isEnabled();
+                const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) override;
+    void disable() override;
+    bool isEnabled() override;
 
     // Intercept display and surface transactions
     void saveTransaction(const Vector<ComposerState>& stateUpdates,
-            const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
-            const Vector<DisplayState>& changedDisplays, uint32_t flags);
+                         const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+                         const Vector<DisplayState>& changedDisplays, uint32_t flags) override;
 
     // Intercept surface data
-    void saveSurfaceCreation(const sp<const Layer>& layer);
-    void saveSurfaceDeletion(const sp<const Layer>& layer);
+    void saveSurfaceCreation(const sp<const Layer>& layer) override;
+    void saveSurfaceDeletion(const sp<const Layer>& layer) override;
     void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
-            uint64_t frameNumber);
+                          uint64_t frameNumber) override;
 
     // Intercept display data
-    void saveDisplayCreation(const DisplayDeviceState& info);
-    void saveDisplayDeletion(int32_t displayId);
-    void savePowerModeUpdate(int32_t displayId, int32_t mode);
-    void saveVSyncEvent(nsecs_t timestamp);
+    void saveDisplayCreation(const DisplayDeviceState& info) override;
+    void saveDisplayDeletion(int32_t displayId) override;
+    void savePowerModeUpdate(int32_t displayId, int32_t mode) override;
+    void saveVSyncEvent(nsecs_t timestamp) override;
 
 private:
     // The creation increments of Surfaces and Displays do not contain enough information to capture
@@ -134,6 +175,7 @@
     SurfaceFlinger* const mFlinger;
 };
 
-}
+} // namespace impl
+} // namespace android
 
 #endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
new file mode 100644
index 0000000..67dcd06
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "SurfaceTracing"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SurfaceTracing.h"
+
+#include <android-base/file.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void SurfaceTracing::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+
+    if (mEnabled) {
+        return;
+    }
+    mEnabled = true;
+
+    mTrace = std::make_unique<LayersTraceFileProto>();
+    mTrace->set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
+                             LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+}
+
+status_t SurfaceTracing::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+
+    if (!mEnabled) {
+        return NO_ERROR;
+    }
+    mEnabled = false;
+    status_t err(writeProtoFileLocked());
+    ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
+    ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
+    mTrace.reset();
+    return err;
+}
+
+bool SurfaceTracing::isEnabled() const {
+    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    return mEnabled;
+}
+
+void SurfaceTracing::traceLayers(const char* where, LayersProto layers) {
+    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    if (!mEnabled) {
+        return;
+    }
+    LayersTraceProto* entry = mTrace->add_entry();
+    entry->set_elapsed_realtime_nanos(elapsedRealtimeNano());
+    entry->set_where(where);
+    entry->mutable_layers()->Swap(&layers);
+
+    constexpr int maxBufferedEntryCount = 3600;
+    if (mTrace->entry_size() >= maxBufferedEntryCount) {
+        // TODO: flush buffered entries without disabling tracing
+        ALOGE("too many buffered frames; force disable tracing");
+        mEnabled = false;
+        writeProtoFileLocked();
+        mTrace.reset();
+    }
+}
+
+status_t SurfaceTracing::writeProtoFileLocked() {
+    ATRACE_CALL();
+
+    if (!mTrace->IsInitialized()) {
+        return NOT_ENOUGH_DATA;
+    }
+    std::string output;
+    if (!mTrace->SerializeToString(&output)) {
+        return PERMISSION_DENIED;
+    }
+    if (!android::base::WriteStringToFile(output, mOutputFileName, true)) {
+        return PERMISSION_DENIED;
+    }
+
+    return NO_ERROR;
+}
+
+void SurfaceTracing::dump(String8& result) const {
+    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+
+    result.appendFormat("Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+    result.appendFormat("  number of entries: %d\n", mTrace ? mTrace->entry_size() : 0);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
new file mode 100644
index 0000000..fd8cb82
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+#include <memory>
+#include <mutex>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+/*
+ * SurfaceTracing records layer states during surface flinging.
+ */
+class SurfaceTracing {
+public:
+    void enable();
+    status_t disable();
+    bool isEnabled() const;
+
+    void traceLayers(const char* where, LayersProto);
+    void dump(String8& result) const;
+
+private:
+    static constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/layers_trace.pb";
+
+    status_t writeProtoFileLocked();
+
+    bool mEnabled = false;
+    std::string mOutputFileName = DEFAULT_FILENAME;
+    mutable std::mutex mTraceMutex;
+    std::unique_ptr<LayersTraceFileProto> mTrace;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
new file mode 100644
index 0000000..d4f1e29
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef LOG_TAG
+#define LOG_TAG "TimeStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TimeStats.h"
+
+#include <android-base/stringprintf.h>
+
+#include <log/log.h>
+
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <algorithm>
+#include <regex>
+
+namespace android {
+
+TimeStats& TimeStats::getInstance() {
+    static std::unique_ptr<TimeStats> sInstance;
+    static std::once_flag sOnceFlag;
+
+    std::call_once(sOnceFlag, [] { sInstance.reset(new TimeStats); });
+    return *sInstance.get();
+}
+
+void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
+                          String8& result) {
+    ATRACE_CALL();
+
+    if (args.size() > index + 10) {
+        ALOGD("Invalid args count");
+        return;
+    }
+
+    std::unordered_map<std::string, int32_t> argsMap;
+    while (index < args.size()) {
+        argsMap[std::string(String8(args[index]).c_str())] = index;
+        ++index;
+    }
+
+    if (argsMap.count("-disable")) {
+        disable();
+    }
+
+    if (argsMap.count("-dump")) {
+        std::optional<uint32_t> maxLayers = std::nullopt;
+        auto iter = argsMap.find("-maxlayers");
+        if (iter != argsMap.end() && iter->second + 1 < static_cast<int32_t>(args.size())) {
+            int64_t value = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
+            value = std::clamp(value, int64_t(0), int64_t(UINT32_MAX));
+            maxLayers = static_cast<uint32_t>(value);
+        }
+
+        dump(asProto, maxLayers, result);
+    }
+
+    if (argsMap.count("-clear")) {
+        clear();
+    }
+
+    if (argsMap.count("-enable")) {
+        enable();
+    }
+}
+
+void TimeStats::incrementTotalFrames() {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    timeStats.totalFrames++;
+}
+
+void TimeStats::incrementMissedFrames() {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    timeStats.missedFrames++;
+}
+
+void TimeStats::incrementClientCompositionFrames() {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    timeStats.clientCompositionFrames++;
+}
+
+bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
+    if (!timeRecord->ready) {
+        ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
+              timeRecord->frameNumber);
+        return false;
+    }
+
+    if (timeRecord->acquireFence != nullptr) {
+        if (timeRecord->acquireFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+            return false;
+        }
+        if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
+            timeRecord->acquireTime = timeRecord->acquireFence->getSignalTime();
+            timeRecord->acquireFence = nullptr;
+        } else {
+            ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
+                  timeRecord->frameNumber);
+        }
+    }
+
+    if (timeRecord->presentFence != nullptr) {
+        if (timeRecord->presentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+            return false;
+        }
+        if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
+            timeRecord->presentTime = timeRecord->presentFence->getSignalTime();
+            timeRecord->presentFence = nullptr;
+        } else {
+            ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
+                  timeRecord->frameNumber);
+        }
+    }
+
+    return true;
+}
+
+static int32_t msBetween(nsecs_t start, nsecs_t end) {
+    int64_t delta = (end - start) / 1000000;
+    delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
+    return static_cast<int32_t>(delta);
+}
+
+static std::string getPackageName(const std::string& layerName) {
+    // This regular expression captures the following for instance:
+    // StatusBar in StatusBar#0
+    // com.appname in com.appname/com.appname.activity#0
+    // com.appname in SurfaceView - com.appname/com.appname.activity#0
+    const std::regex re("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
+    std::smatch match;
+    if (std::regex_match(layerName.begin(), layerName.end(), match, re)) {
+        // There must be a match for group 1 otherwise the whole string is not
+        // matched and the above will return false
+        return match[1];
+    }
+    return "";
+}
+
+void TimeStats::flushAvailableRecordsToStatsLocked(const std::string& layerName) {
+    ATRACE_CALL();
+
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
+    std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
+    while (!timeRecords.empty()) {
+        if (!recordReadyLocked(layerName, &timeRecords[0])) break;
+        ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
+              timeRecords[0].frameNumber, timeRecords[0].presentTime);
+
+        if (prevTimeRecord.ready) {
+            if (!timeStats.stats.count(layerName)) {
+                timeStats.stats[layerName].layerName = layerName;
+                timeStats.stats[layerName].packageName = getPackageName(layerName);
+                timeStats.stats[layerName].statsStart = static_cast<int64_t>(std::time(0));
+            }
+            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
+            timeStatsLayer.totalFrames++;
+
+            const int32_t postToPresentMs =
+                    msBetween(timeRecords[0].postTime, timeRecords[0].presentTime);
+            ALOGV("[%s]-[%" PRIu64 "]-post2present[%d]", layerName.c_str(),
+                  timeRecords[0].frameNumber, postToPresentMs);
+            timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
+
+            const int32_t acquireToPresentMs =
+                    msBetween(timeRecords[0].acquireTime, timeRecords[0].presentTime);
+            ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
+                  timeRecords[0].frameNumber, acquireToPresentMs);
+            timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
+
+            const int32_t latchToPresentMs =
+                    msBetween(timeRecords[0].latchTime, timeRecords[0].presentTime);
+            ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
+                  timeRecords[0].frameNumber, latchToPresentMs);
+            timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
+
+            const int32_t desiredToPresentMs =
+                    msBetween(timeRecords[0].desiredTime, timeRecords[0].presentTime);
+            ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
+                  timeRecords[0].frameNumber, desiredToPresentMs);
+            timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
+
+            const int32_t presentToPresentMs =
+                    msBetween(prevTimeRecord.presentTime, timeRecords[0].presentTime);
+            ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
+                  timeRecords[0].frameNumber, presentToPresentMs);
+            timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
+
+            timeStats.stats[layerName].statsEnd = static_cast<int64_t>(std::time(0));
+        }
+        prevTimeRecord = timeRecords[0];
+        timeRecords.pop_front();
+        layerRecord.waitData--;
+    }
+}
+
+static bool layerNameIsValid(const std::string& layerName) {
+    // This regular expression captures the following layer names for instance:
+    // 1) StatusBat#0
+    // 2) NavigationBar#1
+    // 3) com.*#0
+    // 4) SurfaceView - com.*#0
+    // Using [-\\s\t]+ for the conjunction part between SurfaceView and com.* is
+    // a bit more robust in case there's a slight change.
+    // The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
+    std::regex re("(((SurfaceView[-\\s\\t]+)?com\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
+    return std::regex_match(layerName.begin(), layerName.end(), re);
+}
+
+void TimeStats::setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerName.c_str(), frameNumber, postTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName) && !layerNameIsValid(layerName)) {
+        return;
+    }
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
+        ALOGV("[%s]-timeRecords is already at its maximum size[%zu]", layerName.c_str(),
+              MAX_NUM_TIME_RECORDS);
+        // TODO(zzyiwei): if this happens, there must be a present fence missing
+        // or waitData is not in the correct position. Need to think out a
+        // reasonable way to recover from this state.
+        return;
+    }
+    // For most media content, the acquireFence is invalid because the buffer is
+    // ready at the queueBuffer stage. In this case, acquireTime should be given
+    // a default value as postTime.
+    TimeRecord timeRecord = {
+            .frameNumber = frameNumber,
+            .postTime = postTime,
+            .acquireTime = postTime,
+    };
+    layerRecord.timeRecords.push_back(timeRecord);
+    if (layerRecord.waitData < 0 ||
+        layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
+        layerRecord.waitData = layerRecord.timeRecords.size() - 1;
+}
+
+void TimeStats::setLatchTime(const std::string& layerName, uint64_t frameNumber,
+                             nsecs_t latchTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerName.c_str(), frameNumber, latchTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.latchTime = latchTime;
+    }
+}
+
+void TimeStats::setDesiredTime(const std::string& layerName, uint64_t frameNumber,
+                               nsecs_t desiredTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+          desiredTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.desiredTime = desiredTime;
+    }
+}
+
+void TimeStats::setAcquireTime(const std::string& layerName, uint64_t frameNumber,
+                               nsecs_t acquireTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+          acquireTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.acquireTime = acquireTime;
+    }
+}
+
+void TimeStats::setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+                                const std::shared_ptr<FenceTime>& acquireFence) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+          acquireFence->getSignalTime());
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.acquireFence = acquireFence;
+    }
+}
+
+void TimeStats::setPresentTime(const std::string& layerName, uint64_t frameNumber,
+                               nsecs_t presentTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+          presentTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.presentTime = presentTime;
+        timeRecord.ready = true;
+        layerRecord.waitData++;
+    }
+
+    flushAvailableRecordsToStatsLocked(layerName);
+}
+
+void TimeStats::setPresentFence(const std::string& layerName, uint64_t frameNumber,
+                                const std::shared_ptr<FenceTime>& presentFence) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+          presentFence->getSignalTime());
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
+    if (timeRecord.frameNumber == frameNumber) {
+        timeRecord.presentFence = presentFence;
+        timeRecord.ready = true;
+        layerRecord.waitData++;
+    }
+
+    flushAvailableRecordsToStatsLocked(layerName);
+}
+
+void TimeStats::onDisconnect(const std::string& layerName) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-onDisconnect", layerName.c_str());
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    flushAvailableRecordsToStatsLocked(layerName);
+    timeStatsTracker.erase(layerName);
+}
+
+void TimeStats::clearLayerRecord(const std::string& layerName) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-clearLayerRecord", layerName.c_str());
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    layerRecord.timeRecords.clear();
+    layerRecord.prevTimeRecord.ready = false;
+    layerRecord.waitData = -1;
+}
+
+void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%s]-[%" PRIu64 "]-removeTimeRecord", layerName.c_str(), frameNumber);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!timeStatsTracker.count(layerName)) return;
+    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    size_t removeAt = 0;
+    for (const TimeRecord& record : layerRecord.timeRecords) {
+        if (record.frameNumber == frameNumber) break;
+        removeAt++;
+    }
+    if (removeAt == layerRecord.timeRecords.size()) return;
+    layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
+    if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
+        --layerRecord.waitData;
+    }
+}
+
+void TimeStats::enable() {
+    if (mEnabled.load()) return;
+
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Enabled");
+    mEnabled.store(true);
+    timeStats.statsStart = static_cast<int64_t>(std::time(0));
+}
+
+void TimeStats::disable() {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Disabled");
+    mEnabled.store(false);
+    timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+}
+
+void TimeStats::clear() {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Cleared");
+    timeStats.stats.clear();
+    timeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+    timeStats.statsEnd = 0;
+    timeStats.totalFrames = 0;
+    timeStats.missedFrames = 0;
+    timeStats.clientCompositionFrames = 0;
+}
+
+bool TimeStats::isEnabled() {
+    return mEnabled.load();
+}
+
+void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (timeStats.statsStart == 0) {
+        return;
+    }
+
+    timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+
+    if (asProto) {
+        ALOGD("Dumping TimeStats as proto");
+        SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto(maxLayers);
+        result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
+    } else {
+        ALOGD("Dumping TimeStats as text");
+        result.append(timeStats.toString(maxLayers).c_str());
+        result.append("\n");
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
new file mode 100644
index 0000000..8318210
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <timestatsproto/TimeStatsHelper.h>
+#include <timestatsproto/TimeStatsProtoHeader.h>
+
+#include <ui/FenceTime.h>
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <deque>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class TimeStats {
+    // TODO(zzyiwei): Bound the timeStatsTracker with weighted LRU
+    // static const size_t MAX_NUM_LAYER_RECORDS = 200;
+    static const size_t MAX_NUM_TIME_RECORDS = 64;
+
+    struct TimeRecord {
+        bool ready = false;
+        uint64_t frameNumber = 0;
+        nsecs_t postTime = 0;
+        nsecs_t latchTime = 0;
+        nsecs_t acquireTime = 0;
+        nsecs_t desiredTime = 0;
+        nsecs_t presentTime = 0;
+        std::shared_ptr<FenceTime> acquireFence;
+        std::shared_ptr<FenceTime> presentFence;
+    };
+
+    struct LayerRecord {
+        // This is the index in timeRecords, at which the timestamps for that
+        // specific frame are still not fully received. This is not waiting for
+        // fences to signal, but rather waiting to receive those fences/timestamps.
+        int32_t waitData = -1;
+        TimeRecord prevTimeRecord;
+        std::deque<TimeRecord> timeRecords;
+    };
+
+public:
+    static TimeStats& getInstance();
+    void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
+    void incrementTotalFrames();
+    void incrementMissedFrames();
+    void incrementClientCompositionFrames();
+
+    void setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime);
+    void setLatchTime(const std::string& layerName, uint64_t frameNumber, nsecs_t latchTime);
+    void setDesiredTime(const std::string& layerName, uint64_t frameNumber, nsecs_t desiredTime);
+    void setAcquireTime(const std::string& layerName, uint64_t frameNumber, nsecs_t acquireTime);
+    void setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+                         const std::shared_ptr<FenceTime>& acquireFence);
+    void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
+    void setPresentFence(const std::string& layerName, uint64_t frameNumber,
+                         const std::shared_ptr<FenceTime>& presentFence);
+    void onDisconnect(const std::string& layerName);
+    void clearLayerRecord(const std::string& layerName);
+    void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
+
+private:
+    TimeStats() = default;
+
+    bool recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord);
+    void flushAvailableRecordsToStatsLocked(const std::string& layerName);
+
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result);
+
+    std::atomic<bool> mEnabled = false;
+    std::mutex mMutex;
+    TimeStatsHelper::TimeStatsGlobal timeStats;
+    std::unordered_map<std::string, LayerRecord> timeStatsTracker;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
new file mode 100644
index 0000000..bef6b7c
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -0,0 +1,33 @@
+cc_library_shared {
+    name: "libtimestats_proto",
+    export_include_dirs: ["include"],
+
+    srcs: [
+        "TimeStatsHelper.cpp",
+        "timestats.proto",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libprotobuf-cpp-lite",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+    },
+
+    cppflags: [
+        "-std=c++1z",
+        "-Werror",
+        "-Wno-c++98-compat-pedantic",
+        "-Wno-disabled-macro-expansion",
+        "-Wno-float-conversion",
+        "-Wno-float-equal",
+        "-Wno-format",
+        "-Wno-old-style-cast",
+        "-Wno-padded",
+        "-Wno-sign-conversion",
+        "-Wno-undef",
+        "-Wno-unused-parameter",
+    ],
+}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
new file mode 100644
index 0000000..21f3ef3
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/stringprintf.h>
+#include <timestatsproto/TimeStatsHelper.h>
+
+#include <array>
+
+#define HISTOGRAM_SIZE 85
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
+namespace android {
+namespace surfaceflinger {
+
+// Time buckets for histogram, the calculated time deltas will be lower bounded
+// to the buckets in this array.
+static const std::array<int32_t, HISTOGRAM_SIZE> histogramConfig =
+        {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16,
+         17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,
+         34,  36,  38,  40,  42,  44,  46,  48,  50,  54,  58,  62,  66,  70,  74,  78,  82,
+         86,  90,  94,  98,  102, 106, 110, 114, 118, 122, 126, 130, 134, 138, 142, 146, 150,
+         200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000};
+
+void TimeStatsHelper::Histogram::insert(int32_t delta) {
+    if (delta < 0) return;
+    // std::lower_bound won't work on out of range values
+    if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
+        hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
+        return;
+    }
+    auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
+    hist[*iter]++;
+}
+
+float TimeStatsHelper::Histogram::averageTime() const {
+    int64_t ret = 0;
+    int64_t count = 0;
+    for (auto& ele : hist) {
+        count += ele.second;
+        ret += ele.first * ele.second;
+    }
+    return static_cast<float>(ret) / count;
+}
+
+std::string TimeStatsHelper::Histogram::toString() const {
+    std::string result;
+    for (int32_t i = 0; i < HISTOGRAM_SIZE; ++i) {
+        int32_t bucket = histogramConfig[i];
+        int32_t count = (hist.count(bucket) == 0) ? 0 : hist.at(bucket);
+        StringAppendF(&result, "%dms=%d ", bucket, count);
+    }
+    result.back() = '\n';
+    return result;
+}
+
+std::string TimeStatsHelper::TimeStatsLayer::toString() const {
+    std::string result = "";
+    StringAppendF(&result, "layerName = %s\n", layerName.c_str());
+    StringAppendF(&result, "packageName = %s\n", packageName.c_str());
+    StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
+    StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
+    StringAppendF(&result, "totalFrames= %d\n", totalFrames);
+    auto iter = deltas.find("present2present");
+    if (iter != deltas.end()) {
+        StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
+    }
+    for (auto& ele : deltas) {
+        StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
+        StringAppendF(&result, "%s", ele.second.toString().c_str());
+    }
+
+    return result;
+}
+
+std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
+    std::string result = "SurfaceFlinger TimeStats:\n";
+    StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
+    StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
+    StringAppendF(&result, "totalFrames= %d\n", totalFrames);
+    StringAppendF(&result, "missedFrames= %d\n", missedFrames);
+    StringAppendF(&result, "clientCompositionFrames= %d\n", clientCompositionFrames);
+    StringAppendF(&result, "TimeStats for each layer is as below:\n");
+    const auto dumpStats = generateDumpStats(maxLayers);
+    for (auto& ele : dumpStats) {
+        StringAppendF(&result, "%s", ele->toString().c_str());
+    }
+
+    return result;
+}
+
+SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const {
+    SFTimeStatsLayerProto layerProto;
+    layerProto.set_layer_name(layerName);
+    layerProto.set_package_name(packageName);
+    layerProto.set_stats_start(statsStart);
+    layerProto.set_stats_end(statsEnd);
+    layerProto.set_total_frames(totalFrames);
+    for (auto& ele : deltas) {
+        SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
+        deltaProto->set_delta_name(ele.first);
+        for (auto& histEle : ele.second.hist) {
+            SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
+            histProto->set_render_millis(histEle.first);
+            histProto->set_frame_count(histEle.second);
+        }
+    }
+    return layerProto;
+}
+
+SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
+        std::optional<uint32_t> maxLayers) const {
+    SFTimeStatsGlobalProto globalProto;
+    globalProto.set_stats_start(statsStart);
+    globalProto.set_stats_end(statsEnd);
+    globalProto.set_total_frames(totalFrames);
+    globalProto.set_missed_frames(missedFrames);
+    globalProto.set_client_composition_frames(clientCompositionFrames);
+    const auto dumpStats = generateDumpStats(maxLayers);
+    for (auto& ele : dumpStats) {
+        SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
+        layerProto->CopyFrom(ele->toProto());
+    }
+    return globalProto;
+}
+
+std::vector<TimeStatsHelper::TimeStatsLayer const*>
+TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
+    std::vector<TimeStatsLayer const*> dumpStats;
+    for (auto& ele : stats) {
+        dumpStats.push_back(&ele.second);
+    }
+
+    std::sort(dumpStats.begin(), dumpStats.end(),
+              [](TimeStatsHelper::TimeStatsLayer const* l,
+                 TimeStatsHelper::TimeStatsLayer const* r) {
+                  return l->totalFrames > r->totalFrames;
+              });
+
+    if (maxLayers && (*maxLayers < dumpStats.size())) {
+        dumpStats.resize(*maxLayers);
+    }
+    return dumpStats;
+}
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
new file mode 100644
index 0000000..1798555
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <timestatsproto/TimeStatsProtoHeader.h>
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace surfaceflinger {
+
+class TimeStatsHelper {
+public:
+    class Histogram {
+    public:
+        // Key is the delta time between timestamps
+        // Value is the number of appearances of that delta
+        std::unordered_map<int32_t, int32_t> hist;
+
+        void insert(int32_t delta);
+        float averageTime() const;
+        std::string toString() const;
+    };
+
+    class TimeStatsLayer {
+    public:
+        std::string layerName;
+        std::string packageName;
+        int64_t statsStart = 0;
+        int64_t statsEnd = 0;
+        int32_t totalFrames = 0;
+        std::unordered_map<std::string, Histogram> deltas;
+
+        std::string toString() const;
+        SFTimeStatsLayerProto toProto() const;
+    };
+
+    class TimeStatsGlobal {
+    public:
+        int64_t statsStart = 0;
+        int64_t statsEnd = 0;
+        int32_t totalFrames = 0;
+        int32_t missedFrames = 0;
+        int32_t clientCompositionFrames = 0;
+        std::unordered_map<std::string, TimeStatsLayer> stats;
+
+        std::string toString(std::optional<uint32_t> maxLayers) const;
+        SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
+
+    private:
+        std::vector<TimeStatsLayer const*> generateDumpStats(
+                std::optional<uint32_t> maxLayers) const;
+    };
+};
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsProtoHeader.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsProtoHeader.h
new file mode 100644
index 0000000..fe0d150
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsProtoHeader.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Projectlayerproto/LayerProtoHeader.h
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pragma is used here to disable the warnings emitted from the protobuf
+// headers. By adding #pragma before including layer.pb.h, it supresses
+// protobuf warnings, but allows the rest of the files to continuing using
+// the current flags.
+// This file should be included instead of directly including layer.b.h
+#pragma GCC system_header
+#include <timestats.pb.h>
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
new file mode 100644
index 0000000..f29fbd1
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.surfaceflinger;
+
+option optimize_for = LITE_RUNTIME;
+
+message SFTimeStatsGlobalProto {
+  // The start & end timestamps in UTC as
+  // milliseconds since January 1, 1970
+  optional int64 stats_start = 1;
+  optional int64 stats_end = 2;
+  // Total frames
+  optional int32 total_frames = 3;
+  // Total missed frames of SurfaceFlinger.
+  optional int32 missed_frames = 4;
+  // Total frames fallback to client composition.
+  optional int32 client_composition_frames = 5;
+
+  repeated SFTimeStatsLayerProto stats = 6;
+}
+
+message SFTimeStatsLayerProto {
+  // The layer name
+  optional string layer_name = 1;
+  // The package name
+  optional string package_name = 2;
+  // The start & end timestamps in UTC as
+  // milliseconds since January 1, 1970
+  optional int64 stats_start = 3;
+  optional int64 stats_end = 4;
+  // Distinct frame count.
+  optional int32 total_frames = 5;
+
+  repeated SFTimeStatsDeltaProto deltas = 6;
+}
+
+message SFTimeStatsDeltaProto {
+  // Name of the time interval
+  optional string delta_name = 1;
+  // Histogram of the delta time
+  repeated SFTimeStatsHistogramBucketProto histograms = 2;
+}
+
+message SFTimeStatsHistogramBucketProto {
+  // Lower bound of render time in milliseconds.
+  optional int32 render_millis = 1;
+  // Number of frames in the bucket.
+  optional int32 frame_count = 2;
+}
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 6be9ae2..e05ed53 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,8 +20,8 @@
 #include <utils/String8.h>
 #include <ui/Region.h>
 
-#include "clz.h"
 #include "Transform.h"
+#include "clz.h"
 
 // ---------------------------------------------------------------------------
 
@@ -224,6 +224,27 @@
     return r;
 }
 
+FloatRect Transform::transform(const FloatRect& bounds) const
+{
+    vec2 lt(bounds.left, bounds.top);
+    vec2 rt(bounds.right, bounds.top);
+    vec2 lb(bounds.left, bounds.bottom);
+    vec2 rb(bounds.right, bounds.bottom);
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    FloatRect r;
+    r.left = min(lt[0], rt[0], lb[0], rb[0]);
+    r.top = min(lt[1], rt[1], lb[1], rb[1]);
+    r.right = max(lt[0], rt[0], lb[0], rb[0]);
+    r.bottom = max(lt[1], rt[1], lb[1], rb[1]);
+
+    return r;
+}
+
 Region Transform::transform(const Region& reg) const
 {
     Region out;
@@ -388,6 +409,23 @@
     ALOGD("%.4f  %.4f  %.4f", m[0][2], m[1][2], m[2][2]);
 }
 
+Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) {
+    // Convert to surfaceflinger's internal rotation type.
+    switch (rotation) {
+        case ISurfaceComposer::eRotateNone:
+            return Transform::ROT_0;
+        case ISurfaceComposer::eRotate90:
+            return Transform::ROT_90;
+        case ISurfaceComposer::eRotate180:
+            return Transform::ROT_180;
+        case ISurfaceComposer::eRotate270:
+            return Transform::ROT_270;
+        default:
+            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
+            return Transform::ROT_0;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 6640a13..b11d057 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -25,6 +25,8 @@
 #include <math/vec2.h>
 #include <math/vec3.h>
 
+#include <gui/ISurfaceComposer.h>
+
 #include <hardware/hardware.h>
 
 namespace android {
@@ -51,6 +53,8 @@
                 ROT_INVALID = 0x80
             };
 
+            static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation);
+
             enum type_mask {
                 IDENTITY            = 0,
                 TRANSLATE           = 0x1,
@@ -80,6 +84,7 @@
             Region  transform(const Region& reg) const;
             Rect    transform(const Rect& bounds,
                     bool roundOutwards = false) const;
+            FloatRect transform(const FloatRect& bounds) const;
             Transform operator * (const Transform& rhs) const;
             // assumes the last row is < 0 , 0 , 1 >
             vec2 transform(const vec2& v) const;
diff --git a/services/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/VSyncModulator.h
new file mode 100644
index 0000000..e071a59
--- /dev/null
+++ b/services/surfaceflinger/VSyncModulator.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Errors.h>
+
+#include <mutex>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+/*
+ * Modulates the vsync-offsets depending on current SurfaceFlinger state.
+ */
+class VSyncModulator {
+private:
+
+    // Number of frames we'll keep the early phase offsets once they are activated. This acts as a
+    // low-pass filter in case the client isn't quick enough in sending new transactions.
+    const int MIN_EARLY_FRAME_COUNT = 2;
+
+public:
+
+    struct Offsets {
+        nsecs_t sf;
+        nsecs_t app;
+    };
+
+    enum TransactionStart {
+        EARLY,
+        NORMAL
+    };
+
+    // Sets the phase offsets
+    //
+    // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
+    //          as early. May be the same as late, in which case we don't shift offsets.
+    // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
+    //            and the transaction was marked as early, we'll use sfEarly.
+    // sfLate: The regular SF vsync phase offset.
+    // appEarly: Like sfEarly, but for the app-vsync
+    // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
+    // appLate: The regular app vsync phase offset.
+    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
+        mEarlyOffsets = early;
+        mEarlyGlOffsets = earlyGl;
+        mLateOffsets = late;
+        mOffsets = late;
+    }
+
+    Offsets getEarlyOffsets() const {
+        return mEarlyOffsets;
+    }
+
+    Offsets getEarlyGlOffsets() const {
+        return mEarlyGlOffsets;
+    }
+
+    void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
+        mSfEventThread = sfEventThread;
+        mAppEventThread = appEventThread;
+    }
+
+    void setTransactionStart(TransactionStart transactionStart) {
+
+        if (transactionStart == TransactionStart::EARLY) {
+            mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
+        }
+
+        // An early transaction stays an early transaction.
+        if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
+            return;
+        }
+        mTransactionStart = transactionStart;
+        updateOffsets();
+    }
+
+    void onTransactionHandled() {
+        if (mTransactionStart == TransactionStart::NORMAL) return;
+        mTransactionStart = TransactionStart::NORMAL;
+        updateOffsets();
+    }
+
+    void onRefreshed(bool usedRenderEngine) {
+        bool updateOffsetsNeeded = false;
+        if (mRemainingEarlyFrameCount > 0) {
+            mRemainingEarlyFrameCount--;
+            updateOffsetsNeeded = true;
+        }
+        if (usedRenderEngine != mLastFrameUsedRenderEngine) {
+            mLastFrameUsedRenderEngine = usedRenderEngine;
+            updateOffsetsNeeded = true;
+        }
+        if (updateOffsetsNeeded) {
+            updateOffsets();
+        }
+    }
+
+private:
+
+    void updateOffsets() {
+        const Offsets desired = getOffsets();
+        const Offsets current = mOffsets;
+
+        bool changed = false;
+        if (desired.sf != current.sf) {
+            mSfEventThread->setPhaseOffset(desired.sf);
+            changed = true;
+        }
+        if (desired.app != current.app) {
+            mAppEventThread->setPhaseOffset(desired.app);
+            changed = true;
+        }
+
+        if (changed) {
+            mOffsets = desired;
+        }
+    }
+
+    Offsets getOffsets() {
+        if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+            return mEarlyOffsets;
+        } else if (mLastFrameUsedRenderEngine) {
+            return mEarlyGlOffsets;
+        } else {
+            return mLateOffsets;
+        }
+    }
+
+    Offsets mLateOffsets;
+    Offsets mEarlyOffsets;
+    Offsets mEarlyGlOffsets;
+
+    EventThread* mSfEventThread = nullptr;
+    EventThread* mAppEventThread = nullptr;
+
+    std::atomic<Offsets> mOffsets;
+
+    std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
+    std::atomic<bool> mLastFrameUsedRenderEngine = false;
+    std::atomic<int> mRemainingEarlyFrameCount = 0;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
new file mode 100644
index 0000000..ac147fe
--- /dev/null
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -0,0 +1,55 @@
+cc_library_shared {
+    name: "liblayers_proto",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+
+    srcs: [
+        "LayerProtoParser.cpp",
+        "layers.proto",
+        "layerstrace.proto",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.common@1.1",
+        "libui",
+        "libprotobuf-cpp-lite",
+        "libbase",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+    },
+
+    cppflags: [
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-format",
+        "-Wno-c++98-compat-pedantic",
+        "-Wno-float-conversion",
+        "-Wno-disabled-macro-expansion",
+        "-Wno-float-equal",
+        "-Wno-sign-conversion",
+        "-Wno-padded",
+        "-Wno-old-style-cast",
+        "-Wno-undef",
+    ],
+
+}
+
+java_library_static {
+    name: "layersprotosnano",
+    host_supported: true,
+    proto: {
+        type: "nano",
+    },
+    srcs: ["*.proto"],
+    no_framework_libs: true,
+    target: {
+        android: {
+            jarjar_rules: "jarjar-rules.txt",
+        },
+        host: {
+            static_libs: ["libprotobuf-java-nano"],
+        },
+    },
+}
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
new file mode 100644
index 0000000..fcf42f0
--- /dev/null
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/stringprintf.h>
+#include <layerproto/LayerProtoParser.h>
+#include <ui/DebugUtils.h>
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
+namespace android {
+namespace surfaceflinger {
+
+bool sortLayers(LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
+    uint32_t ls = lhs->layerStack;
+    uint32_t rs = rhs->layerStack;
+    if (ls != rs) return ls < rs;
+
+    int32_t lz = lhs->z;
+    int32_t rz = rhs->z;
+    if (lz != rz) {
+        return (lz > rz) ? 1 : -1;
+    }
+
+    return lhs->id < rhs->id;
+}
+
+bool sortLayerUniquePtrs(const std::unique_ptr<LayerProtoParser::Layer>& lhs,
+                   const std::unique_ptr<LayerProtoParser::Layer>& rhs) {
+    return sortLayers(lhs.get(), rhs.get());
+}
+
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
+        const LayersProto& layersProto) {
+    LayerGlobal layerGlobal;
+    layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
+    layerGlobal.colorMode = layersProto.color_mode();
+    layerGlobal.colorTransform = layersProto.color_transform();
+    layerGlobal.globalTransform = layersProto.global_transform();
+    return layerGlobal;
+}
+
+std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
+        const LayersProto& layersProto) {
+    std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto);
+    std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers;
+
+    for (std::pair<int32_t, Layer*> kv : layerMap) {
+        if (kv.second->parent == nullptr) {
+            // Make unique_ptr for top level layers since they are not children. This ensures there
+            // will only be one unique_ptr made for each layer.
+            layers.push_back(std::unique_ptr<Layer>(kv.second));
+        }
+    }
+
+    std::sort(layers.begin(), layers.end(), sortLayerUniquePtrs);
+    return layers;
+}
+
+std::unordered_map<int32_t, LayerProtoParser::Layer*> LayerProtoParser::generateMap(
+        const LayersProto& layersProto) {
+    std::unordered_map<int32_t, Layer*> layerMap;
+
+    for (int i = 0; i < layersProto.layers_size(); i++) {
+        const LayerProto& layerProto = layersProto.layers(i);
+        layerMap[layerProto.id()] = generateLayer(layerProto);
+    }
+
+    for (int i = 0; i < layersProto.layers_size(); i++) {
+        const LayerProto& layerProto = layersProto.layers(i);
+        updateChildrenAndRelative(layerProto, layerMap);
+    }
+
+    return layerMap;
+}
+
+LayerProtoParser::Layer* LayerProtoParser::generateLayer(const LayerProto& layerProto) {
+    Layer* layer = new Layer();
+    layer->id = layerProto.id();
+    layer->name = layerProto.name();
+    layer->type = layerProto.type();
+    layer->transparentRegion = generateRegion(layerProto.transparent_region());
+    layer->visibleRegion = generateRegion(layerProto.visible_region());
+    layer->damageRegion = generateRegion(layerProto.damage_region());
+    layer->layerStack = layerProto.layer_stack();
+    layer->z = layerProto.z();
+    layer->position = {layerProto.position().x(), layerProto.position().y()};
+    layer->requestedPosition = {layerProto.requested_position().x(),
+                                layerProto.requested_position().y()};
+    layer->size = {layerProto.size().w(), layerProto.size().h()};
+    layer->crop = generateRect(layerProto.crop());
+    layer->finalCrop = generateRect(layerProto.final_crop());
+    layer->isOpaque = layerProto.is_opaque();
+    layer->invalidate = layerProto.invalidate();
+    layer->dataspace = layerProto.dataspace();
+    layer->pixelFormat = layerProto.pixel_format();
+    layer->color = {layerProto.color().r(), layerProto.color().g(), layerProto.color().b(),
+                    layerProto.color().a()};
+    layer->requestedColor = {layerProto.requested_color().r(), layerProto.requested_color().g(),
+                             layerProto.requested_color().b(), layerProto.requested_color().a()};
+    layer->flags = layerProto.flags();
+    layer->transform = generateTransform(layerProto.transform());
+    layer->requestedTransform = generateTransform(layerProto.requested_transform());
+    layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
+    layer->queuedFrames = layerProto.queued_frames();
+    layer->refreshPending = layerProto.refresh_pending();
+    layer->hwcFrame = generateRect(layerProto.hwc_frame());
+    layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+    layer->hwcTransform = layerProto.hwc_transform();
+    layer->windowType = layerProto.window_type();
+    layer->appId = layerProto.app_id();
+    layer->hwcCompositionType = layerProto.hwc_composition_type();
+    layer->isProtected = layerProto.is_protected();
+
+    return layer;
+}
+
+LayerProtoParser::Region LayerProtoParser::generateRegion(const RegionProto& regionProto) {
+    LayerProtoParser::Region region;
+    region.id = regionProto.id();
+    for (int i = 0; i < regionProto.rect_size(); i++) {
+        const RectProto& rectProto = regionProto.rect(i);
+        region.rects.push_back(generateRect(rectProto));
+    }
+
+    return region;
+}
+
+LayerProtoParser::Rect LayerProtoParser::generateRect(const RectProto& rectProto) {
+    LayerProtoParser::Rect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+    LayerProtoParser::FloatRect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
+LayerProtoParser::Transform LayerProtoParser::generateTransform(
+        const TransformProto& transformProto) {
+    LayerProtoParser::Transform transform;
+    transform.dsdx = transformProto.dsdx();
+    transform.dtdx = transformProto.dtdx();
+    transform.dsdy = transformProto.dsdy();
+    transform.dtdy = transformProto.dtdy();
+
+    return transform;
+}
+
+LayerProtoParser::ActiveBuffer LayerProtoParser::generateActiveBuffer(
+        const ActiveBufferProto& activeBufferProto) {
+    LayerProtoParser::ActiveBuffer activeBuffer;
+    activeBuffer.width = activeBufferProto.width();
+    activeBuffer.height = activeBufferProto.height();
+    activeBuffer.stride = activeBufferProto.stride();
+    activeBuffer.format = activeBufferProto.format();
+
+    return activeBuffer;
+}
+
+void LayerProtoParser::updateChildrenAndRelative(const LayerProto& layerProto,
+                                                 std::unordered_map<int32_t, Layer*>& layerMap) {
+    auto currLayer = layerMap[layerProto.id()];
+
+    for (int i = 0; i < layerProto.children_size(); i++) {
+        if (layerMap.count(layerProto.children(i)) > 0) {
+            // Only make unique_ptrs for children since they are guaranteed to be unique, only one
+            // parent per child. This ensures there will only be one unique_ptr made for each layer.
+            currLayer->children.push_back(std::unique_ptr<Layer>(layerMap[layerProto.children(i)]));
+        }
+    }
+
+    for (int i = 0; i < layerProto.relatives_size(); i++) {
+        if (layerMap.count(layerProto.relatives(i)) > 0) {
+            currLayer->relatives.push_back(layerMap[layerProto.relatives(i)]);
+        }
+    }
+
+    if (layerProto.has_parent()) {
+        if (layerMap.count(layerProto.parent()) > 0) {
+            currLayer->parent = layerMap[layerProto.parent()];
+        }
+    }
+
+    if (layerProto.has_z_order_relative_of()) {
+        if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
+            currLayer->zOrderRelativeOf = layerMap[layerProto.z_order_relative_of()];
+        }
+    }
+}
+
+std::string LayerProtoParser::layersToString(
+        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers) {
+    std::string result;
+    for (std::unique_ptr<LayerProtoParser::Layer>& layer : layers) {
+        if (layer->zOrderRelativeOf != nullptr) {
+            continue;
+        }
+        result.append(layerToString(layer.get()).c_str());
+    }
+
+    return result;
+}
+
+std::string LayerProtoParser::layerToString(LayerProtoParser::Layer* layer) {
+    std::string result;
+
+    std::vector<Layer*> traverse(layer->relatives);
+    for (std::unique_ptr<LayerProtoParser::Layer>& child : layer->children) {
+        if (child->zOrderRelativeOf != nullptr) {
+            continue;
+        }
+
+        traverse.push_back(child.get());
+    }
+
+    std::sort(traverse.begin(), traverse.end(), sortLayers);
+
+    size_t i = 0;
+    for (; i < traverse.size(); i++) {
+        auto& relative = traverse[i];
+        if (relative->z >= 0) {
+            break;
+        }
+        result.append(layerToString(relative).c_str());
+    }
+    result.append(layer->to_string().c_str());
+    result.append("\n");
+    for (; i < traverse.size(); i++) {
+        auto& relative = traverse[i];
+        result.append(layerToString(relative).c_str());
+    }
+
+    return result;
+}
+
+std::string LayerProtoParser::ActiveBuffer::to_string() const {
+    return StringPrintf("[%4ux%4u:%4u,%s]", width, height, stride,
+                        decodePixelFormat(format).c_str());
+}
+
+std::string LayerProtoParser::Transform::to_string() const {
+    return StringPrintf("[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(dsdx),
+                        static_cast<double>(dtdx), static_cast<double>(dsdy),
+                        static_cast<double>(dtdy));
+}
+
+std::string LayerProtoParser::Rect::to_string() const {
+    return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
+}
+
+std::string LayerProtoParser::FloatRect::to_string() const {
+    return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
+std::string LayerProtoParser::Region::to_string(const char* what) const {
+    std::string result =
+            StringPrintf("  Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
+                         static_cast<int>(rects.size()));
+
+    for (auto& rect : rects) {
+        StringAppendF(&result, "    %s\n", rect.to_string().c_str());
+    }
+
+    return result;
+}
+
+std::string LayerProtoParser::Layer::to_string() const {
+    std::string result;
+    StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str());
+    result.append(transparentRegion.to_string("TransparentRegion").c_str());
+    result.append(visibleRegion.to_string("VisibleRegion").c_str());
+    result.append(damageRegion.to_string("SurfaceDamageRegion").c_str());
+
+    StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", layerStack,
+                  z, static_cast<double>(position.x), static_cast<double>(position.y), size.x,
+                  size.y);
+
+    StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
+                  finalCrop.to_string().c_str());
+    StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
+    StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
+    StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
+    StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+                  static_cast<double>(color.r), static_cast<double>(color.g),
+                  static_cast<double>(color.b), static_cast<double>(color.a), flags);
+    StringAppendF(&result, "tr=%s", transform.to_string().c_str());
+    result.append("\n");
+    StringAppendF(&result, "      parent=%s\n", parent == nullptr ? "none" : parent->name.c_str());
+    StringAppendF(&result, "      zOrderRelativeOf=%s\n",
+                  zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
+    StringAppendF(&result, "      activeBuffer=%s,", activeBuffer.to_string().c_str());
+    StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
+    StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
+
+    return result;
+}
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h
new file mode 100644
index 0000000..f560562
--- /dev/null
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoHeader.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Projectlayerproto/LayerProtoHeader.h
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pragma is used here to disable the warnings emitted from the protobuf
+// headers. By adding #pragma before including layer.pb.h, it supresses
+// protobuf warnings, but allows the rest of the files to continuing using
+// the current flags.
+// This file should be included instead of directly including layer.b.h
+#pragma GCC system_header
+#include <layers.pb.h>
+#include <layerstrace.pb.h>
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
new file mode 100644
index 0000000..74a6f28
--- /dev/null
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+
+#include <math/vec4.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace surfaceflinger {
+
+class LayerProtoParser {
+public:
+    class ActiveBuffer {
+    public:
+        uint32_t width;
+        uint32_t height;
+        uint32_t stride;
+        int32_t format;
+
+        std::string to_string() const;
+    };
+
+    class Transform {
+    public:
+        float dsdx;
+        float dtdx;
+        float dsdy;
+        float dtdy;
+
+        std::string to_string() const;
+    };
+
+    class Rect {
+    public:
+        int32_t left;
+        int32_t top;
+        int32_t right;
+        int32_t bottom;
+
+        std::string to_string() const;
+    };
+
+    class FloatRect {
+    public:
+        float left;
+        float top;
+        float right;
+        float bottom;
+
+        std::string to_string() const;
+    };
+
+    class Region {
+    public:
+        uint64_t id;
+        std::vector<Rect> rects;
+
+        std::string to_string(const char* what) const;
+    };
+
+    class Layer {
+    public:
+        int32_t id;
+        std::string name;
+        std::vector<std::unique_ptr<Layer>> children;
+        std::vector<Layer*> relatives;
+        std::string type;
+        LayerProtoParser::Region transparentRegion;
+        LayerProtoParser::Region visibleRegion;
+        LayerProtoParser::Region damageRegion;
+        uint32_t layerStack;
+        int32_t z;
+        float2 position;
+        float2 requestedPosition;
+        int2 size;
+        LayerProtoParser::Rect crop;
+        LayerProtoParser::Rect finalCrop;
+        bool isOpaque;
+        bool invalidate;
+        std::string dataspace;
+        std::string pixelFormat;
+        half4 color;
+        half4 requestedColor;
+        uint32_t flags;
+        Transform transform;
+        Transform requestedTransform;
+        Layer* parent = 0;
+        Layer* zOrderRelativeOf = 0;
+        LayerProtoParser::ActiveBuffer activeBuffer;
+        int32_t queuedFrames;
+        bool refreshPending;
+        LayerProtoParser::Rect hwcFrame;
+        LayerProtoParser::FloatRect hwcCrop;
+        int32_t hwcTransform;
+        int32_t windowType;
+        int32_t appId;
+        int32_t hwcCompositionType;
+        bool isProtected;
+
+        std::string to_string() const;
+    };
+
+    class LayerGlobal {
+    public:
+        int2 resolution;
+        std::string colorMode;
+        std::string colorTransform;
+        int32_t globalTransform;
+    };
+
+    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
+    static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto);
+    static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers);
+
+private:
+    static std::unordered_map<int32_t, Layer*> generateMap(const LayersProto& layersProto);
+    static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
+    static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
+    static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+    static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
+    static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
+    static LayerProtoParser::ActiveBuffer generateActiveBuffer(
+            const ActiveBufferProto& activeBufferProto);
+    static void updateChildrenAndRelative(const LayerProto& layerProto,
+                                          std::unordered_map<int32_t, Layer*>& layerMap);
+
+    static std::string layerToString(LayerProtoParser::Layer* layer);
+};
+
+} // namespace surfaceflinger
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/jarjar-rules.txt b/services/surfaceflinger/layerproto/jarjar-rules.txt
new file mode 100644
index 0000000..40043a8
--- /dev/null
+++ b/services/surfaceflinger/layerproto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
new file mode 100644
index 0000000..edf56ab
--- /dev/null
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -0,0 +1,144 @@
+// Definitions for SurfaceFlinger layers.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
+
+// Contains a list of all layers.
+message LayersProto {
+  repeated LayerProto layers = 1;
+  optional SizeProto resolution = 2;
+  optional string color_mode = 3;
+  optional string color_transform = 4;
+  optional int32 global_transform = 5;
+}
+
+// Information about each layer.
+message LayerProto {
+  // unique id per layer.
+  optional int32 id = 1;
+  // unique name per layer.
+  optional string name = 2;
+  // list of children this layer may have. May be empty.
+  repeated int32 children = 3;
+  // list of layers that are z order relative to this layer.
+  repeated int32 relatives = 4;
+  // The type of layer, ex Color, Layer
+  optional string type = 5;
+  optional RegionProto transparent_region = 6;
+  optional RegionProto visible_region = 7;
+  optional RegionProto damage_region = 8;
+  optional uint32 layer_stack = 9;
+  // The layer's z order. Can be z order in layer stack, relative to parent,
+  // or relative to another layer specified in zOrderRelative.
+  optional int32 z = 10;
+  // The layer's position on the display.
+  optional PositionProto position = 11;
+  // The layer's requested position.
+  optional PositionProto requested_position = 12;
+  // The layer's size.
+  optional SizeProto size = 13;
+  // The layer's crop in it's own bounds.
+  optional RectProto crop = 14;
+  // The layer's crop in it's parent's bounds.
+  optional RectProto final_crop = 15;
+  optional bool is_opaque = 16;
+  optional bool invalidate = 17;
+  optional string dataspace = 18;
+  optional string pixel_format = 19;
+  // The layer's actual color.
+  optional ColorProto color = 20;
+  // The layer's requested color.
+  optional ColorProto requested_color = 21;
+  // Can be any combination of
+  //    hidden = 0x01
+  //    opaque = 0x02,
+  //    secure = 0x80,
+  optional uint32 flags = 22;
+  // The layer's actual transform
+  optional TransformProto transform = 23;
+  // The layer's requested transform.
+  optional TransformProto requested_transform = 24;
+  // The parent layer. This value can be null if there is no parent.
+  optional int32 parent = 25 [default = -1];
+  // The layer that this layer has a z order relative to. This value can be null.
+  optional int32 z_order_relative_of = 26 [default = -1];
+  // This value can be null if there's nothing to draw.
+  optional ActiveBufferProto active_buffer = 27;
+  // The number of frames available.
+  optional int32 queued_frames = 28;
+  optional bool refresh_pending = 29;
+  // The layer's composer backend destination frame
+  optional RectProto hwc_frame = 30;
+  // The layer's composer backend source crop
+  optional FloatRectProto hwc_crop = 31;
+  // The layer's composer backend transform
+  optional int32 hwc_transform = 32;
+  optional int32 window_type = 33;
+  optional int32 app_id = 34;
+  // The layer's composition type
+  optional int32 hwc_composition_type = 35;
+  // If it's a buffer layer, indicate if the content is protected
+  optional bool is_protected = 36;
+  // Current frame number being rendered.
+  optional uint64 curr_frame = 37;
+  // A list of barriers that the layer is waiting to update state.
+  repeated BarrierLayerProto barrier_layer = 38;
+}
+
+message PositionProto {
+  optional float x = 1;
+  optional float y = 2;
+}
+
+message SizeProto {
+  optional int32 w = 1;
+  optional int32 h = 2;
+}
+
+message TransformProto {
+  optional float dsdx = 1;
+  optional float dtdx = 2;
+  optional float dsdy = 3;
+  optional float dtdy = 4;
+}
+
+message RegionProto {
+  optional uint64 id = 1;
+  repeated RectProto rect = 2;
+}
+
+message RectProto {
+  optional int32 left   = 1;
+  optional int32 top    = 2;
+  optional int32 right  = 3;
+  optional int32 bottom = 4;
+}
+
+message FloatRectProto {
+  optional float left = 1;
+  optional float top = 2;
+  optional float right = 3;
+  optional float bottom = 4;
+}
+
+message ActiveBufferProto {
+  optional uint32 width = 1;
+  optional uint32 height = 2;
+  optional uint32 stride = 3;
+  optional int32 format = 4;
+}
+
+message ColorProto {
+  optional float r = 1;
+  optional float g = 2;
+  optional float b = 3;
+  optional float a = 4;
+}
+
+message BarrierLayerProto {
+  // layer id the barrier is waiting on.
+  optional int32 id = 1;
+  // frame number the barrier is waiting on.
+  optional uint64 frame_number = 2;
+}
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
new file mode 100644
index 0000000..bee17d2
--- /dev/null
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+import "frameworks/native/services/surfaceflinger/layerproto/layers.proto";
+
+package android.surfaceflinger;
+
+/* represents a file full of surface flinger trace entries.
+   Encoded, it should start with 0x4c 0x59 0x52 0x54 0x52 0x41 0x43 0x45 (.LYRTRACE), such
+   that they can be easily identified. */
+message LayersTraceFileProto {
+
+    /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+       (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+        constants into .proto files. */
+    enum MagicNumber {
+        INVALID = 0;
+        MAGIC_NUMBER_L = 0x5452594c;  /* LYRT (little-endian ASCII) */
+        MAGIC_NUMBER_H = 0x45434152;  /* RACE (little-endian ASCII) */
+    }
+
+    optional fixed64 magic_number = 1;  /* Must be the first field, set to value in MagicNumber */
+    repeated LayersTraceProto entry = 2;
+}
+
+/* one window manager trace entry. */
+message LayersTraceProto {
+    /* required: elapsed realtime in nanos since boot of when this entry was logged */
+    optional fixed64 elapsed_realtime_nanos = 1;
+
+    /* where the trace originated */
+    optional string where = 2;
+
+    optional LayersProto layers = 3;
+}
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e50f3ce..b1ff522 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -35,6 +35,13 @@
 using namespace android;
 
 static status_t startGraphicsAllocatorService() {
+    using android::hardware::configstore::getBool;
+    using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
+    if (!getBool<ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) {
+        return OK;
+    }
+
     using android::hardware::graphics::allocator::V2_0::IAllocator;
 
     status_t result =
@@ -47,27 +54,12 @@
     return OK;
 }
 
-static status_t startHidlServices() {
+static status_t startDisplayService() {
     using android::frameworks::displayservice::V1_0::implementation::DisplayService;
     using android::frameworks::displayservice::V1_0::IDisplayService;
-    using android::hardware::configstore::getBool;
-    using android::hardware::configstore::getBool;
-    using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
-    hardware::configureRpcThreadpool(1 /* maxThreads */,
-            false /* callerWillJoin */);
-
-    status_t err;
-
-    if (getBool<ISurfaceFlingerConfigs,
-            &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) {
-        err = startGraphicsAllocatorService();
-        if (err != OK) {
-           return err;
-        }
-    }
 
     sp<IDisplayService> displayservice = new DisplayService();
-    err = displayservice->registerAsService();
+    status_t err = displayservice->registerAsService();
 
     if (err != OK) {
         ALOGE("Could not register IDisplayService service.");
@@ -77,9 +69,13 @@
 }
 
 int main(int, char**) {
-    startHidlServices();
-
     signal(SIGPIPE, SIG_IGN);
+
+    hardware::configureRpcThreadpool(1 /* maxThreads */,
+            false /* callerWillJoin */);
+
+    startGraphicsAllocatorService();
+
     // When SF is launched in its own process, limit the number of
     // binder threads to 4.
     ProcessState::self()->setThreadPoolMaxThreadCount(4);
@@ -105,12 +101,15 @@
 
     // publish surface flinger
     sp<IServiceManager> sm(defaultServiceManager());
-    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
+    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
+                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
     // publish GpuService
     sp<GpuService> gpuservice = new GpuService();
     sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
 
+    startDisplayService(); // dependency on SF getting registered above
+
     struct sched_param param = {0};
     param.sched_priority = 2;
     if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
new file mode 100644
index 0000000..322e8a0
--- /dev/null
+++ b/services/surfaceflinger/tests/Android.bp
@@ -0,0 +1,52 @@
+// 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.
+
+cc_test {
+    name: "SurfaceFlinger_test",
+    defaults: ["surfaceflinger_defaults"],
+    tags: ["test"],
+    test_suites: ["device-tests"],
+    srcs: [
+        "Stress_test.cpp",
+        "SurfaceInterceptor_test.cpp",
+        "Transaction_test.cpp",
+    ],
+    data: ["SurfaceFlinger_test.filter"],
+    static_libs: [
+        "libtrace_proto",
+    ],
+    shared_libs: [
+        "libandroid",
+        "libbinder",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libgui",
+        "liblayers_proto",
+        "liblog",
+        "libprotobuf-cpp-full",
+        "libtimestats_proto",
+        "libui",
+        "libutils",
+    ]
+
+}
+
+subdirs = [
+    "fakehwc",
+    "hwc2",
+    "unittests",
+    "vsync",
+    "waitforvsync",
+]
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
deleted file mode 100644
index 43e22a0..0000000
--- a/services/surfaceflinger/tests/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Build the unit tests,
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := SurfaceFlinger_test
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-   Transaction_test.cpp \
-   Stress_test.cpp \
-   SurfaceInterceptor_test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libEGL \
-    libGLESv2 \
-    libbinder \
-    libcutils \
-    libgui \
-    libprotobuf-cpp-full \
-    libui \
-    libutils \
-    libandroid \
-    liblog
-
-LOCAL_STATIC_LIBRARIES := libtrace_proto
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-LOCAL_TEST_DATA = SurfaceFlinger_test.filter
-
-# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-# to integrate with auto-test framework.
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 33dd2f5..4577153 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -22,7 +22,7 @@
 
 #include <thread>
 #include <functional>
-
+#include <layerproto/LayerProtoParser.h>
 
 namespace android {
 
@@ -47,4 +47,66 @@
     }
 }
 
+surfaceflinger::LayersProto generateLayerProto() {
+    surfaceflinger::LayersProto layersProto;
+    std::array<surfaceflinger::LayerProto*, 10> layers = {};
+    for (size_t i = 0; i < layers.size(); ++i) {
+        layers[i] = layersProto.add_layers();
+        layers[i]->set_id(i);
+    }
+
+    layers[0]->add_children(1);
+    layers[1]->set_parent(0);
+    layers[0]->add_children(2);
+    layers[2]->set_parent(0);
+    layers[0]->add_children(3);
+    layers[3]->set_parent(0);
+    layers[2]->add_children(4);
+    layers[4]->set_parent(2);
+    layers[3]->add_children(5);
+    layers[5]->set_parent(3);
+    layers[5]->add_children(6);
+    layers[6]->set_parent(5);
+    layers[5]->add_children(7);
+    layers[7]->set_parent(5);
+    layers[6]->add_children(8);
+    layers[8]->set_parent(6);
+
+    layers[4]->set_z_order_relative_of(3);
+    layers[3]->add_relatives(4);
+    layers[8]->set_z_order_relative_of(9);
+    layers[9]->add_relatives(8);
+    layers[3]->set_z_order_relative_of(1);
+    layers[1]->add_relatives(3);
+
+/* ----------------------------
+ *       - 0 -      - 9 -
+ *      /  |  \
+ *     1   2   3(1)
+ *         |    |
+ *         4(3) 5
+ *             / \
+ *            6   7
+ *            |
+ *            8(9)
+ * -------------------------- */
+
+    return layersProto;
+}
+
+TEST(LayerProtoStress, mem_info) {
+    std::string cmd = "dumpsys meminfo ";
+    cmd += std::to_string(getpid());
+    system(cmd.c_str());
+    for (int i = 0; i < 100000; i++) {
+        surfaceflinger::LayersProto layersProto = generateLayerProto();
+        auto layerTree = surfaceflinger::LayerProtoParser::generateLayerTree(layersProto);
+        // Allow some layerTrees to just fall out of scope (instead of std::move)
+        if (i % 2) {
+            surfaceflinger::LayerProtoParser::layersToString(std::move(layerTree));
+        }
+    }
+    system(cmd.c_str());
+}
+
 }
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6be708a..cca84e5 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
+            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize"
         }
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 0cc763c..de78c3f 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -22,10 +22,11 @@
 #include <android/native_window.h>
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
+
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 #include <ui/DisplayInfo.h>
 
 #include <fstream>
@@ -34,6 +35,8 @@
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 constexpr int32_t SCALING_UPDATE = 1;
 constexpr uint32_t BUFFER_UPDATES = 18;
 constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
@@ -145,15 +148,15 @@
         mBGSurfaceControl = mComposerClient->createSurface(
                 String8("BG Interceptor Test Surface"), displayWidth, displayHeight,
                 PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mBGSurfaceControl != NULL);
+        ASSERT_TRUE(mBGSurfaceControl != nullptr);
         ASSERT_TRUE(mBGSurfaceControl->isValid());
         mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
 
-        SurfaceComposerClient::openGlobalTransaction();
-        mComposerClient->setDisplayLayerStack(display, 0);
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-3));
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction(true);
+        Transaction t;
+        t.setDisplayLayerStack(display, 0);
+        ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+                .show(mBGSurfaceControl)
+                .apply());
     }
 
     virtual void TearDown() {
@@ -169,13 +172,14 @@
     int32_t mTargetId;
 
 public:
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             bool (SurfaceInterceptorTest::* verification)(Trace *));
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             SurfaceChange::SurfaceChangeCase changeCase);
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             Increment::IncrementCase incrementCase);
-    void runInTransaction(void (SurfaceInterceptorTest::* action)(void), bool intercepted = false);
+    void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
+            bool intercepted = false);
 
     // Verification of changes to a surface
     bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -206,28 +210,29 @@
     bool bufferUpdatesFound(Trace* trace);
 
     // Perform each of the possible changes to a surface
-    void positionUpdate();
-    void sizeUpdate();
-    void alphaUpdate();
-    void layerUpdate();
-    void cropUpdate();
-    void finalCropUpdate();
-    void matrixUpdate();
-    void overrideScalingModeUpdate();
-    void transparentRegionHintUpdate();
-    void layerStackUpdate();
-    void hiddenFlagUpdate();
-    void opaqueFlagUpdate();
-    void secureFlagUpdate();
-    void deferredTransactionUpdate();
-    void runAllUpdates();
-    void surfaceCreation();
+    void positionUpdate(Transaction&);
+    void sizeUpdate(Transaction&);
+    void alphaUpdate(Transaction&);
+    void layerUpdate(Transaction&);
+    void cropUpdate(Transaction&);
+    void finalCropUpdate(Transaction&);
+    void matrixUpdate(Transaction&);
+    void overrideScalingModeUpdate(Transaction&);
+    void transparentRegionHintUpdate(Transaction&);
+    void layerStackUpdate(Transaction&);
+    void hiddenFlagUpdate(Transaction&);
+    void opaqueFlagUpdate(Transaction&);
+    void secureFlagUpdate(Transaction&);
+    void deferredTransactionUpdate(Transaction&);
+    void surfaceCreation(Transaction&);
+    void displayCreation(Transaction&);
+    void displayDeletion(Transaction&);
+
     void nBufferUpdates();
-    void displayCreation();
-    void displayDeletion();
+    void runAllUpdates();
 };
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         bool (SurfaceInterceptorTest::* verification)(Trace *))
 {
     runInTransaction(action, true);
@@ -236,7 +241,7 @@
     ASSERT_TRUE((this->*verification)(&capturedTrace));
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         Increment::IncrementCase incrementCase)
 {
     runInTransaction(action, true);
@@ -245,7 +250,7 @@
     ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         SurfaceChange::SurfaceChangeCase changeCase)
 {
     runInTransaction(action, true);
@@ -254,83 +259,84 @@
     ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
 }
 
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
         bool intercepted)
 {
     if (intercepted) {
         enableInterceptor();
     }
-    SurfaceComposerClient::openGlobalTransaction();
-    (this->*action)();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    Transaction t;
+    (this->*action)(t);
+    t.apply(true);
+
     if (intercepted) {
         disableInterceptor();
     }
 }
 
-void SurfaceInterceptorTest::positionUpdate() {
-    mBGSurfaceControl->setPosition(POSITION_UPDATE, POSITION_UPDATE);
+void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
+    t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE);
 }
 
-void SurfaceInterceptorTest::sizeUpdate() {
-    mBGSurfaceControl->setSize(SIZE_UPDATE, SIZE_UPDATE);
+void SurfaceInterceptorTest::sizeUpdate(Transaction& t) {
+    t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE);
 }
 
-void SurfaceInterceptorTest::alphaUpdate() {
-    mBGSurfaceControl->setAlpha(ALPHA_UPDATE);
+void SurfaceInterceptorTest::alphaUpdate(Transaction& t) {
+    t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE);
 }
 
-void SurfaceInterceptorTest::layerUpdate() {
-    mBGSurfaceControl->setLayer(LAYER_UPDATE);
+void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
+    t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
 }
 
-void SurfaceInterceptorTest::cropUpdate() {
-    mBGSurfaceControl->setCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
+    t.setCrop(mBGSurfaceControl, CROP_UPDATE);
 }
 
-void SurfaceInterceptorTest::finalCropUpdate() {
-    mBGSurfaceControl->setFinalCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
+    t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE);
 }
 
-void SurfaceInterceptorTest::matrixUpdate() {
-    mBGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
+void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
+    t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
 }
 
-void SurfaceInterceptorTest::overrideScalingModeUpdate() {
-    mBGSurfaceControl->setOverrideScalingMode(SCALING_UPDATE);
+void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) {
+    t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE);
 }
 
-void SurfaceInterceptorTest::transparentRegionHintUpdate() {
+void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
     Region region(CROP_UPDATE);
-    mBGSurfaceControl->setTransparentRegionHint(region);
+    t.setTransparentRegionHint(mBGSurfaceControl, region);
 }
 
-void SurfaceInterceptorTest::layerStackUpdate() {
-    mBGSurfaceControl->setLayerStack(STACK_UPDATE);
+void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
+    t.setLayerStack(mBGSurfaceControl, STACK_UPDATE);
 }
 
-void SurfaceInterceptorTest::hiddenFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
 }
 
-void SurfaceInterceptorTest::opaqueFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+void SurfaceInterceptorTest::opaqueFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
 }
 
-void SurfaceInterceptorTest::secureFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
 }
 
-void SurfaceInterceptorTest::deferredTransactionUpdate() {
-    mBGSurfaceControl->deferTransactionUntil(mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
+    t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
 }
 
-void SurfaceInterceptorTest::displayCreation() {
+void SurfaceInterceptorTest::displayCreation(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
     SurfaceComposerClient::destroyDisplay(testDisplay);
 }
 
-void SurfaceInterceptorTest::displayDeletion() {
+void SurfaceInterceptorTest::displayDeletion(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
     mTargetId = getDisplayId(DISPLAY_NAME.string());
     SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -353,7 +359,7 @@
     runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
 }
 
-void SurfaceInterceptorTest::surfaceCreation() {
+void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
     mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE,
             PIXEL_FORMAT_RGBA_8888, 0);
 }
@@ -825,8 +831,10 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
-    captureTest(&SurfaceInterceptorTest::nBufferUpdates,
-            &SurfaceInterceptorTest::bufferUpdatesFound);
+    nBufferUpdates();
+    Trace capturedTrace;
+    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
 }
 
 // If the interceptor is enabled while buffer updates are being pushed, the interceptor should
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4ce14f8..5108279 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -14,34 +14,146 @@
  * limitations under the License.
  */
 
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <ostream>
+
 #include <gtest/gtest.h>
 
 #include <android/native_window.h>
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
-#include <utils/String8.h>
 #include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <utils/String8.h>
 
 #include <math.h>
+#include <math/vec3.h>
 
 namespace android {
 
+namespace {
+
+struct Color {
+    uint8_t r;
+    uint8_t g;
+    uint8_t b;
+    uint8_t a;
+
+    static const Color RED;
+    static const Color GREEN;
+    static const Color BLUE;
+    static const Color WHITE;
+    static const Color BLACK;
+    static const Color TRANSPARENT;
+};
+
+const Color Color::RED{255, 0, 0, 255};
+const Color Color::GREEN{0, 255, 0, 255};
+const Color Color::BLUE{0, 0, 255, 255};
+const Color Color::WHITE{255, 255, 255, 255};
+const Color Color::BLACK{0, 0, 0, 255};
+const Color Color::TRANSPARENT{0, 0, 0, 0};
+
+std::ostream& operator<<(std::ostream& os, const Color& color) {
+    os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
+    return os;
+}
+
+// Fill a region with the specified color.
+void fillBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, const Color& color) {
+    int32_t x = rect.left;
+    int32_t y = rect.top;
+    int32_t width = rect.right - rect.left;
+    int32_t height = rect.bottom - rect.top;
+
+    if (x < 0) {
+        width += x;
+        x = 0;
+    }
+    if (y < 0) {
+        height += y;
+        y = 0;
+    }
+    if (x + width > buffer.width) {
+        x = std::min(x, buffer.width);
+        width = buffer.width - x;
+    }
+    if (y + height > buffer.height) {
+        y = std::min(y, buffer.height);
+        height = buffer.height - y;
+    }
+
+    for (int32_t j = 0; j < height; j++) {
+        uint8_t* dst = static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (y + j) + x) * 4;
+        for (int32_t i = 0; i < width; i++) {
+            dst[0] = color.r;
+            dst[1] = color.g;
+            dst[2] = color.b;
+            dst[3] = color.a;
+            dst += 4;
+        }
+    }
+}
+
+// Check if a region has the specified color.
+void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
+                       const Color& color, uint8_t tolerance) {
+    int32_t x = rect.left;
+    int32_t y = rect.top;
+    int32_t width = rect.right - rect.left;
+    int32_t height = rect.bottom - rect.top;
+
+    int32_t bufferWidth = int32_t(outBuffer->getWidth());
+    int32_t bufferHeight = int32_t(outBuffer->getHeight());
+    if (x + width > bufferWidth) {
+        x = std::min(x, bufferWidth);
+        width = bufferWidth - x;
+    }
+    if (y + height > bufferHeight) {
+        y = std::min(y, bufferHeight);
+        height = bufferHeight - y;
+    }
+
+    auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+        uint8_t tmp = a >= b ? a - b : b - a;
+        return tmp <= tolerance;
+    };
+    for (int32_t j = 0; j < height; j++) {
+        const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
+        for (int32_t i = 0; i < width; i++) {
+            const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
+            EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
+                    << "pixel @ (" << x + i << ", " << y + j << "): "
+                    << "expected (" << color << "), "
+                    << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
+            src += 4;
+        }
+    }
+}
+
+} // anonymous namespace
+
+using Transaction = SurfaceComposerClient::Transaction;
+
 // Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
-        uint8_t r, uint8_t g, uint8_t b, bool unlock=true) {
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
+                             bool unlock = true) {
     ANativeWindow_Buffer outBuffer;
     sp<Surface> s = sc->getSurface();
-    ASSERT_TRUE(s != NULL);
-    ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, NULL));
+    ASSERT_TRUE(s != nullptr);
+    ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
     uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
     for (int y = 0; y < outBuffer.height; y++) {
         for (int x = 0; x < outBuffer.width; x++) {
-            uint8_t* pixel = img + (4 * (y*outBuffer.stride + x));
+            uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
             pixel[0] = r;
             pixel[1] = g;
             pixel[2] = b;
@@ -57,67 +169,1346 @@
 // individual pixel values for testing purposes.
 class ScreenCapture : public RefBase {
 public:
-    static void captureScreen(sp<ScreenCapture>* sc) {
-        sp<IGraphicBufferProducer> producer;
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer);
-        sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+    static void captureScreen(sp<ScreenCapture>* sc, int32_t minLayerZ = 0,
+                              int32_t maxLayerZ = std::numeric_limits<int32_t>::max()) {
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> display(sf->getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
-        SurfaceComposerClient::openGlobalTransaction();
-        SurfaceComposerClient::closeGlobalTransaction(true);
-        ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
-                0, INT_MAX, false));
-        *sc = new ScreenCapture(cpuConsumer);
+        sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR,
+                  sf->captureScreen(display, &outBuffer, Rect(), 0, 0, minLayerZ, maxLayerZ,
+                                    false));
+        *sc = new ScreenCapture(outBuffer);
+    }
+
+    static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+                              Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+                                   Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
+    }
+
+    void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        const bool leftBorder = rect.left > 0;
+        const bool topBorder = rect.top > 0;
+        const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
+        const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
+
+        if (topBorder) {
+            Rect top(rect.left, rect.top - 1, rect.right, rect.top);
+            if (leftBorder) {
+                top.left -= 1;
+            }
+            if (rightBorder) {
+                top.right += 1;
+            }
+            expectColor(top, color, tolerance);
+        }
+        if (leftBorder) {
+            Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
+            expectColor(left, color, tolerance);
+        }
+        if (rightBorder) {
+            Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
+            expectColor(right, color, tolerance);
+        }
+        if (bottomBorder) {
+            Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
+            if (leftBorder) {
+                bottom.left -= 1;
+            }
+            if (rightBorder) {
+                bottom.right += 1;
+            }
+            expectColor(bottom, color, tolerance);
+        }
+    }
+
+    void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
+                        const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
+                        uint8_t tolerance = 0) {
+        ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
+
+        const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
+        const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
+        // avoid checking borders due to unspecified filtering behavior
+        const int32_t offsetX = filtered ? 2 : 0;
+        const int32_t offsetY = filtered ? 2 : 0;
+        expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
+                    tolerance);
+        expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
+                    tolerance);
+        expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
+                    tolerance);
+        expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
+                    bottomRight, tolerance);
     }
 
     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
-        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format);
-        const uint8_t* img = static_cast<const uint8_t*>(mBuf.data);
-        const uint8_t* pixel = img + (4 * (y * mBuf.stride + x));
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
             String8 err(String8::format("pixel @ (%3d, %3d): "
-                    "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
-                    x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+                                        "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+                                        x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
             EXPECT_EQ(String8(), err) << err.string();
         }
     }
 
-    void expectFGColor(uint32_t x, uint32_t y) {
-        checkPixel(x, y, 195, 63, 63);
+    void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
+
+    void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
+
+    void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+
+    ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+        mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
     }
 
-    void expectBGColor(uint32_t x, uint32_t y) {
-        checkPixel(x, y, 63, 63, 195);
-    }
-
-    void expectChildColor(uint32_t x, uint32_t y) {
-        checkPixel(x, y, 200, 200, 200);
-    }
+    ~ScreenCapture() { mOutBuffer->unlock(); }
 
 private:
-    ScreenCapture(const sp<CpuConsumer>& cc) :
-        mCC(cc) {
-        EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf));
-    }
-
-    ~ScreenCapture() {
-        mCC->unlockBuffer(mBuf);
-    }
-
-    sp<CpuConsumer> mCC;
-    CpuConsumer::LockedBuffer mBuf;
+    sp<GraphicBuffer> mOutBuffer;
+    uint8_t* mPixels = nullptr;
 };
 
-class LayerUpdateTest : public ::testing::Test {
+class LayerTransactionTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        mClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
+
+        ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+    }
+
+    sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                   uint32_t flags = 0) {
+        auto layer =
+                mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
+        EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+
+        status_t error = Transaction()
+                                 .setLayerStack(layer, mDisplayLayerStack)
+                                 .setLayer(layer, mLayerZBase)
+                                 .apply();
+        if (error != NO_ERROR) {
+            ADD_FAILURE() << "failed to initialize SurfaceControl";
+            layer.clear();
+        }
+
+        return layer;
+    }
+
+    ANativeWindow_Buffer getLayerBuffer(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));
+
+        return buffer;
+    }
+
+    void postLayerBuffer(const sp<SurfaceControl>& layer) {
+        ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+
+        // wait for the newly posted buffer to be latched
+        waitForLayerBuffers();
+    }
+
+    void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color) {
+        ANativeWindow_Buffer buffer;
+        ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
+        fillBufferColor(buffer, Rect(0, 0, buffer.width, buffer.height), color);
+        postLayerBuffer(layer);
+    }
+
+    void fillLayerQuadrant(const sp<SurfaceControl>& layer, const Color& topLeft,
+                           const Color& topRight, const Color& bottomLeft,
+                           const Color& bottomRight) {
+        ANativeWindow_Buffer buffer;
+        ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
+        ASSERT_TRUE(buffer.width % 2 == 0 && buffer.height % 2 == 0);
+
+        const int32_t halfW = buffer.width / 2;
+        const int32_t halfH = buffer.height / 2;
+        fillBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+        fillBufferColor(buffer, Rect(halfW, 0, buffer.width, halfH), topRight);
+        fillBufferColor(buffer, Rect(0, halfH, halfW, buffer.height), bottomLeft);
+        fillBufferColor(buffer, Rect(halfW, halfH, buffer.width, buffer.height), bottomRight);
+
+        postLayerBuffer(layer);
+    }
+
+    sp<ScreenCapture> screenshot() {
+        sp<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot, mLayerZBase);
+        return screenshot;
+    }
+
+    sp<SurfaceComposerClient> mClient;
+
+    sp<IBinder> mDisplay;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+    uint32_t mDisplayLayerStack;
+
+    // leave room for ~256 layers
+    const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
+
+private:
+    void SetUpDisplay() {
+        mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+        ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display";
+
+        // get display width/height
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+        mDisplayWidth = info.w;
+        mDisplayHeight = info.h;
+
+        // 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;
+
+        mDisplayLayerStack = 0;
+        // set layer stack (b/68888219)
+        Transaction t;
+        t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+        t.apply();
+    }
+
+    void waitForLayerBuffers() { usleep(mBufferPostDelay); }
+
+    int32_t mBufferPostDelay;
+};
+
+TEST_F(LayerTransactionTest, SetPositionBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    {
+        SCOPED_TRACE("default position");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    Transaction().setPosition(layer, 5, 10).apply();
+    {
+        SCOPED_TRACE("new position");
+        auto shot = screenshot();
+        shot->expectColor(Rect(5, 10, 37, 42), Color::RED);
+        shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionRounding) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // GLES requires only 4 bits of subpixel precision during rasterization
+    // XXX GLES composition does not match HWC composition due to precision
+    // loss (b/69315223)
+    const float epsilon = 1.0f / 16.0f;
+    Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
+    {
+        SCOPED_TRACE("rounding down");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
+    {
+        SCOPED_TRACE("rounding up");
+        screenshot()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionOutOfBounds) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    Transaction().setPosition(layer, -32, -32).apply();
+    {
+        SCOPED_TRACE("negative coordinates");
+        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+
+    Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
+    {
+        SCOPED_TRACE("positive coordinates");
+        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // partially out of bounds
+    Transaction().setPosition(layer, -30, -30).apply();
+    {
+        SCOPED_TRACE("negative coordinates");
+        screenshot()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+    }
+
+    Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
+    {
+        SCOPED_TRACE("positive coordinates");
+        screenshot()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+                                       mDisplayHeight),
+                                  Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setPosition is applied immediately by default, with or without resize
+    // pending
+    Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(5, 10, 37, 42), Color::RED);
+        shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("resize applied");
+        screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithNextResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // request setPosition to be applied with the next resize
+    Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
+    {
+        SCOPED_TRACE("new position pending");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setPosition(layer, 15, 20).apply();
+    {
+        SCOPED_TRACE("pending new position modified");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    // finally resize and latch the buffer
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("new position applied");
+        screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setPosition is not immediate even with SCALE_TO_WINDOW override
+    Transaction()
+            .setPosition(layer, 5, 10)
+            .setSize(layer, 64, 64)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .setGeometryAppliesWithResize(layer)
+            .apply();
+    {
+        SCOPED_TRACE("new position pending");
+        screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("new position applied");
+        screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetSizeBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    Transaction().setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("resize applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetSizeInvalid) {
+    // cannot test robustness against invalid sizes (zero or really huge)
+}
+
+TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
+    Transaction()
+            .setSize(layer, 64, 64)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetZBasic) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+
+    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("layerR");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setLayer(layerG, mLayerZBase + 2).apply();
+    {
+        SCOPED_TRACE("layerG");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetZNegative) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+
+    Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
+    {
+        SCOPED_TRACE("layerR");
+        sp<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot, -2, -1);
+        screenshot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setLayer(layerR, -3).apply();
+    {
+        SCOPED_TRACE("layerG");
+        sp<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot, -3, -1);
+        screenshot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZBasic) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+
+    Transaction()
+            .setPosition(layerG, 16, 16)
+            .setRelativeLayer(layerG, layerR->getHandle(), 1)
+            .apply();
+    {
+        SCOPED_TRACE("layerG above");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
+    }
+
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
+    {
+        SCOPED_TRACE("layerG below");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZNegative) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    sp<SurfaceControl> layerB;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+
+    // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
+
+    sp<ScreenCapture> screenshot;
+    // only layerB is in this range
+    ScreenCapture::captureScreen(&screenshot, -2, -1);
+    screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZGroup) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    sp<SurfaceControl> layerB;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+
+    // layerR = 0, layerG = layerR + 3, layerB = 2
+    Transaction()
+            .setPosition(layerG, 8, 8)
+            .setRelativeLayer(layerG, layerR->getHandle(), 3)
+            .setPosition(layerB, 16, 16)
+            .setLayer(layerB, mLayerZBase + 2)
+            .apply();
+    {
+        SCOPED_TRACE("(layerR < layerG) < layerB");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+        shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+    }
+
+    // layerR = 4, layerG = layerR + 3, layerB = 2
+    Transaction().setLayer(layerR, mLayerZBase + 4).apply();
+    {
+        SCOPED_TRACE("layerB < (layerR < layerG)");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+        shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
+        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+    }
+
+    // layerR = 4, layerG = layerR - 3, layerB = 2
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
+    {
+        SCOPED_TRACE("layerB < (layerG < layerR)");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
+        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+    }
+
+    // restore to absolute z
+    // layerR = 4, layerG = 0, layerB = 2
+    Transaction().setLayer(layerG, mLayerZBase).apply();
+    {
+        SCOPED_TRACE("layerG < layerB < layerR");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
+    }
+
+    // layerR should not affect layerG anymore
+    // layerR = 1, layerG = 0, layerB = 2
+    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("layerG < layerR < layerB");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZBug64572777) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+
+    Transaction()
+            .setPosition(layerG, 16, 16)
+            .setRelativeLayer(layerG, layerR->getHandle(), 1)
+            .apply();
+
+    mClient->destroySurface(layerG->getHandle());
+    // layerG should have been removed
+    screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetFlagsHidden) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
+    {
+        SCOPED_TRACE("layer hidden");
+        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+
+    Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
+    {
+        SCOPED_TRACE("layer shown");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFlagsOpaque) {
+    const Color translucentRed = {100, 0, 0, 100};
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+
+    Transaction()
+            .setLayer(layerR, mLayerZBase + 1)
+            .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+            .apply();
+    {
+        SCOPED_TRACE("layerR opaque");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+    }
+
+    Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
+    {
+        SCOPED_TRACE("layerR translucent");
+        const uint8_t g = uint8_t(255 - translucentRed.a);
+        screenshot()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFlagsSecure) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<GraphicBuffer> outBuffer;
+    Transaction()
+            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+            .apply(true);
+    ASSERT_EQ(PERMISSION_DENIED,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase,
+                                      false));
+
+    Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase,
+                                      false));
+}
+
+TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic) {
+    const Rect top(0, 0, 32, 16);
+    const Rect bottom(0, 16, 32, 32);
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+    ANativeWindow_Buffer buffer;
+    ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::RED));
+    // setTransparentRegionHint always applies to the following buffer
+    Transaction().setTransparentRegionHint(layer, Region(top)).apply();
+    ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+    {
+        SCOPED_TRACE("top transparent");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+    {
+        SCOPED_TRACE("transparent region hint pending");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+    {
+        SCOPED_TRACE("bottom transparent");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::RED);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds) {
+    sp<SurfaceControl> layerTransparent;
+    sp<SurfaceControl> layerR;
+    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+
+    // check that transparent region hint is bound by the layer size
+    Transaction()
+            .setTransparentRegionHint(layerTransparent,
+                                      Region(Rect(0, 0, mDisplayWidth, mDisplayHeight)))
+            .setPosition(layerR, 16, 16)
+            .setLayer(layerR, mLayerZBase + 1)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetAlphaBasic) {
+    sp<SurfaceControl> layer1;
+    sp<SurfaceControl> layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}));
+
+    Transaction()
+            .setAlpha(layer1, 0.25f)
+            .setAlpha(layer2, 0.75f)
+            .setPosition(layer2, 16, 0)
+            .setLayer(layer2, mLayerZBase + 1)
+            .apply();
+    {
+        auto shot = screenshot();
+        uint8_t r = 16; // 64 * 0.25f
+        uint8_t g = 48; // 64 * 0.75f
+        shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
+        shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
+
+        r /= 4; // r * (1.0f - 0.75f)
+        shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
+    }
+}
+
+TEST_F(LayerTransactionTest, SetAlphaClamped) {
+    const Color color = {64, 0, 0, 255};
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color));
+
+    Transaction().setAlpha(layer, 2.0f).apply();
+    {
+        SCOPED_TRACE("clamped to 1.0f");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), color);
+    }
+
+    Transaction().setAlpha(layer, -1.0f).apply();
+    {
+        SCOPED_TRACE("clamped to 0.0f");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetColorBasic) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+    Transaction().setLayer(colorLayer, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("default color");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const Color expected = {15, 51, 85, 255};
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction().setColor(colorLayer, color).apply();
+    {
+        SCOPED_TRACE("new color");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetColorClamped) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+    Transaction().setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)).apply();
+    screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetColorWithAlpha) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const float alpha = 0.25f;
+    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction()
+            .setColor(colorLayer, color)
+            .setAlpha(colorLayer, alpha)
+            .setLayer(colorLayer, mLayerZBase + 1)
+            .apply();
+    screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+                              tolerance);
+}
+
+TEST_F(LayerTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> parentLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer(
+            "childWithColor", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const float alpha = 0.25f;
+    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+    // this is handwavy, but the precision loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction()
+            .reparent(colorLayer, parentLayer->getHandle())
+            .setColor(colorLayer, color)
+            .setAlpha(parentLayer, alpha)
+            .setLayer(parentLayer, mLayerZBase + 1)
+            .apply();
+    screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+                              tolerance);
+}
+
+TEST_F(LayerTransactionTest, SetColorWithBuffer) {
+    sp<SurfaceControl> bufferLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+
+    // color is ignored
+    Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
+    screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetLayerStackBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+    {
+        SCOPED_TRACE("non-existing layer stack");
+        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+
+    Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
+    {
+        SCOPED_TRACE("original layer stack");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetMatrixBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("IDENTITY");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
+    {
+        SCOPED_TRACE("FLIP_H");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+                                     Color::BLUE);
+    }
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
+    {
+        SCOPED_TRACE("FLIP_V");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+                                     Color::GREEN);
+    }
+
+    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
+    {
+        SCOPED_TRACE("ROT_90");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+                                     Color::GREEN);
+    }
+
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("SCALE");
+        screenshot()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE, true /* filtered */);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetMatrixRot45) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+
+    const float rot = M_SQRT1_2; // 45 degrees
+    const float trans = M_SQRT2 * 16.0f;
+    Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
+
+    auto shot = screenshot();
+    // check a 8x8 region inside each color
+    auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
+        const int32_t halfL = 4;
+        return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
+    };
+    const int32_t unit = int32_t(trans / 2);
+    shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
+    shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
+    shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
+    shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
+}
+
+TEST_F(LayerTransactionTest, SetMatrixWithResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setMatrix is applied after any pending resize, unlike setPosition
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("resize applied");
+        screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setSize(layer, 64, 64)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+
+    // XXX SCALE_CROP is not respected; calling setSize and
+    // setOverrideScalingMode in separate transactions does not work
+    // (b/69315456)
+    Transaction()
+            .setSize(layer, 64, 16)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    {
+        SCOPED_TRACE("SCALE_TO_WINDOW");
+        screenshot()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE, true /* filtered */);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    const Rect crop(8, 8, 24, 24);
+
+    Transaction().setCrop(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop, Color::RED);
+    shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropEmpty) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropOutOfBounds) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithTranslation) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    const Point position(32, 32);
+    const Rect crop(8, 8, 24, 24);
+    Transaction().setPosition(layer, position.x, position.y).setCrop(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop + position, Color::RED);
+    shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithScale) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // crop is affected by matrix
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setCrop(layer, Rect(8, 8, 24, 24))
+            .apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setCrop is applied immediately by default, with or without resize pending
+    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+        shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("resize applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // request setCrop to be applied with the next resize
+    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
+    {
+        SCOPED_TRACE("waiting for next resize");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
+    {
+        SCOPED_TRACE("pending crop modified");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    // finally resize
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("new crop applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // setCrop is not immediate even with SCALE_TO_WINDOW override
+    Transaction()
+            .setCrop(layer, Rect(4, 4, 12, 12))
+            .setSize(layer, 16, 16)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .setGeometryAppliesWithResize(layer)
+            .apply();
+    {
+        SCOPED_TRACE("new crop pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
+    }
+
+    // XXX crop is never latched without other geometry change (b/69315677)
+    Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    Transaction().setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("new crop applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    const Rect crop(8, 8, 24, 24);
+
+    // same as in SetCropBasic
+    Transaction().setFinalCrop(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop, Color::RED);
+    shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropEmpty) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // same as in SetCropEmpty
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setFinalCrop(layer, Rect(8, 8, 8, 8)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setFinalCrop(layer, Rect(8, 8, 0, 0)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // same as in SetCropOutOfBounds
+    Transaction().setFinalCrop(layer, Rect(-128, -64, 128, 64)).apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropWithTranslation) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // final crop is applied post-translation
+    Transaction().setPosition(layer, 16, 16).setFinalCrop(layer, Rect(8, 8, 24, 24)).apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(16, 16, 24, 24), Color::RED);
+    shot->expectBorder(Rect(16, 16, 24, 24), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropWithScale) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // final crop is not affected by matrix
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setFinalCrop(layer, Rect(8, 8, 24, 24))
+            .apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+    shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropWithResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // same as in SetCropWithResize
+    Transaction().setFinalCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+        shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("resize applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropWithNextResize) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // same as in SetCropWithNextResize
+    Transaction()
+            .setFinalCrop(layer, Rect(8, 8, 24, 24))
+            .setGeometryAppliesWithResize(layer)
+            .apply();
+    {
+        SCOPED_TRACE("waiting for next resize");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setFinalCrop(layer, Rect(4, 4, 12, 12)).apply();
+    {
+        SCOPED_TRACE("pending final crop modified");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    // finally resize
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    {
+        SCOPED_TRACE("new final crop applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+
+    // same as in SetCropWithNextResizeScaleToWindow
+    Transaction()
+            .setFinalCrop(layer, Rect(4, 4, 12, 12))
+            .setSize(layer, 16, 16)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .setGeometryAppliesWithResize(layer)
+            .apply();
+    {
+        SCOPED_TRACE("new final crop pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
+    }
+
+    // XXX final crop is never latched without other geometry change (b/69315677)
+    Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    Transaction().setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("new final crop applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+class LayerUpdateTest : public LayerTransactionTest {
 protected:
     virtual void SetUp() {
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
-        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
+        sp<IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
         DisplayInfo info;
         SurfaceComposerClient::getDisplayInfo(display, &info);
 
@@ -125,46 +1516,42 @@
         ssize_t displayHeight = info.h;
 
         // Background surface
-        mBGSurfaceControl = mComposerClient->createSurface(
-                String8("BG Test Surface"), displayWidth, displayHeight,
-                PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mBGSurfaceControl != NULL);
+        mBGSurfaceControl =
+                mComposerClient->createSurface(String8("BG Test Surface"), displayWidth,
+                                               displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mBGSurfaceControl != nullptr);
         ASSERT_TRUE(mBGSurfaceControl->isValid());
         fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
 
         // Foreground surface
-        mFGSurfaceControl = mComposerClient->createSurface(
-                String8("FG Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mFGSurfaceControl != NULL);
+        mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+                                                           PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mFGSurfaceControl != nullptr);
         ASSERT_TRUE(mFGSurfaceControl->isValid());
 
         fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
 
         // Synchronization surface
-        mSyncSurfaceControl = mComposerClient->createSurface(
-                String8("Sync Test Surface"), 1, 1, PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mSyncSurfaceControl != NULL);
+        mSyncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+                                                             PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mSyncSurfaceControl != nullptr);
         ASSERT_TRUE(mSyncSurfaceControl->isValid());
 
         fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
 
-        SurfaceComposerClient::openGlobalTransaction();
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
 
-        mComposerClient->setDisplayLayerStack(display, 0);
+            t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
 
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX-2));
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+            t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
+                    .setPosition(mFGSurfaceControl, 64, 64)
+                    .show(mFGSurfaceControl);
 
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX-1));
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
-
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT32_MAX-1));
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
-                displayHeight-2));
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
-
-        SurfaceComposerClient::closeGlobalTransaction(true);
+            t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
+                    .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
+                    .show(mSyncSurfaceControl);
+        });
     }
 
     virtual void TearDown() {
@@ -185,6 +1572,12 @@
         fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
     }
 
+    void asTransaction(const std::function<void(Transaction&)>& exec) {
+        Transaction t;
+        exec(t);
+        t.apply(true);
+    }
+
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
     sp<SurfaceControl> mFGSurfaceControl;
@@ -194,287 +1587,45 @@
     sp<SurfaceControl> mSyncSurfaceControl;
 };
 
-TEST_F(LayerUpdateTest, LayerMoveWorks) {
+TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
     sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before move");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(0, 12);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should reflect the new position, but not the new color.
-        SCOPED_TRACE("after move, before redraw");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectFGColor(145, 145);
-    }
-
-    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+    sp<SurfaceControl> relative = mComposerClient->createSurface(String8("relativeTestSurface"), 10,
+                                                                 10, PIXEL_FORMAT_RGBA_8888, 0);
+    fillSurfaceRGBA8(relative, 10, 10, 10);
     waitForPostedBuffers();
-    {
-        // This should reflect the new position and the new color.
-        SCOPED_TRACE("after redraw");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->checkPixel(145, 145, 63, 195, 63);
-    }
-}
 
-TEST_F(LayerUpdateTest, LayerResizeWorks) {
-    sp<ScreenCapture> sc;
+    Transaction{}
+            .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
+            .setPosition(relative, 64, 64)
+            .apply();
+
     {
-        SCOPED_TRACE("before resize");
+        // The relative should be on top of the FG control.
         ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(0, 12);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
+        sc->checkPixel(64, 64, 10, 10, 10);
+    }
+    Transaction{}.detachChildren(mFGSurfaceControl).apply();
+
+    {
+        // Nothing should change at this point.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(64, 64, 10, 10, 10);
     }
 
-    ALOGD("resizing");
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    ALOGD("resized");
-    {
-        // This should not reflect the new size or color because SurfaceFlinger
-        // has not yet received a buffer of the correct size.
-        SCOPED_TRACE("after resize, before redraw");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(0, 12);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
+    Transaction{}.hide(relative).apply();
 
-    ALOGD("drawing");
-    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
-    waitForPostedBuffers();
-    ALOGD("drawn");
     {
-        // This should reflect the new size and the new color.
-        SCOPED_TRACE("after redraw");
+        // Ensure that the relative was actually hidden, rather than
+        // being left in the detached but visible state.
         ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->checkPixel(75, 75, 63, 195, 63);
-        sc->checkPixel(145, 145, 63, 195, 63);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerCropWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before crop");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    Rect cropRect(16, 16, 32, 32);
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should crop the foreground surface.
-        SCOPED_TRACE("after crop");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectFGColor(95, 80);
-        sc->expectFGColor(80, 95);
-        sc->expectBGColor(96, 96);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerFinalCropWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before crop");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-    SurfaceComposerClient::openGlobalTransaction();
-    Rect cropRect(16, 16, 32, 32);
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should crop the foreground surface.
-        SCOPED_TRACE("after crop");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectBGColor(95, 80);
-        sc->expectBGColor(80, 95);
-        sc->expectBGColor(96, 96);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerSetLayerWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before setLayer");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should hide the foreground surface beneath the background.
-        SCOPED_TRACE("after setLayer");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerShowHideWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before hide");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should hide the foreground surface.
-        SCOPED_TRACE("after hide, before show");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should show the foreground surface.
-        SCOPED_TRACE("after show");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerSetAlphaWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before setAlpha");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should set foreground to be 75% opaque.
-        SCOPED_TRACE("after setAlpha");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->checkPixel(75, 75, 162, 63, 96);
-        sc->expectBGColor(145, 145);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerSetLayerStackWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before setLayerStack");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should hide the foreground surface since it goes to a different
-        // layer stack.
-        SCOPED_TRACE("after setLayerStack");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerSetFlagsWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before setFlags");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags(
-            layer_state_t::eLayerHidden, layer_state_t::eLayerHidden));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        // This should hide the foreground surface
-        SCOPED_TRACE("after setFlags");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectBGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerSetMatrixWorks) {
-    sp<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before setMatrix");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(91, 96);
-        sc->expectFGColor(96, 101);
-        sc->expectBGColor(145, 145);
-    }
-
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2,
-            -M_SQRT1_2, M_SQRT1_2));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-    {
-        SCOPED_TRACE("after setMatrix");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
-        sc->expectFGColor(91, 96);
-        sc->expectBGColor(96, 91);
-        sc->expectBGColor(145, 145);
+        sc->expectFGColor(64, 64);
     }
 }
 
 class GeometryLatchingTest : public LayerUpdateTest {
 protected:
-    void EXPECT_INITIAL_STATE(const char * trace) {
+    void EXPECT_INITIAL_STATE(const char* trace) {
         SCOPED_TRACE(trace);
         ScreenCapture::captureScreen(&sc);
         // We find the leading edge of the FG surface.
@@ -482,9 +1633,7 @@
         sc->expectBGColor(128, 128);
     }
 
-    void lockAndFillFGBuffer() {
-        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false);
-    }
+    void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); }
 
     void unlockFGBuffer() {
         sp<Surface> s = mFGSurfaceControl->getSurface();
@@ -497,65 +1646,18 @@
         waitForPostedBuffers();
     }
     void restoreInitialState() {
-        SurfaceComposerClient::openGlobalTransaction();
-        mFGSurfaceControl->setSize(64, 64);
-        mFGSurfaceControl->setPosition(64, 64);
-        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
-        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
-        SurfaceComposerClient::closeGlobalTransaction(true);
+        asTransaction([&](Transaction& t) {
+            t.setSize(mFGSurfaceControl, 64, 64);
+            t.setPosition(mFGSurfaceControl, 64, 64);
+            t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+            t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+        });
 
         EXPECT_INITIAL_STATE("After restoring initial state");
     }
     sp<ScreenCapture> sc;
 };
 
-TEST_F(GeometryLatchingTest, SurfacePositionLatching) {
-    EXPECT_INITIAL_STATE("before anything");
-
-    // By default position can be updated even while
-    // a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(32, 32);
-    mFGSurfaceControl->setPosition(100, 100);
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    {
-        SCOPED_TRACE("After moving surface");
-        ScreenCapture::captureScreen(&sc);
-        // If we moved, the FG Surface should cover up what was previously BG
-        // however if we didn't move the FG wouldn't be large enough now.
-        sc->expectFGColor(163, 163);
-    }
-
-    restoreInitialState();
-
-    // Now we repeat with setGeometryAppliesWithResize
-    // and verify the position DOESN'T latch.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setSize(32, 32);
-    mFGSurfaceControl->setPosition(100, 100);
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    {
-        SCOPED_TRACE("While resize is pending");
-        ScreenCapture::captureScreen(&sc);
-        // This time we shouldn't have moved, so the BG color
-        // should still be visible.
-        sc->expectBGColor(128, 128);
-    }
-
-    completeFGResize();
-
-    {
-        SCOPED_TRACE("After the resize");
-        ScreenCapture::captureScreen(&sc);
-        // But after the resize completes, we should move
-        // and the FG should be visible here.
-        sc->expectFGColor(128, 128);
-    }
-}
-
 class CropLatchingTest : public GeometryLatchingTest {
 protected:
     void EXPECT_CROPPED_STATE(const char* trace) {
@@ -577,65 +1679,15 @@
     }
 };
 
-TEST_F(CropLatchingTest, CropLatching) {
-    EXPECT_INITIAL_STATE("before anything");
-    // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
-
-    restoreInitialState();
-
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
-
-    completeFGResize();
-
-    EXPECT_CROPPED_STATE("after the resize finishes");
-}
-
-TEST_F(CropLatchingTest, FinalCropLatching) {
-    EXPECT_INITIAL_STATE("before anything");
-    // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
-
-    restoreInitialState();
-
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
-
-    completeFGResize();
-
-    EXPECT_CROPPED_STATE("after the resize finishes");
-}
-
 // In this test we ensure that setGeometryAppliesWithResize actually demands
 // a buffer of the new size, and not just any size.
 TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
     EXPECT_INITIAL_STATE("before anything");
     // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
 
@@ -645,11 +1697,11 @@
     // initiating the resize.
     lockAndFillFGBuffer();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
 
@@ -664,30 +1716,6 @@
     EXPECT_CROPPED_STATE("after the resize finishes");
 }
 
-TEST_F(CropLatchingTest, FinalCropLatchingRegressionForb37531386) {
-    EXPECT_INITIAL_STATE("before anything");
-    // In this scenario, we attempt to set the final crop a second time while the resize
-    // is still pending, and ensure we are successful. Success meaning the second crop
-    // is the one which eventually latches and not the first.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize");
-
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
-    EXPECT_INITIAL_STATE("after setting another crop");
-
-    completeFGResize();
-
-    EXPECT_RESIZE_STATE("after the resize finishes");
-}
-
 TEST_F(LayerUpdateTest, DeferredTransactionTest) {
     sp<ScreenCapture> sc;
     {
@@ -699,17 +1727,17 @@
     }
 
     // set up two deferred transactions on different frames
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
-    mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
-            mSyncSurfaceControl->getSurface()->getNextFrameNumber());
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 0.75);
+        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+    });
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128));
-    mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
-            mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 128, 128);
+        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+    });
 
     {
         SCOPED_TRACE("before any trigger");
@@ -730,9 +1758,7 @@
     }
 
     // should show up immediately since it's not deferred
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
 
     // trigger the second deferred transaction
     fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
@@ -745,46 +1771,55 @@
     }
 }
 
-TEST_F(LayerUpdateTest, LayerSetRelativeLayerWorks) {
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+    sp<ScreenCapture> sc;
+
+    sp<SurfaceControl> childNoBuffer =
+            mComposerClient->createSurface(String8("Bufferless child"), 10, 10,
+                                           PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    sp<SurfaceControl> childBuffer =
+            mComposerClient->createSurface(String8("Buffered child"), 20, 20,
+                                           PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+    fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction{}.show(childNoBuffer).show(childBuffer).apply(true);
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectFGColor(74, 74);
+    }
+
+    SurfaceComposerClient::Transaction{}.setSize(childNoBuffer, 20, 20).apply(true);
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectChildColor(74, 74);
+    }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactions) {
     sp<ScreenCapture> sc;
     {
-        SCOPED_TRACE("before adding relative surface");
+        SCOPED_TRACE("before move");
         ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(24, 24);
+        sc->expectBGColor(0, 12);
         sc->expectFGColor(75, 75);
         sc->expectBGColor(145, 145);
     }
 
-    auto relativeSurfaceControl = mComposerClient->createSurface(
-            String8("Test Surface"), 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
-    fillSurfaceRGBA8(relativeSurfaceControl, 255, 177, 177);
-    waitForPostedBuffers();
-
-    // Now we stack the surface above the foreground surface and make sure it is visible.
-    SurfaceComposerClient::openGlobalTransaction();
-    relativeSurfaceControl->setPosition(64, 64);
-    relativeSurfaceControl->show();
-    relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
+    Transaction t1, t2;
+    t1.setPosition(mFGSurfaceControl, 128, 128);
+    t2.setPosition(mFGSurfaceControl, 0, 0);
+    // We expect that the position update from t2 now
+    // overwrites the position update from t1.
+    t1.merge(std::move(t2));
+    t1.apply();
 
     {
-        SCOPED_TRACE("after adding relative surface");
         ScreenCapture::captureScreen(&sc);
-        // our relative surface should be visible now.
-        sc->checkPixel(75, 75, 255, 177, 177);
-    }
-
-    // A call to setLayer will override a call to setRelativeLayer
-    SurfaceComposerClient::openGlobalTransaction();
-    relativeSurfaceControl->setLayer(0);
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    {
-        SCOPED_TRACE("after set layer");
-        ScreenCapture::captureScreen(&sc);
-        // now the FG surface should be visible again.
-        sc->expectFGColor(75, 75);
+        sc->expectFGColor(1, 1);
     }
 }
 
@@ -792,10 +1827,8 @@
 protected:
     void SetUp() override {
         LayerUpdateTest::SetUp();
-        mChild = mComposerClient->createSurface(
-                String8("Child surface"),
-                10, 10, PIXEL_FORMAT_RGBA_8888,
-                0, mFGSurfaceControl.get());
+        mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
         fillSurfaceRGBA8(mChild, 200, 200, 200);
 
         {
@@ -814,11 +1847,11 @@
 };
 
 TEST_F(ChildLayerTest, ChildLayerPositioning) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -830,9 +1863,7 @@
         mCapture->expectFGColor(84, 84);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -846,12 +1877,12 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerCropping) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -862,12 +1893,12 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerFinalCropping) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -878,11 +1909,11 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerConstraints) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mFGSurfaceControl->setPosition(0, 0);
-    mChild->setPosition(63, 63);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setPosition(mChild, 63, 63);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -896,9 +1927,7 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerScaling) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
 
     // Find the boundary between the parent and child
     {
@@ -907,9 +1936,7 @@
         mCapture->expectFGColor(10, 10);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
 
     // The boundary should be twice as far from the origin now.
     // The pixels from the last test should all be child now
@@ -928,11 +1955,11 @@
     fillSurfaceRGBA8(mChild, 0, 254, 0);
     waitForPostedBuffers();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -940,9 +1967,7 @@
         mCapture->checkPixel(0, 0, 0, 254, 0);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -950,9 +1975,7 @@
         mCapture->checkPixel(0, 0, 127, 127, 0);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -962,11 +1985,11 @@
 }
 
 TEST_F(ChildLayerTest, ReparentChildren) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -977,7 +2000,11 @@
         // And 10 more pixels we should be back to the foreground surface
         mCapture->expectFGColor(84, 84);
     }
-    mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle());
+
+    asTransaction([&](Transaction& t) {
+        t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+    });
+
     {
         ScreenCapture::captureScreen(&mCapture);
         mCapture->expectFGColor(64, 64);
@@ -990,12 +2017,12 @@
     }
 }
 
-TEST_F(ChildLayerTest, DetachChildren) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1007,13 +2034,51 @@
         mCapture->expectFGColor(84, 84);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->detachChildren();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->hide();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) { t.hide(mChild); });
+
+    // Since the child has the same client as the parent, it will not get
+    // detached and will be hidden.
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectFGColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+    sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> mChildNewClient =
+            mNewComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+    ASSERT_TRUE(mChildNewClient != nullptr);
+    ASSERT_TRUE(mChildNewClient->isValid());
+
+    fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(mChildNewClient);
+        t.setPosition(mChildNewClient, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+    asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
 
     // Nothing should have changed.
     {
@@ -1025,11 +2090,11 @@
 }
 
 TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1039,11 +2104,11 @@
         mCapture->expectFGColor(10, 10);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-    // We cause scaling by 2.
-    mFGSurfaceControl->setSize(128, 128);
-    SurfaceComposerClient::closeGlobalTransaction();
+    asTransaction([&](Transaction& t) {
+        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // We cause scaling by 2.
+        t.setSize(mFGSurfaceControl, 128, 128);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1058,11 +2123,11 @@
 
 // Regression test for b/37673612
 TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1071,11 +2136,9 @@
         // But it's only 10x10.
         mCapture->expectFGColor(10, 10);
     }
-
-
     // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
     // the WM specified state size.
-    mFGSurfaceControl->setSize(128, 64);
+    asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
     sp<Surface> s = mFGSurfaceControl->getSurface();
     auto anw = static_cast<ANativeWindow*>(s.get());
     native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1102,11 +2165,11 @@
                                             mFGSurfaceControl.get());
 
     // Show the child layer in a deferred transaction
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(),
-                                  mFGSurfaceControl->getSurface()->getNextFrameNumber());
-    mChild->show();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
+                                mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        t.show(mChild);
+    });
 
     // Render the foreground surface a few times
     //
@@ -1123,4 +2186,508 @@
     fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
 }
 
+TEST_F(ChildLayerTest, Reparent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+        // In reparenting we should have exposed the entire foreground surface.
+        mCapture->expectFGColor(74, 74);
+        // And the child layer should now begin at 10, 10 (since the BG
+        // layer is at (0, 0)).
+        mCapture->expectBGColor(9, 9);
+        mCapture->expectChildColor(10, 10);
+    }
 }
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+    asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Nothing should have changed.
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectChildColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+    sp<SurfaceControl> newSurface = mComposerClient->createSurface(String8("New Surface"), 10, 10,
+                                                                   PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(newSurface != nullptr);
+    ASSERT_TRUE(newSurface->isValid());
+
+    fillSurfaceRGBA8(newSurface, 63, 195, 63);
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(newSurface);
+        t.setPosition(newSurface, 10, 10);
+        t.setLayer(newSurface, INT32_MAX - 2);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // At 10, 10 we should see the new surface
+        mCapture->checkPixel(10, 10, 63, 195, 63);
+    }
+
+    asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+        // mFGSurface, putting it at 74, 74.
+        mCapture->expectFGColor(64, 64);
+        mCapture->checkPixel(74, 74, 63, 195, 63);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+    sp<SurfaceControl> grandchild =
+            mComposerClient->createSurface(String8("Grandchild surface"), 10, 10,
+                                           PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+        // which begins at 64, 64
+        mCapture->checkPixel(64, 64, 50, 50, 50);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
+    sp<SurfaceControl> relative = mComposerClient->createSurface(String8("Relative surface"), 128,
+                                                                 128, PIXEL_FORMAT_RGBA_8888, 0);
+    fillSurfaceRGBA8(relative, 255, 255, 255);
+
+    Transaction t;
+    t.setLayer(relative, INT32_MAX)
+            .setRelativeLayer(mChild, relative->getHandle(), 1)
+            .setPosition(mFGSurfaceControl, 0, 0)
+            .apply(true);
+
+    // We expect that the child should have been elevated above our
+    // INT_MAX layer even though it's not a child of it.
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(9, 9);
+        mCapture->checkPixel(10, 10, 255, 255, 255);
+    }
+}
+
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+    std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+    auto bgHandle = mBGSurfaceControl->getHandle();
+    ScreenCapture::captureLayers(&mCapture, bgHandle);
+    mCapture->expectBGColor(0, 0);
+    // Doesn't capture FG layer which is at 64, 64
+    mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    // Captures mFGSurfaceControl layer and its child.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    // Captures mFGSurfaceControl's child
+    ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+
+    fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    auto childHandle = child->getHandle();
+
+    // Captures child
+    ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+    mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+    // Area outside of child's bounds is transparent.
+    mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
+TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    sp<SurfaceControl> relative = mComposerClient->createSurface(String8("Relative surface"), 10,
+                                                                 10, PIXEL_FORMAT_RGBA_8888, 0);
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    fillSurfaceRGBA8(relative, 100, 100, 100);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            // Set relative layer above fg layer so should be shown above when computing all layers.
+            .setRelativeLayer(relative, fgHandle, 1)
+            .show(relative)
+            .apply(true);
+
+    // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    sp<SurfaceControl> relative =
+            mComposerClient->createSurface(String8("Relative surface"), 10, 10,
+                                           PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    fillSurfaceRGBA8(relative, 100, 100, 100);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            // Set relative layer below fg layer but relative to child layer so it should be shown
+            // above child layer.
+            .setLayer(relative, -1)
+            .setRelativeLayer(relative, child->getHandle(), 1)
+            .show(relative)
+            .apply(true);
+
+    // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
+    // relative value should be taken into account, placing it above child layer.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    // Relative layer is showing on top of child layer
+    mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
+}
+
+// In the following tests we verify successful skipping of a parent layer,
+// so we use the same verification logic and only change how we mutate
+// the parent layer to verify that various properties are ignored.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+
+        mChild =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                    0, mFGSurfaceControl.get());
+        fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+        SurfaceComposerClient::Transaction().show(mChild).apply(true);
+    }
+
+    void verify() {
+        auto fgHandle = mFGSurfaceControl->getHandle();
+        ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+        mCapture->checkPixel(10, 10, 0, 0, 0);
+        mCapture->expectChildColor(0, 0);
+    }
+
+    std::unique_ptr<ScreenCapture> mCapture;
+    sp<SurfaceControl> mChild;
+};
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+
+    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+    // Even though the parent is hidden we should still capture the child.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+
+    SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
+
+    // Even though the parent is cropped out we should still capture the child.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+
+    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2);
+
+    // We should not inherit the parent scaling.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, RegressionTest76099859) {
+    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+    // Even though the parent is hidden we should still capture the child.
+    verify();
+
+    // Verify everything was properly hidden when rendering the full-screen.
+    screenshot()->expectBGColor(0,0);
+}
+
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+
+    sp<SurfaceControl> grandchild =
+            mComposerClient->createSurface(String8("Grandchild surface"), 5, 5,
+                                           PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .setPosition(grandchild, 5, 5)
+            .show(grandchild)
+            .apply(true);
+
+    // Captures mFGSurfaceControl, its child, and the grandchild.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+    mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
+
+    // Captures only the child layer, and not the parent.
+    ScreenCapture::captureLayers(&mCapture, childHandle);
+    mCapture->expectChildColor(0, 0);
+    mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    sp<SurfaceControl> grandchild =
+            mComposerClient->createSurface(String8("Grandchild surface"), 5, 5,
+                                           PIXEL_FORMAT_RGBA_8888, 0, child.get());
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .setPosition(grandchild, 5, 5)
+            .show(grandchild)
+            .apply(true);
+
+    auto grandchildHandle = grandchild->getHandle();
+
+    // Captures only the grandchild.
+    ScreenCapture::captureLayers(&mCapture, grandchildHandle);
+    mCapture->checkPixel(0, 0, 50, 50, 50);
+    mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+    sp<SurfaceControl> blueLayer =
+            mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
+                                           0, redLayer.get());
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+
+    SurfaceComposerClient::Transaction()
+            .setLayer(redLayer, INT32_MAX - 1)
+            .show(redLayer)
+            .show(blueLayer)
+            .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+    Rect crop = Rect(0, 0, 30, 30);
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
+    // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+    // area visible.
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+    sp<SurfaceControl> blueLayer =
+            mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
+                                           0, redLayer.get());
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+
+    SurfaceComposerClient::Transaction()
+            .setLayer(redLayer, INT32_MAX - 1)
+            .show(redLayer)
+            .show(blueLayer)
+            .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+    // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+    mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
+
+    auto redLayerHandle = redLayer->getHandle();
+    mComposerClient->destroySurface(redLayerHandle);
+    SurfaceComposerClient::Transaction().apply(true);
+
+    sp<GraphicBuffer> outBuffer;
+
+    // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
+}
+
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+    void SetUp() override {
+        LayerTransactionTest::SetUp();
+        bgLayer = createLayer("BG layer", 20, 20);
+        fillLayerColor(bgLayer, Color::RED);
+        fgLayer = createLayer("FG layer", 20, 20);
+        fillLayerColor(fgLayer, Color::BLUE);
+        Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+        {
+            SCOPED_TRACE("before anything");
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+        }
+    }
+    void TearDown() override {
+        LayerTransactionTest::TearDown();
+        bgLayer = 0;
+        fgLayer = 0;
+    }
+
+    sp<SurfaceControl> bgLayer;
+    sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+    }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+    auto transaction = Transaction().show(fgLayer);
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
new file mode 100644
index 0000000..5fa8a09
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -0,0 +1,42 @@
+cc_test {
+    name: "sffakehwc_test",
+    defaults: ["surfaceflinger_defaults"],
+    tags: ["test"],
+    test_suites: ["device-tests"],
+    srcs: [
+         "FakeComposerClient.cpp",
+         "FakeComposerService.cpp",
+         "FakeComposerUtils.cpp",
+         "SFFakeHwc_test.cpp"
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.power@1.3",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libgui",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblayers_proto",
+        "liblog",
+        "libnativewindow",
+        "libsync",
+        "libtimestats_proto",
+        "libui",
+        "libutils",
+    ],
+    static_libs: [
+        "libtrace_proto",
+        "libgmock"
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.1-hal",
+        "libsurfaceflinger_headers",
+    ],
+}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
new file mode 100644
index 0000000..973156a
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeComposer"
+
+#include "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+#include <inttypes.h>
+#include <time.h>
+#include <algorithm>
+#include <condition_variable>
+#include <iostream>
+#include <mutex>
+#include <set>
+#include <thread>
+
+constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
+
+using namespace sftest;
+
+using android::Condition;
+using android::Mutex;
+
+using Clock = std::chrono::steady_clock;
+using TimePoint = std::chrono::time_point<Clock>;
+
+namespace {
+
+// Internal state of a layer in the HWC API.
+class LayerImpl {
+public:
+    LayerImpl() = default;
+
+    bool mValid = true;
+    RenderState mRenderState;
+    uint32_t mZ = 0;
+};
+
+// Struct for storing per frame rectangle state. Contains the render
+// state shared to the test case. Basically a snapshot and a subset of
+// LayerImpl sufficient to re-create the pixels of a layer for the
+// frame.
+struct FrameRect {
+public:
+    FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
+          : layer(layer_), renderState(state), z(z_) {}
+
+    const Layer layer;
+    const RenderState renderState;
+    const uint32_t z;
+};
+
+// Collection of FrameRects forming one rendered frame. Could store
+// related fences and other data in the future.
+class Frame {
+public:
+    Frame() = default;
+    std::vector<std::unique_ptr<FrameRect>> rectangles;
+};
+
+class DelayedEventGenerator {
+public:
+    DelayedEventGenerator(std::function<void()> onTimerExpired)
+          : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
+
+    ~DelayedEventGenerator() {
+        ALOGI("DelayedEventGenerator exiting.");
+        {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mRunning = false;
+            mWakeups.clear();
+            mCondition.notify_one();
+        }
+        mThread.join();
+        ALOGI("DelayedEventGenerator exited.");
+    }
+
+    void wakeAfter(std::chrono::nanoseconds waitTime) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mWakeups.insert(Clock::now() + waitTime);
+        mCondition.notify_one();
+    }
+
+private:
+    void loop() {
+        while (true) {
+            // Lock scope
+            {
+                std::unique_lock<std::mutex> lock(mMutex);
+                mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
+                if (!mRunning && mWakeups.empty()) {
+                    // This thread should only exit once the destructor has been called and all
+                    // wakeups have been processed
+                    return;
+                }
+
+                // At this point, mWakeups will not be empty
+
+                TimePoint target = *(mWakeups.begin());
+                auto status = mCondition.wait_until(lock, target);
+                while (status == std::cv_status::no_timeout) {
+                    // This was either a spurious wakeup or another wakeup was added, so grab the
+                    // oldest point and wait again
+                    target = *(mWakeups.begin());
+                    status = mCondition.wait_until(lock, target);
+                }
+
+                // status must have been timeout, so we can finally clear this point
+                mWakeups.erase(target);
+            }
+            // Callback *without* locks!
+            mOnTimerExpired();
+        }
+    }
+
+    std::function<void()> mOnTimerExpired;
+    std::thread mThread;
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    bool mRunning = true;
+    std::set<TimePoint> mWakeups;
+};
+
+} // namespace
+
+FakeComposerClient::FakeComposerClient()
+      : mEventCallback(nullptr),
+        mCurrentConfig(NULL_DISPLAY_CONFIG),
+        mVsyncEnabled(false),
+        mLayers(),
+        mDelayedEventGenerator(
+                std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
+        mSurfaceComposer(nullptr) {}
+
+FakeComposerClient::~FakeComposerClient() {}
+
+bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
+    return false;
+}
+
+std::string FakeComposerClient::dumpDebugInfo() {
+    return {};
+}
+
+void FakeComposerClient::registerEventCallback(EventCallback* callback) {
+    ALOGV("registerEventCallback");
+    mEventCallback = callback;
+    if (mEventCallback) {
+        mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+    }
+}
+
+void FakeComposerClient::unregisterEventCallback() {
+    ALOGV("unregisterEventCallback");
+    mEventCallback = nullptr;
+}
+
+void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
+    if (mEventCallback) {
+        mEventCallback->onHotplug(display, state);
+    }
+}
+
+void FakeComposerClient::refreshDisplay(Display display) {
+    if (mEventCallback) {
+        mEventCallback->onRefresh(display);
+    }
+}
+
+uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
+    ALOGV("getMaxVirtualDisplayCount");
+    return 1;
+}
+
+Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+                                               PixelFormat* /*format*/, Display* /*outDisplay*/) {
+    ALOGV("createVirtualDisplay");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
+    ALOGV("destroyVirtualDisplay");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
+    ALOGV("createLayer");
+    *outLayer = mLayers.size();
+    auto newLayer = std::make_unique<LayerImpl>();
+    mLayers.push_back(std::move(newLayer));
+    return Error::NONE;
+}
+
+Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
+    ALOGV("destroyLayer");
+    mLayers[layer]->mValid = false;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
+    ALOGV("getActiveConfig");
+
+    // TODO Assert outConfig != nullptr
+
+    // TODO This is my reading of the
+    // IComposerClient::getActiveConfig, but returning BAD_CONFIG
+    // seems to not fit SurfaceFlinger plans. See version 2 below.
+    // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
+    //     return Error::BAD_CONFIG;
+    // }
+    //*outConfig = mCurrentConfig;
+    *outConfig = 1; // Very special config for you my friend
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
+                                                 uint32_t /*height*/, PixelFormat /*format*/,
+                                                 Dataspace /*dataspace*/) {
+    ALOGV("getClientTargetSupport");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
+    ALOGV("getColorModes");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
+                                              IComposerClient::Attribute attribute,
+                                              int32_t* outValue) {
+    ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
+          static_cast<int>(config), static_cast<int>(attribute), outValue);
+
+    // TODO: SOOO much fun to be had with these alone
+    switch (attribute) {
+        case IComposerClient::Attribute::WIDTH:
+            *outValue = 1920;
+            break;
+        case IComposerClient::Attribute::HEIGHT:
+            *outValue = 1080;
+            break;
+        case IComposerClient::Attribute::VSYNC_PERIOD:
+            *outValue = 1666666666;
+            break; // TOOD: Tests break down if lowered to 16ms?
+        case IComposerClient::Attribute::DPI_X:
+            *outValue = 240;
+            break;
+        case IComposerClient::Attribute::DPI_Y:
+            *outValue = 240;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Say what!?! New attribute");
+    }
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
+    ALOGV("getDisplayConfigs");
+    // TODO assert display == 1, outConfigs != nullptr
+
+    outConfigs->resize(1);
+    (*outConfigs)[0] = 1;
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
+    ALOGV("getDisplayName");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDisplayType(Display /*display*/,
+                                         IComposerClient::DisplayType* outType) {
+    ALOGV("getDisplayType");
+    // TODO: This setting nothing on the output had no effect on initial trials. Is first display
+    // assumed to be physical?
+    *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
+    ALOGV("getDozeSupport");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
+                                             float* /*outMaxLuminance*/,
+                                             float* /*outMaxAverageLuminance*/,
+                                             float* /*outMinLuminance*/) {
+    ALOGV("getHdrCapabilities");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
+    ALOGV("setActiveConfig");
+    mCurrentConfig = config;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
+    ALOGV("setColorMode");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
+    ALOGV("setPowerMode");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
+    mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
+    ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
+                                            int32_t /*hint*/) {
+    ALOGV("setColorTransform");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
+                                          int32_t /*acquireFence*/, int32_t /*dataspace*/,
+                                          const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setClientTarget");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
+                                          int32_t /*releaseFence*/) {
+    ALOGV("setOutputBuffer");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::validateDisplay(
+        Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+        std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+        uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+        std::vector<uint32_t>* /*outRequestMasks*/) {
+    ALOGV("validateDisplay");
+    // TODO: Assume touching nothing means All Korrekt!
+    return Error::NONE;
+}
+
+Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
+    ALOGV("acceptDisplayChanges");
+    // Didn't ask for changes because software is omnipotent.
+    return Error::NONE;
+}
+
+bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
+    return a->z <= b->z;
+}
+
+Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
+                                         std::vector<Layer>* /*outLayers*/,
+                                         std::vector<int32_t>* /*outReleaseFences*/) {
+    ALOGV("presentDisplay");
+    // TODO Leaving layers and their fences out for now. Doing so
+    // means that we've already processed everything. Important to
+    // test that the fences are respected, though. (How?)
+
+    std::unique_ptr<Frame> newFrame(new Frame);
+    for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
+        const LayerImpl& layerImpl = *mLayers[layer];
+
+        if (!layerImpl.mValid) continue;
+
+        auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
+        newFrame->rectangles.push_back(std::move(rect));
+    }
+    std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
+    {
+        Mutex::Autolock _l(mStateMutex);
+        mFrames.push_back(std::move(newFrame));
+        mFramesAvailable.broadcast();
+    }
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
+                                                 int32_t /*x*/, int32_t /*y*/) {
+    ALOGV("setLayerCursorPosition");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
+                                         int32_t acquireFence) {
+    ALOGV("setLayerBuffer");
+    LayerImpl& l = getLayerImpl(layer);
+    if (buffer != l.mRenderState.mBuffer) {
+        l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
+    }
+    l.mRenderState.mBuffer = buffer;
+    l.mRenderState.mAcquireFence = acquireFence;
+
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
+                                                const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setLayerSurfaceDamage");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
+    ALOGV("setLayerBlendMode");
+    getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
+                                        IComposerClient::Color color) {
+    ALOGV("setLayerColor");
+    getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
+    getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
+    getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
+    getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
+                                                  int32_t /*type*/) {
+    ALOGV("setLayerCompositionType");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
+                                            int32_t /*dataspace*/) {
+    ALOGV("setLayerDataspace");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
+                                               const hwc_rect_t& frame) {
+    ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
+          frame.bottom);
+    getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
+    ALOGV("setLayerPlaneAlpha");
+    getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
+                                                 buffer_handle_t /*stream*/) {
+    ALOGV("setLayerSidebandStream");
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
+                                             const hwc_frect_t& crop) {
+    ALOGV("setLayerSourceCrop");
+    getLayerImpl(layer).mRenderState.mSourceCrop = crop;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
+    ALOGV("setLayerTransform");
+    getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
+                                                const std::vector<hwc_rect_t>& visible) {
+    ALOGV("setLayerVisibleRegion");
+    getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
+    return Error::NONE;
+}
+
+Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
+    ALOGV("setLayerZOrder");
+    getLayerImpl(layer).mZ = z;
+    return Error::NONE;
+}
+
+//////////////////////////////////////////////////////////////////
+
+void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
+    if (mEventCallback) {
+        uint64_t timestamp = vsyncTime;
+        ALOGV("Vsync");
+        if (timestamp == 0) {
+            struct timespec ts;
+            clock_gettime(CLOCK_MONOTONIC, &ts);
+            timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+        }
+        if (mSurfaceComposer != nullptr) {
+            mSurfaceComposer->injectVSync(timestamp);
+        } else {
+            mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
+        }
+    }
+}
+
+void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
+    mDelayedEventGenerator->wakeAfter(wait);
+}
+
+LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
+    // TODO Change these to an internal state check that can be
+    // invoked from the gtest? GTest macros do not seem all that safe
+    // when used outside the test class
+    EXPECT_GE(handle, static_cast<Layer>(0));
+    EXPECT_LT(handle, mLayers.size());
+    return *(mLayers[handle]);
+}
+
+int FakeComposerClient::getFrameCount() const {
+    return mFrames.size();
+}
+
+static std::vector<RenderState> extractRenderState(
+        const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
+    std::vector<RenderState> result;
+    result.reserve(internalRects.size());
+    for (const std::unique_ptr<FrameRect>& rect : internalRects) {
+        result.push_back(rect->renderState);
+    }
+    return result;
+}
+
+std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
+    Mutex::Autolock _l(mStateMutex);
+    return extractRenderState(mFrames[frame]->rectangles);
+}
+
+std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
+    Mutex::Autolock _l(mStateMutex);
+    return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
+}
+
+void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
+    int currentFrame = 0;
+    {
+        Mutex::Autolock _l(mStateMutex); // I hope this is ok...
+        currentFrame = static_cast<int>(mFrames.size());
+        requestVSync();
+    }
+    waitUntilFrame(currentFrame + 1, maxWait);
+}
+
+void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
+    Mutex::Autolock _l(mStateMutex);
+    while (mFrames.size() < static_cast<size_t>(targetFrame)) {
+        android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
+        if (result == android::TIMED_OUT) {
+            ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
+                  mFrames.size(), maxWait.count());
+            return;
+        }
+    }
+}
+
+void FakeComposerClient::clearFrames() {
+    Mutex::Autolock _l(mStateMutex);
+    mFrames.clear();
+    for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
+        if (layer->mValid) {
+            layer->mRenderState.mSwapCount = 0;
+        }
+    }
+}
+
+void FakeComposerClient::onSurfaceFlingerStart() {
+    mSurfaceComposer = nullptr;
+    do {
+        mSurfaceComposer = new android::SurfaceComposerClient;
+        android::status_t initResult = mSurfaceComposer->initCheck();
+        if (initResult != android::NO_ERROR) {
+            ALOGD("Init result: %d", initResult);
+            mSurfaceComposer = nullptr;
+            std::this_thread::sleep_for(10ms);
+        }
+    } while (mSurfaceComposer == nullptr);
+    ALOGD("SurfaceComposerClient created");
+    mSurfaceComposer->enableVSyncInjections(true);
+}
+
+void FakeComposerClient::onSurfaceFlingerStop() {
+    mSurfaceComposer->dispose();
+    mSurfaceComposer.clear();
+}
+
+// Includes destroyed layers, stored in order of creation.
+int FakeComposerClient::getLayerCount() const {
+    return mLayers.size();
+}
+
+Layer FakeComposerClient::getLayer(size_t index) const {
+    // NOTE: If/when passing calls through to actual implementation,
+    // this might get more involving.
+    return static_cast<Layer>(index);
+}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
new file mode 100644
index 0000000..d115d79
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define HWC2_USE_CPP11
+#define HWC2_INCLUDE_STRINGIFICATION
+#include <composer-hal/2.1/ComposerClient.h>
+#undef HWC2_USE_CPP11
+#undef HWC2_INCLUDE_STRINGIFICATION
+#include "RenderState.h"
+
+// Needed for display type/ID enums
+#include <hardware/hwcomposer_defs.h>
+
+#include <utils/Condition.h>
+
+#include <chrono>
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::hal;
+using namespace android::hardware;
+using namespace std::chrono_literals;
+
+namespace {
+class LayerImpl;
+class Frame;
+class DelayedEventGenerator;
+} // namespace
+
+namespace android {
+class SurfaceComposerClient;
+} // namespace android
+
+namespace sftest {
+
+// NOTE: The ID's need to be exactly these. VR composer and parts of
+// the SurfaceFlinger assume the display IDs to have these values
+// despite the enum being documented as a display type.
+// TODO: Reference to actual documentation
+constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY);
+constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL);
+
+class FakeComposerClient : public ComposerHal {
+public:
+    FakeComposerClient();
+    virtual ~FakeComposerClient();
+
+    bool hasCapability(hwc2_capability_t capability) override;
+
+    std::string dumpDebugInfo() override;
+    void registerEventCallback(EventCallback* callback) override;
+    void unregisterEventCallback() override;
+
+    uint32_t getMaxVirtualDisplayCount() override;
+    Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+                               Display* outDisplay) override;
+    Error destroyVirtualDisplay(Display display) override;
+    Error createLayer(Display display, Layer* outLayer) override;
+    Error destroyLayer(Display display, Layer layer) override;
+
+    Error getActiveConfig(Display display, Config* outConfig) override;
+    Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+                                 PixelFormat format, Dataspace dataspace) override;
+    Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
+    Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
+                              int32_t* outValue) override;
+    Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
+    Error getDisplayName(Display display, hidl_string* outName) override;
+    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+    Error getDozeSupport(Display display, bool* outSupport) override;
+    Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
+                             float* outMaxAverageLuminance, float* outMinLuminance) override;
+
+    Error setActiveConfig(Display display, Config config) override;
+    Error setColorMode(Display display, ColorMode mode) override;
+    Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
+    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+
+    Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
+    Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+                          int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
+    Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override;
+    Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+                          std::vector<IComposerClient::Composition>* outCompositionTypes,
+                          uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+                          std::vector<uint32_t>* outRequestMasks) override;
+    Error acceptDisplayChanges(Display display) override;
+    Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
+                         std::vector<int32_t>* outReleaseFences) override;
+
+    Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+    Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+                         int32_t acquireFence) override;
+    Error setLayerSurfaceDamage(Display display, Layer layer,
+                                const std::vector<hwc_rect_t>& damage) override;
+    Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
+    Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
+    Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
+    Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
+    Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override;
+    Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+    Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override;
+    Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
+    Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
+    Error setLayerVisibleRegion(Display display, Layer layer,
+                                const std::vector<hwc_rect_t>& visible) override;
+    Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+    void setClient(ComposerClient* client);
+
+    void requestVSync(uint64_t vsyncTime = 0);
+    // We don't want tests hanging, so always use a timeout. Remember
+    // to always check the number of frames with test ASSERT_!
+    // Wait until next frame is rendered after requesting vsync.
+    void runVSyncAndWait(std::chrono::nanoseconds maxWait = 100ms);
+    void runVSyncAfter(std::chrono::nanoseconds wait);
+
+    int getFrameCount() const;
+    // We don't want tests hanging, so always use a timeout. Remember
+    // to always check the number of frames with test ASSERT_!
+    void waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait = 100ms) const;
+    std::vector<RenderState> getFrameRects(int frame) const;
+    std::vector<RenderState> getLatestFrame() const;
+    void clearFrames();
+
+    void onSurfaceFlingerStart();
+    void onSurfaceFlingerStop();
+
+    int getLayerCount() const;
+    Layer getLayer(size_t index) const;
+
+    void hotplugDisplay(Display display, IComposerCallback::Connection state);
+    void refreshDisplay(Display display);
+
+private:
+    LayerImpl& getLayerImpl(Layer handle);
+
+    EventCallback* mEventCallback;
+    Config mCurrentConfig;
+    bool mVsyncEnabled;
+    std::vector<std::unique_ptr<LayerImpl>> mLayers;
+    std::vector<std::unique_ptr<Frame>> mFrames;
+    // Using a pointer to hide the implementation into the CPP file.
+    std::unique_ptr<DelayedEventGenerator> mDelayedEventGenerator;
+    android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
+    mutable android::Mutex mStateMutex;
+    mutable android::Condition mFramesAvailable;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
new file mode 100644
index 0000000..f70cbdb
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcService"
+#include <log/log.h>
+
+#include "FakeComposerService.h"
+
+using namespace android::hardware;
+
+namespace sftest {
+
+FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {}
+
+FakeComposerService::~FakeComposerService() {
+    ALOGI("Maybe killing client %p", mClient.get());
+    // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) {
+    ALOGI("FakeComposerService::getCapabilities");
+    hidl_cb(hidl_vec<Capability>());
+    return Void();
+}
+
+Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+    ALOGI("FakeComposerService::dumpDebugInfo");
+    hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) {
+    ALOGI("FakeComposerService::createClient %p", mClient.get());
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(Error::NONE, mClient);
+    return Void();
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
new file mode 100644
index 0000000..c439b7e
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <composer-hal/2.1/ComposerClient.h>
+
+using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_1::hal;
+using android::hardware::Return;
+
+namespace sftest {
+
+class FakeComposerService : public IComposer {
+public:
+    FakeComposerService(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService();
+
+    Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+    Return<void> createClient(createClient_cb hidl_cb) override;
+
+private:
+    android::sp<ComposerClient> mClient;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
new file mode 100644
index 0000000..51956ec
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcUtil"
+#include <log/log.h>
+
+#include "FakeComposerUtils.h"
+#include "RenderState.h"
+
+#include "SurfaceFlinger.h" // Get the name of the service...
+
+#include <binder/IServiceManager.h>
+
+#include <cutils/properties.h>
+
+#include <iomanip>
+#include <thread>
+
+using android::String16;
+using android::sp;
+using namespace std::chrono_literals;
+using namespace sftest;
+using std::setw;
+
+namespace sftest {
+
+// clang-format off
+inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) {
+    os << std::fixed << std::setprecision(1) << "("
+       << setw(align) << sourceRect.left << setw(0) << ","
+       << setw(align) << sourceRect.top << setw(0) << ","
+       << setw(align) << sourceRect.right << setw(0) << ","
+       << setw(align) << sourceRect.bottom << setw(0) << ")";
+}
+
+inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) {
+    os << "("
+       << setw(align) << displayRect.left << setw(0) << ","
+       << setw(align) << displayRect.top << setw(0) << ","
+       << setw(align) << displayRect.right << setw(0) << ","
+       << setw(align) << displayRect.bottom << setw(0) << ")";
+}
+// clang-format on
+
+inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) {
+    printSourceRectAligned(os, state.mSourceCrop, 7);
+    os << "->";
+    printDisplayRectAligned(os, state.mDisplayFrame, 5);
+    return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3)
+              << state.mPlaneAlpha << " Xform:" << state.mTransform;
+}
+
+// Helper for verifying the parts of the RenderState
+template <typename T>
+bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val,
+                 const char* name) {
+    if (ref != val) {
+        message = message << "Expected " << name << ":" << ref << ", got:" << val << ".";
+        return false;
+    }
+    return true;
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) {
+    // TODO: Message could start as success and be assigned as failure.
+    // Only problem is that utility assumes it to be failure and just adds stuff. Would
+    // need still special case the initial failure in the utility?
+    // TODO: ... or would it be possible to break this back to gtest primitives?
+    ::testing::AssertionResult message = ::testing::AssertionFailure();
+    bool passes = true;
+
+    // The work here is mostly about providing good log strings for differences
+    passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame");
+    passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha");
+    passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count");
+    passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop");
+    // ... add more
+    if (passes) {
+        return ::testing::AssertionSuccess();
+    }
+    return message;
+}
+
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+                                         const std::vector<RenderState>& val) {
+    ::testing::AssertionResult message = ::testing::AssertionFailure();
+    bool passed = true;
+    if (ref.size() != val.size()) {
+        message << "Expected " << ref.size() << " rects, got " << val.size() << ".";
+        passed = false;
+    }
+    for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) {
+        ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]);
+        if (rectResult == false) {
+            message << "First different rect at " << rectIndex << ": " << rectResult.message();
+            passed = false;
+            break;
+        }
+    }
+
+    if (passed) {
+        return ::testing::AssertionSuccess();
+    } else {
+        message << "\nReference:";
+        for (auto state = ref.begin(); state != ref.end(); ++state) {
+            message << "\n" << *state;
+        }
+        message << "\nActual:";
+        for (auto state = val.begin(); state != val.end(); ++state) {
+            message << "\n" << *state;
+        }
+    }
+    return message;
+}
+
+void startSurfaceFlinger() {
+    ALOGI("Start SurfaceFlinger");
+    system("start surfaceflinger");
+
+    sp<android::IServiceManager> sm(android::defaultServiceManager());
+    sp<android::IBinder> sf;
+    while (sf == nullptr) {
+        std::this_thread::sleep_for(10ms);
+        sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+    }
+    ALOGV("SurfaceFlinger running");
+}
+
+void stopSurfaceFlinger() {
+    ALOGI("Stop SurfaceFlinger");
+    system("stop surfaceflinger");
+    sp<android::IServiceManager> sm(android::defaultServiceManager());
+    sp<android::IBinder> sf;
+    while (sf != nullptr) {
+        std::this_thread::sleep_for(10ms);
+        sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
+    }
+    ALOGV("SurfaceFlinger stopped");
+}
+
+////////////////////////////////////////////////
+
+void FakeHwcEnvironment::SetUp() {
+    ALOGI("Test env setup");
+    system("setenforce 0");
+    system("stop");
+    property_set("debug.sf.nobootanimation", "1");
+    {
+        char value[PROPERTY_VALUE_MAX];
+        property_get("debug.sf.nobootanimation", value, "0");
+        LOG_FATAL_IF(atoi(value) != 1, "boot skip not set");
+    }
+    // TODO: Try registering the mock as the default service instead.
+    property_set("debug.sf.hwc_service_name", "mock");
+    // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+    property_set("debug.sf.treble_testing_override", "true");
+}
+
+void FakeHwcEnvironment::TearDown() {
+    ALOGI("Test env tear down");
+    system("stop");
+    // Wait for mock call signaling teardown?
+    property_set("debug.sf.nobootanimation", "0");
+    property_set("debug.sf.hwc_service_name", "default");
+    ALOGI("Test env tear down - done");
+}
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
new file mode 100644
index 0000000..1258a97
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "FakeComposerClient.h"
+
+#include <gui/SurfaceComposerClient.h>
+
+#include <hardware/hwcomposer_defs.h>
+
+#include <log/log.h>
+
+#include <gtest/gtest.h>
+
+// clang-format off
+// Note: This needs to reside in the global namespace for the GTest to use it
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_rect_t& rect) {
+    return os << "(" << rect.left << ","
+              << rect.top << ","
+              << rect.right << ","
+              << rect.bottom << ")";
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, const hwc_frect_t& rect) {
+    return os << "(" << rect.left << ","
+              << rect.top << ","
+              << rect.right << ","
+              << rect.bottom << ")";
+}
+// clang-format on
+
+namespace sftest {
+
+class RenderState;
+
+// clang-format off
+inline bool operator==(const hwc_rect_t& a, const hwc_rect_t& b) {
+    return a.top == b.top &&
+            a.left == b.left &&
+            a.bottom == b.bottom &&
+            a.right == b.right;
+}
+
+inline bool operator==(const hwc_frect_t& a, const hwc_frect_t& b) {
+    return a.top == b.top &&
+            a.left == b.left &&
+            a.bottom == b.bottom &&
+            a.right == b.right;
+}
+// clang-format on
+
+inline bool operator!=(const hwc_rect_t& a, const hwc_rect_t& b) {
+    return !(a == b);
+}
+
+inline bool operator!=(const hwc_frect_t& a, const hwc_frect_t& b) {
+    return !(a == b);
+}
+
+::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val);
+::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
+                                         const std::vector<RenderState>& val);
+
+void startSurfaceFlinger();
+void stopSurfaceFlinger();
+
+class FakeHwcEnvironment : public ::testing::Environment {
+public:
+    virtual ~FakeHwcEnvironment() {}
+    void SetUp() override;
+    void TearDown() override;
+};
+
+/*
+ * All surface state changes are supposed to happen inside a global
+ * transaction. TransactionScope object at the beginning of
+ * scope automates the process. The resulting scope gives a visual cue
+ * on the span of the transaction as well.
+ *
+ * Closing the transaction is synchronous, i.e., it waits for
+ * SurfaceFlinger to composite one frame. Now, the FakeComposerClient
+ * is built to explicitly request vsyncs one at the time. A delayed
+ * request must be made before closing the transaction or the test
+ * thread stalls until SurfaceFlinger does an emergency vsync by
+ * itself. TransactionScope encapsulates this vsync magic.
+ */
+class TransactionScope : public android::SurfaceComposerClient::Transaction {
+public:
+    TransactionScope(FakeComposerClient& composer) :
+            Transaction(),
+            mComposer(composer) {
+    }
+
+    ~TransactionScope() {
+        int frameCount = mComposer.getFrameCount();
+        mComposer.runVSyncAfter(1ms);
+        LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
+        // Make sure that exactly one frame has been rendered.
+        mComposer.waitUntilFrame(frameCount + 1);
+        LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
+                            "Unexpected frame advance. Delta: %d",
+                            mComposer.getFrameCount() - frameCount);
+    }
+
+    FakeComposerClient& mComposer;
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
new file mode 100644
index 0000000..0059289
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/RenderState.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <hardware/hwcomposer2.h>
+
+#include <vector>
+
+namespace sftest {
+// Description of a rendered rectangle.  Should only contain
+// instructions necessary to rasterize the rectangle. The full scene
+// is given as a sorted list of rectangles, bottom layer at index 0.
+class RenderState {
+public:
+    RenderState() = default;
+    // Default copy-ctor
+
+    hwc_rect_t mDisplayFrame = {0, 0, 0, 0};
+    hwc_frect_t mSourceCrop = {0.f, 0.f, 0.f, 0.f};
+    std::vector<hwc_rect_t> mVisibleRegion;
+    hwc2_blend_mode_t mBlendMode = HWC2_BLEND_MODE_NONE;
+    buffer_handle_t mBuffer = 0;
+    uint32_t mSwapCount = 0;   // How many set buffer calls to the layer.
+    int32_t mAcquireFence = 0; // Probably should not be here.
+    float mPlaneAlpha = 0.f;
+    hwc_color_t mLayerColor = {0, 0, 0, 0};
+    hwc_transform_t mTransform = static_cast<hwc_transform_t>(0);
+};
+
+} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
new file mode 100644
index 0000000..9b31985
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -0,0 +1,1424 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FakeHwcTest"
+
+#include "FakeComposerClient.h"
+#include "FakeComposerService.h"
+#include "FakeComposerUtils.h"
+
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/looper.h>
+#include <android/native_window.h>
+#include <binder/ProcessState.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayInfo.h>
+#include <utils/Looper.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <limits>
+
+using namespace std::chrono_literals;
+
+using namespace android;
+using namespace android::hardware;
+
+using namespace sftest;
+
+namespace {
+
+// Mock test helpers
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::_;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+///////////////////////////////////////////////
+
+struct TestColor {
+public:
+    uint8_t r;
+    uint8_t g;
+    uint8_t b;
+    uint8_t a;
+};
+
+constexpr static TestColor RED = {195, 63, 63, 255};
+constexpr static TestColor LIGHT_RED = {255, 177, 177, 255};
+constexpr static TestColor GREEN = {63, 195, 63, 255};
+constexpr static TestColor BLUE = {63, 63, 195, 255};
+constexpr static TestColor DARK_GRAY = {63, 63, 63, 255};
+constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255};
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const TestColor& color,
+                             bool unlock = true) {
+    ANativeWindow_Buffer outBuffer;
+    sp<Surface> s = sc->getSurface();
+    ASSERT_TRUE(s != nullptr);
+    ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+    uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+    for (int y = 0; y < outBuffer.height; y++) {
+        for (int x = 0; x < outBuffer.width; x++) {
+            uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+            pixel[0] = color.r;
+            pixel[1] = color.g;
+            pixel[2] = color.b;
+            pixel[3] = color.a;
+        }
+    }
+    if (unlock) {
+        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+    }
+}
+
+inline RenderState makeSimpleRect(int left, int top, int right, int bottom) {
+    RenderState res;
+    res.mDisplayFrame = hwc_rect_t{left, top, right, bottom};
+    res.mPlaneAlpha = 1.0f;
+    res.mSwapCount = 0;
+    res.mSourceCrop = hwc_frect_t{0.f, 0.f, static_cast<float>(right - left),
+                                  static_cast<float>(bottom - top)};
+    return res;
+}
+
+inline RenderState makeSimpleRect(unsigned int left, unsigned int top, unsigned int right,
+                                  unsigned int bottom) {
+    EXPECT_LE(left, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(top, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(right, static_cast<unsigned int>(INT_MAX));
+    EXPECT_LE(bottom, static_cast<unsigned int>(INT_MAX));
+    return makeSimpleRect(static_cast<int>(left), static_cast<int>(top), static_cast<int>(right),
+                          static_cast<int>(bottom));
+}
+
+////////////////////////////////////////////////
+
+class DisplayTest : public ::testing::Test {
+public:
+    class MockComposerClient : public FakeComposerClient {
+    public:
+        MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
+        MOCK_METHOD4(getDisplayAttribute,
+                     Error(Display display, Config config, IComposerClient::Attribute attribute,
+                           int32_t* outValue));
+
+        // Re-routing to basic fake implementation
+        Error getDisplayAttributeFake(Display display, Config config,
+                                      IComposerClient::Attribute attribute, int32_t* outValue) {
+            return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue);
+        }
+    };
+
+protected:
+    static int processDisplayEvents(int fd, int events, void* data);
+
+    void SetUp() override;
+    void TearDown() override;
+
+    void waitForDisplayTransaction();
+    bool waitForHotplugEvent(uint32_t id, bool connected);
+
+    sp<IComposer> mFakeService;
+    sp<SurfaceComposerClient> mComposerClient;
+
+    MockComposerClient* mMockComposer;
+
+    std::unique_ptr<DisplayEventReceiver> mReceiver;
+    sp<Looper> mLooper;;
+    std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
+};
+
+void DisplayTest::SetUp() {
+    // TODO: The mMockComposer should be a unique_ptr, but it needs to
+    // outlive the test class.  Currently ComposerClient only dies
+    // when the service is replaced. The Mock deletes itself when
+    // removeClient is called on it, which is ugly.  This can be
+    // changed if HIDL ServiceManager allows removing services or
+    // ComposerClient starts taking the ownership of the contained
+    // implementation class. Moving the fake class to the HWC2
+    // interface instead of the current Composer interface might also
+    // change the situation.
+    mMockComposer = new MockComposerClient;
+    sp<ComposerClient> client = new ComposerClient(mMockComposer);
+    mFakeService = new FakeComposerService(client);
+    (void)mFakeService->registerAsService("mock");
+
+    android::hardware::ProcessState::self()->startThreadPool();
+    android::ProcessState::self()->startThreadPool();
+
+    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
+            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+                            Return(Error::NONE)));
+    // Primary display will be queried twice for all 5 attributes. One
+    // set of queries comes from the SurfaceFlinger proper an the
+    // other set from the VR composer.
+    // TODO: Is VR composer always present? Change to atLeast(5)?
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+            .Times(2 * 5)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+
+    startSurfaceFlinger();
+
+    // Fake composer wants to enable VSync injection
+    mMockComposer->onSurfaceFlingerStart();
+
+    mComposerClient = new SurfaceComposerClient;
+    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+    mReceiver.reset(new DisplayEventReceiver());
+    mLooper = new Looper(false);
+    mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
+}
+
+void DisplayTest::TearDown() {
+    mLooper = nullptr;
+    mReceiver = nullptr;
+
+    mComposerClient->dispose();
+    mComposerClient = nullptr;
+
+    // Fake composer needs to release SurfaceComposerClient before the stop.
+    mMockComposer->onSurfaceFlingerStop();
+    stopSurfaceFlinger();
+
+    mFakeService = nullptr;
+    // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
+    // management.
+    mMockComposer = nullptr;
+}
+
+
+int DisplayTest::processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
+    auto self = static_cast<DisplayTest*>(data);
+
+    ssize_t n;
+    DisplayEventReceiver::Event buffer[1];
+
+    while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
+        for (int i=0 ; i<n ; i++) {
+            self->mReceivedDisplayEvents.push_back(buffer[i]);
+        }
+    }
+    ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+    return 1;
+}
+
+void DisplayTest::waitForDisplayTransaction() {
+    // Both a refresh and a vsync event are needed to apply pending display
+    // transactions.
+    mMockComposer->refreshDisplay(EXTERNAL_DISPLAY);
+    mMockComposer->runVSyncAndWait();
+
+    // Extra vsync and wait to avoid a 10% flake due to a race.
+    mMockComposer->runVSyncAndWait();
+}
+
+bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) {
+    int waitCount = 20;
+    while (waitCount--) {
+        while (!mReceivedDisplayEvents.empty()) {
+            auto event = mReceivedDisplayEvents.front();
+            mReceivedDisplayEvents.pop_front();
+
+            ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+                    "event hotplug: id %d, connected %d\t", event.header.id,
+                    event.hotplug.connected);
+
+            if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
+                event.header.id == id && event.hotplug.connected == connected) {
+                return true;
+            }
+        }
+
+        mLooper->pollOnce(1);
+    }
+
+    return false;
+}
+
+TEST_F(DisplayTest, Hotplug) {
+    ALOGD("DisplayTest::Hotplug");
+
+    EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+                                  Return(Error::NONE)));
+    // The attribute queries will get done twice. This is for defaults
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
+            .Times(2 * 3)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+    // ... and then special handling for dimensions. Specifying these
+    // rules later means that gmock will try them first, i.e.,
+    // ordering of width/height vs. the default implementation for
+    // other queries is significant.
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+    waitForDisplayTransaction();
+
+    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(400u, info.w);
+        ASSERT_EQ(200u, info.h);
+
+        auto surfaceControl =
+                mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h,
+                                               PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(surfaceControl != nullptr);
+        ASSERT_TRUE(surfaceControl->isValid());
+        fillSurfaceRGBA8(surfaceControl, BLUE);
+
+        {
+            TransactionScope ts(*mMockComposer);
+            ts.setDisplayLayerStack(display, 0);
+
+            ts.setLayer(surfaceControl, INT32_MAX - 2)
+                .show(surfaceControl);
+        }
+    }
+
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+    mMockComposer->clearFrames();
+
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+    waitForDisplayTransaction();
+
+    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false));
+    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(400u, info.w);
+        ASSERT_EQ(200u, info.h);
+
+        auto surfaceControl =
+                mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h,
+                                               PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(surfaceControl != nullptr);
+        ASSERT_TRUE(surfaceControl->isValid());
+        fillSurfaceRGBA8(surfaceControl, BLUE);
+
+        {
+            TransactionScope ts(*mMockComposer);
+            ts.setDisplayLayerStack(display, 0);
+
+            ts.setLayer(surfaceControl, INT32_MAX - 2)
+                .show(surfaceControl);
+        }
+    }
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+}
+
+TEST_F(DisplayTest, HotplugPrimaryDisplay) {
+    ALOGD("DisplayTest::HotplugPrimaryDisplay");
+
+    mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+    waitForDisplayTransaction();
+
+    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false));
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        DisplayInfo info;
+        auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+        EXPECT_NE(NO_ERROR, result);
+    }
+
+    mMockComposer->clearFrames();
+
+    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+                                  Return(Error::NONE)));
+    // The attribute queries will get done twice. This is for defaults
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+            .Times(2 * 3)
+            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+    // ... and then special handling for dimensions. Specifying these
+    // rules later means that gmock will try them first, i.e.,
+    // ordering of width/height vs. the default implementation for
+    // other queries is significant.
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
+            .Times(2)
+            .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+
+    mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+    waitForDisplayTransaction();
+
+    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true));
+
+    {
+        sp<android::IBinder> display(
+                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        DisplayInfo info;
+        auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+        EXPECT_EQ(NO_ERROR, result);
+        ASSERT_EQ(400u, info.w);
+        ASSERT_EQ(200u, info.h);
+    }
+}
+
+////////////////////////////////////////////////
+
+class TransactionTest : public ::testing::Test {
+protected:
+    // Layer array indexing constants.
+    constexpr static int BG_LAYER = 0;
+    constexpr static int FG_LAYER = 1;
+
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+    void SetUp() override;
+    void TearDown() override;
+
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
+    std::vector<RenderState> mBaseFrame;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+
+    static FakeComposerClient* sFakeComposer;
+};
+
+FakeComposerClient* TransactionTest::sFakeComposer;
+
+void TransactionTest::SetUpTestCase() {
+    // TODO: See TODO comment at DisplayTest::SetUp for background on
+    // the lifetime of the FakeComposerClient.
+    sFakeComposer = new FakeComposerClient;
+    sp<ComposerClient> client = new ComposerClient(sFakeComposer);
+    sp<IComposer> fakeService = new FakeComposerService(client);
+    (void)fakeService->registerAsService("mock");
+
+    android::hardware::ProcessState::self()->startThreadPool();
+    android::ProcessState::self()->startThreadPool();
+
+    startSurfaceFlinger();
+
+    // Fake composer wants to enable VSync injection
+    sFakeComposer->onSurfaceFlingerStart();
+}
+
+void TransactionTest::TearDownTestCase() {
+    // Fake composer needs to release SurfaceComposerClient before the stop.
+    sFakeComposer->onSurfaceFlingerStop();
+    stopSurfaceFlinger();
+    // TODO: This is deleted when the ComposerClient calls
+    // removeClient. Devise better lifetime control.
+    sFakeComposer = nullptr;
+}
+
+void TransactionTest::SetUp() {
+    ALOGI("TransactionTest::SetUp");
+    mComposerClient = new SurfaceComposerClient;
+    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+    ALOGI("TransactionTest::SetUp - display");
+    sp<android::IBinder> display(
+            SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    DisplayInfo info;
+    SurfaceComposerClient::getDisplayInfo(display, &info);
+
+    mDisplayWidth = info.w;
+    mDisplayHeight = info.h;
+
+    // Background surface
+    mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
+                                                       mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mBGSurfaceControl != nullptr);
+    ASSERT_TRUE(mBGSurfaceControl->isValid());
+    fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
+
+    // Foreground surface
+    mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+                                                       PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mFGSurfaceControl != nullptr);
+    ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+
+    Transaction t;
+    t.setDisplayLayerStack(display, 0);
+
+    t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
+    t.show(mBGSurfaceControl);
+
+    t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
+    t.setPosition(mFGSurfaceControl, 64, 64);
+    t.show(mFGSurfaceControl);
+
+    // Synchronous transaction will stop this thread, so we set up a
+    // delayed, off-thread vsync request before closing the
+    // transaction. In the test code this is usually done with
+    // TransactionScope. Leaving here in the 'vanilla' form for
+    // reference.
+    ASSERT_EQ(0, sFakeComposer->getFrameCount());
+    sFakeComposer->runVSyncAfter(1ms);
+    t.apply();
+    sFakeComposer->waitUntilFrame(1);
+
+    // Reference data. This is what the HWC should see.
+    static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
+    mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
+    mBaseFrame[BG_LAYER].mSwapCount = 1;
+    mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+    mBaseFrame[FG_LAYER].mSwapCount = 1;
+
+    auto frame = sFakeComposer->getFrameRects(0);
+    ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+}
+
+void TransactionTest::TearDown() {
+    ALOGD("TransactionTest::TearDown");
+
+    mComposerClient->dispose();
+    mBGSurfaceControl = 0;
+    mFGSurfaceControl = 0;
+    mComposerClient = 0;
+
+    sFakeComposer->runVSyncAndWait();
+    mBaseFrame.clear();
+    sFakeComposer->clearFrames();
+    ASSERT_EQ(0, sFakeComposer->getFrameCount());
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    std::vector<LayerDebugInfo> layers;
+    status_t result = sf->getLayerDebugInfo(&layers);
+    if (result != NO_ERROR) {
+        ALOGE("Failed to get layers %s %d", strerror(-result), result);
+    } else {
+        // If this fails, the test being torn down leaked layers.
+        EXPECT_EQ(0u, layers.size());
+        if (layers.size() > 0) {
+            for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
+                std::cout << to_string(*layer).c_str();
+            }
+            // To ensure the next test has clean slate, will run the class
+            // tear down and setup here.
+            TearDownTestCase();
+            SetUpTestCase();
+        }
+    }
+    ALOGD("TransactionTest::TearDown - complete");
+}
+
+TEST_F(TransactionTest, LayerMove) {
+    ALOGD("TransactionTest::LayerMove");
+
+    // The scope opens and closes a global transaction and, at the
+    // same time, makes sure the SurfaceFlinger progresses one frame
+    // after the transaction closes. The results of the transaction
+    // should be available in the latest frame stored by the fake
+    // composer.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 128, 128);
+        // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
+        // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
+        //
+        // sFakeComposer->runVSyncAndWait();
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+
+    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+                                                  // no extra frames.
+
+    // NOTE: Frame 0 is produced in the SetUp.
+    auto frame1Ref = mBaseFrame;
+    frame1Ref[FG_LAYER].mDisplayFrame =
+            hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
+    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+    auto frame2Ref = frame1Ref;
+    frame2Ref[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerResize) {
+    ALOGD("TransactionTest::LayerResize");
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+
+    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
+                                                  // no extra frames.
+
+    auto frame1Ref = mBaseFrame;
+    // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted.
+    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+    auto frame2Ref = frame1Ref;
+    frame2Ref[FG_LAYER].mSwapCount++;
+    frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
+    frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
+    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+}
+
+TEST_F(TransactionTest, LayerCrop) {
+    // TODO: Add scaling to confirm that crop happens in buffer space?
+    {
+        TransactionScope ts(*sFakeComposer);
+        Rect cropRect(16, 16, 32, 32);
+        ts.setCrop(mFGSurfaceControl, cropRect);
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCrop) {
+    // TODO: Add scaling to confirm that crop happens in display space?
+    {
+        TransactionScope ts(*sFakeComposer);
+        Rect cropRect(32, 32, 32 + 64, 32 + 64);
+        ts.setFinalCrop(mFGSurfaceControl, cropRect);
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // In display space we are cropping with [32, 32, 96, 96] against display rect
+    // [64, 64, 128, 128]. Should yield display rect [64, 64, 96, 96]
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 32, 64 + 32};
+
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerFinalCropEmpty) {
+    // TODO: Add scaling to confirm that crop happens in display space?
+    {
+        TransactionScope ts(*sFakeComposer);
+        Rect cropRect(16, 16, 32, 32);
+        ts.setFinalCrop(mFGSurfaceControl, cropRect);
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // In display space we are cropping with [16, 16, 32, 32] against display rect
+    // [64, 64, 128, 128]. The intersection is empty and only the background layer is composited.
+    std::vector<RenderState> referenceFrame(1);
+    referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayer) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // The layers will switch order, but both are rendered because the background layer is
+    // transparent (RGBA8888).
+    std::vector<RenderState> referenceFrame(2);
+    referenceFrame[0] = mBaseFrame[FG_LAYER];
+    referenceFrame[1] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetLayerOpaque) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+        ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
+                layer_state_t::eLayerOpaque);
+    }
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+    // The former foreground layer is now covered with opaque layer - it should have disappeared
+    std::vector<RenderState> referenceFrame(1);
+    referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetLayerStack) {
+    ALOGD("TransactionTest::SetLayerStack");
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayerStack(mFGSurfaceControl, 1);
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerShowHide) {
+    ALOGD("TransactionTest::LayerShowHide");
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.hide(mFGSurfaceControl);
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mFGSurfaceControl);
+    }
+
+    // Foreground layer should be back
+    ASSERT_EQ(3, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetAlpha) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.75f);
+    }
+
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetFlags) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
+                layer_state_t::eLayerHidden);
+    }
+
+    // Foreground layer should have disappeared.
+    ASSERT_EQ(2, sFakeComposer->getFrameCount());
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, LayerSetMatrix) {
+    struct matrixTestData {
+        float matrix[4];
+        hwc_transform_t expectedTransform;
+        hwc_rect_t expectedDisplayFrame;
+    };
+
+    // The matrix operates on the display frame and is applied before
+    // the position is added. So, the foreground layer rect is (0, 0,
+    // 64, 64) is first transformed, potentially yielding negative
+    // coordinates and then the position (64, 64) is added yielding
+    // the final on-screen rectangles given.
+
+    const matrixTestData MATRIX_TESTS[7] = // clang-format off
+            {{{-1.f, 0.f, 0.f, 1.f},    HWC_TRANSFORM_FLIP_H,           {0, 64, 64, 128}},
+             {{1.f, 0.f, 0.f, -1.f},    HWC_TRANSFORM_FLIP_V,           {64, 0, 128, 64}},
+             {{0.f, 1.f, -1.f, 0.f},    HWC_TRANSFORM_ROT_90,           {0, 64, 64, 128}},
+             {{-1.f, 0.f, 0.f, -1.f},   HWC_TRANSFORM_ROT_180,          {0, 0, 64, 64}},
+             {{0.f, -1.f, 1.f, 0.f},    HWC_TRANSFORM_ROT_270,          {64, 0, 128, 64}},
+             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_H_ROT_90,    {64, 64, 128, 128}},
+             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_V_ROT_90,    {64, 64, 128, 128}}};
+    // clang-format on
+    constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
+
+    for (int i = 0; i < TEST_COUNT; i++) {
+        // TODO: How to leverage the HWC2 stringifiers?
+        const matrixTestData& xform = MATRIX_TESTS[i];
+        SCOPED_TRACE(i);
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1],
+                    xform.matrix[2], xform.matrix[3]);
+        }
+
+        auto referenceFrame = mBaseFrame;
+        referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
+        referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
+
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+}
+
+#if 0
+TEST_F(TransactionTest, LayerSetMatrix2) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        // TODO: PLEASE SPEC THE FUNCTION!
+        ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f,
+                -2.33f, 0.22f);
+    }
+    auto referenceFrame = mBaseFrame;
+    // TODO: Is this correct for sure?
+    //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90;
+
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+#endif
+
+TEST_F(TransactionTest, DeferredTransaction) {
+    // Synchronization surface
+    constexpr static int SYNC_LAYER = 2;
+    auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+                                                             PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(syncSurfaceControl != nullptr);
+    ASSERT_TRUE(syncSurfaceControl->isValid());
+
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
+        ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
+        ts.show(syncSurfaceControl);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
+                                            mDisplayWidth - 1, mDisplayHeight - 1));
+    referenceFrame[SYNC_LAYER].mSwapCount = 1;
+    EXPECT_EQ(2, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // set up two deferred transactions on different frames - these should not yield composited
+    // frames
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.75);
+        ts.deferTransactionUntil(mFGSurfaceControl, 
+                syncSurfaceControl->getHandle(),
+                syncSurfaceControl->getSurface()->getNextFrameNumber());
+    }
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 128, 128);
+        ts.deferTransactionUntil(mFGSurfaceControl,
+                syncSurfaceControl->getHandle(),
+                syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+    }
+    EXPECT_EQ(4, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // should trigger the first deferred transaction, but not the second one
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+    sFakeComposer->runVSyncAndWait();
+    EXPECT_EQ(5, sFakeComposer->getFrameCount());
+
+    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+    referenceFrame[SYNC_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // should show up immediately since it's not deferred
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 1.0);
+    }
+    referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
+    EXPECT_EQ(6, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // trigger the second deferred transaction
+    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+    sFakeComposer->runVSyncAndWait();
+    // TODO: Compute from layer size?
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
+    referenceFrame[SYNC_LAYER].mSwapCount++;
+    EXPECT_EQ(7, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(TransactionTest, SetRelativeLayer) {
+    constexpr int RELATIVE_LAYER = 2;
+    auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+    fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
+
+    // Now we stack the surface above the foreground surface and make sure it is visible.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(relativeSurfaceControl, 64, 64);
+        ts.show(relativeSurfaceControl);
+        ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+    }
+    auto referenceFrame = mBaseFrame;
+    // NOTE: All three layers will be visible as the surfaces are
+    // transparent because of the RGBA format.
+    referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+    referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    // A call to setLayer will override a call to setRelativeLayer
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(relativeSurfaceControl, 0);
+    }
+
+    // Previous top layer will now appear at the bottom.
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
+    EXPECT_EQ(3, sFakeComposer->getFrameCount());
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+class ChildLayerTest : public TransactionTest {
+protected:
+    constexpr static int CHILD_LAYER = 2;
+
+    void SetUp() override {
+        TransactionTest::SetUp();
+        mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+        fillSurfaceRGBA8(mChild, LIGHT_GRAY);
+
+        sFakeComposer->runVSyncAndWait();
+        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+        mBaseFrame[CHILD_LAYER].mSwapCount = 1;
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+    }
+    void TearDown() override {
+        mChild = 0;
+        TransactionTest::TearDown();
+    }
+
+    sp<SurfaceControl> mChild;
+};
+
+TEST_F(ChildLayerTest, Positioning) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
+        // Move to the same position as in the original setup.
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+    }
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Cropping) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    }
+    // NOTE: The foreground surface would be occluded by the child
+    // now, but is included in the stack because the child is
+    // transparent.
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, FinalCropping) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Constraints) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setPosition(mChild, 63, 63);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Scaling) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
+    }
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, LayerAlpha) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setAlpha(mChild, 0.5);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.5);
+    }
+
+    auto referenceFrame2 = referenceFrame;
+    referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
+    referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+    }
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+    }
+
+    auto referenceFrame2 = referenceFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, DetachChildren) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.detachChildren(mFGSurfaceControl);
+    }
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.hide(mChild);
+    }
+
+    // Nothing should have changed. The child control becomes a no-op
+    // zombie on detach. See comments for detachChildren in the
+    // SurfaceControl.h file.
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+    }
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // We cause scaling by 2.
+        ts.setSize(mFGSurfaceControl, 128, 128);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+    }
+
+    // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+    // the WM specified state size.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 64);
+    }
+
+    sp<Surface> s = mFGSurfaceControl->getSurface();
+    auto anw = static_cast<ANativeWindow*>(s.get());
+    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+    native_window_set_buffers_dimensions(anw, 64, 128);
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+    sFakeComposer->runVSyncAndWait();
+
+    // The child should still be in the same place and not have any strange scaling as in
+    // b/37673612.
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
+    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
+    referenceFrame[FG_LAYER].mSwapCount++;
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+    // Destroy the child layer
+    mChild.clear();
+
+    // Now recreate it as hidden
+    mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                            PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
+                                            mFGSurfaceControl.get());
+
+    // Show the child layer in a deferred transaction
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(), 
+                                      mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        ts.show(mChild);
+    }
+
+    // Render the foreground surface a few times
+    //
+    // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+    // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+    // never acquire/release the first buffer
+    ALOGI("Filling 1");
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 2");
+    fillSurfaceRGBA8(mFGSurfaceControl, BLUE);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 3");
+    fillSurfaceRGBA8(mFGSurfaceControl, RED);
+    sFakeComposer->runVSyncAndWait();
+    ALOGI("Filling 4");
+    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+    sFakeComposer->runVSyncAndWait();
+}
+
+class LatchingTest : public TransactionTest {
+protected:
+    void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
+
+    void unlockFGBuffer() {
+        sp<Surface> s = mFGSurfaceControl->getSurface();
+        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+        sFakeComposer->runVSyncAndWait();
+    }
+
+    void completeFGResize() {
+        fillSurfaceRGBA8(mFGSurfaceControl, RED);
+        sFakeComposer->runVSyncAndWait();
+    }
+    void restoreInitialState() {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 64, 64);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+    }
+};
+
+TEST_F(LatchingTest, SurfacePositionLatching) {
+    // By default position can be updated even while
+    // a resize is pending.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 32, 32);
+        ts.setPosition(mFGSurfaceControl, 100, 100);
+    }
+
+    // The size should not have updated as we have not provided a new buffer.
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    // Now we repeat with setGeometryAppliesWithResize
+    // and verify the position DOESN'T latch.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setSize(mFGSurfaceControl, 32, 32);
+        ts.setPosition(mFGSurfaceControl, 100, 100);
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
+    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, CropLatching) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+    referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatching) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame1[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame2[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+// In this test we ensure that setGeometryAppliesWithResize actually demands
+// a buffer of the new size, and not just any size.
+TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
+    // Normally the crop applies immediately even while a resize is pending.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    }
+
+    auto referenceFrame1 = mBaseFrame;
+    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame1[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
+
+    restoreInitialState();
+
+    // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
+    // initiating the resize.
+    lockAndFillFGBuffer();
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    // We now submit our old buffer, at the old size, and ensure it doesn't
+    // trigger geometry latching.
+    unlockFGBuffer();
+
+    auto referenceFrame2 = mBaseFrame;
+    referenceFrame2[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+    auto referenceFrame3 = referenceFrame2;
+    referenceFrame3[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 127, 127};
+    referenceFrame3[FG_LAYER].mSourceCrop =
+            hwc_frect_t{0.f, 0.f, static_cast<float>(127 - 64), static_cast<float>(127 - 64)};
+    referenceFrame3[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame3, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(LatchingTest, FinalCropLatchingRegressionForb37531386) {
+    // In this scenario, we attempt to set the final crop a second time while the resize
+    // is still pending, and ensure we are successful. Success meaning the second crop
+    // is the one which eventually latches and not the first.
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    }
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+    }
+    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+
+    completeFGResize();
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mSwapCount++;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment;
+    ::testing::AddGlobalTestEnvironment(fakeEnvironment);
+    ::testing::InitGoogleMock(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp
new file mode 100644
index 0000000..0957d6a
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Android.bp
@@ -0,0 +1,56 @@
+// 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.
+
+cc_test {
+    name: "test-hwc2",
+    defaults: ["surfaceflinger_defaults"],
+    tags: ["test"],
+    cflags: [
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-fno-builtin",
+        "-fstack-protector-all",
+        "-g",
+        "-Wextra",
+    ],
+    srcs: [
+        "Hwc2Test.cpp",
+        "Hwc2TestProperties.cpp",
+        "Hwc2TestLayer.cpp",
+        "Hwc2TestLayers.cpp",
+        "Hwc2TestBuffer.cpp",
+        "Hwc2TestClientTarget.cpp",
+        "Hwc2TestVirtualDisplay.cpp",
+        "Hwc2TestPixelComparator.cpp",
+    ],
+    static_libs: [
+        "libadf",
+        "libadfhwc",
+        "libbase",
+        "libmath",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.common@1.1",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libgui",
+        "libhardware",
+        "libhwui",
+        "liblog",
+        "libsync",
+        "libui",
+        "libutils",
+    ],
+}
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
deleted file mode 100644
index 203ced5..0000000
--- a/services/surfaceflinger/tests/hwc2/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := test-hwc2
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS += \
-    -fstack-protector-all \
-    -g \
-    -Wall -Wextra \
-    -Werror \
-    -fno-builtin \
-    -DEGL_EGLEXT_PROTOTYPES \
-    -DGL_GLEXT_PROTOTYPES
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    libhardware \
-    libEGL \
-    libGLESv2 \
-    libui \
-    libgui \
-    liblog \
-    libsync
-LOCAL_STATIC_LIBRARIES := \
-    libbase \
-    libadf \
-    libadfhwc \
-    libmath
-LOCAL_SRC_FILES := \
-    Hwc2Test.cpp \
-    Hwc2TestProperties.cpp \
-    Hwc2TestLayer.cpp \
-    Hwc2TestLayers.cpp \
-    Hwc2TestBuffer.cpp \
-    Hwc2TestClientTarget.cpp \
-    Hwc2TestVirtualDisplay.cpp
-
-include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 062485e..13774b4 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -22,6 +22,7 @@
 #include <android-base/unique_fd.h>
 #include <hardware/hardware.h>
 #include <sync/sync.h>
+#include <ui/GraphicTypes.h>
 
 #define HWC2_INCLUDE_STRINGIFICATION
 #define HWC2_USE_CPP11
@@ -34,6 +35,9 @@
 #include "Hwc2TestClientTarget.h"
 #include "Hwc2TestVirtualDisplay.h"
 
+using android::ui::ColorMode;
+using android::ui::Dataspace;
+
 void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
         hwc2_display_t display, int32_t connected);
 void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
@@ -382,7 +386,9 @@
         if (outErr) {
             *outErr = err;
         } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position";
+            ASSERT_TRUE((err == HWC2_ERROR_NONE) ||
+                (err == HWC2_ERROR_BAD_LAYER)) <<
+                "failed to set cursor position";
         }
     }
 
@@ -437,14 +443,14 @@
     }
 
     void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer,
-            android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>(
                 getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE));
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                layer, dataspace));
+                layer, static_cast<int>(dataspace)));
         if (outErr) {
             *outErr = err;
         } else {
@@ -652,7 +658,7 @@
             hwc2_layer_request_t request = requests.at(i);
 
             EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
-                    0) << "get display requests returned an unknown layer";
+                    1) << "get display requests returned an unknown layer";
             EXPECT_NE(request, 0) << "returned empty request for layer "
                     << requestedLayer;
 
@@ -785,14 +791,14 @@
 
     void getClientTargetSupport(hwc2_display_t display, int32_t width,
             int32_t height, android_pixel_format_t format,
-            android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
                 getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT));
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width,
-                height, format, dataspace));
+                height, format, static_cast<int>(dataspace)));
         if (outErr) {
             *outErr = err;
         } else {
@@ -802,7 +808,7 @@
     }
 
     void setClientTarget(hwc2_display_t display, buffer_handle_t handle,
-            int32_t acquireFence, android_dataspace_t dataspace,
+            int32_t acquireFence, Dataspace dataspace,
             hwc_region_t damage, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>(
@@ -810,7 +816,7 @@
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle,
-                acquireFence, dataspace, damage));
+                acquireFence, static_cast<int>(dataspace), damage));
         if (outErr) {
             *outErr = err;
         } else {
@@ -863,7 +869,7 @@
     }
 
     void getColorModes(hwc2_display_t display,
-            std::vector<android_color_mode_t>* outColorModes,
+            std::vector<ColorMode>* outColorModes,
             hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>(
@@ -890,7 +896,7 @@
         }
     }
 
-    void setColorMode(hwc2_display_t display, android_color_mode_t colorMode,
+    void setColorMode(hwc2_display_t display, ColorMode colorMode,
             hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>(
@@ -903,7 +909,7 @@
             *outErr = err;
         } else {
             ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode "
-                    << colorMode;
+                    << static_cast<int>(colorMode);
         }
     }
 
@@ -1603,9 +1609,10 @@
         EXPECT_EQ(layers.size(), fences.size());
 
         for (int32_t fence : fences) {
-            EXPECT_GE(sync_wait(fence, msWait), 0);
-            if (fence >= 0)
+            if (fence >= 0) {
+                EXPECT_GE(sync_wait(fence, msWait), 0);
                 close(fence);
+            }
         }
     }
 
@@ -1643,8 +1650,9 @@
                 testLayers->getBlendMode(layer)));
         EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
                 testLayers->getColor(layer)));
-        EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left,
-                cursor.top));
+        if (composition == HWC2_COMPOSITION_CURSOR)
+            EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer,
+            cursor.left, cursor.top));
         EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
                 testLayers->getDataspace(layer)));
         EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
@@ -1684,7 +1692,7 @@
             const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
             const Area& displayArea)
     {
-        android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+        Dataspace dataspace = Dataspace::UNKNOWN;
         hwc_region_t damage = { };
         buffer_handle_t handle;
         int32_t acquireFence;
@@ -1771,6 +1779,145 @@
         }
     }
 
+    void createAndPresentVirtualDisplay(size_t layerCnt,
+            Hwc2TestCoverage coverage,
+            const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
+            coverageExceptions)
+    {
+        Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
+        hwc2_display_t display;
+        android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+        do {
+            // Items dependent on the display dimensions
+            hwc2_error_t err = HWC2_ERROR_NONE;
+            const UnsignedArea& dimension =
+                    testVirtualDisplay.getDisplayDimension();
+            ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
+                    dimension.height, &desiredFormat, &display, &err));
+            ASSERT_TRUE(err == HWC2_ERROR_NONE)
+                    << "Cannot allocate virtual display";
+
+            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+            ASSERT_NO_FATAL_FAILURE(enableVsync(display));
+
+            std::vector<hwc2_config_t> configs;
+            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+            for (auto config : configs) {
+                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+                Area displayArea;
+                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+                        &displayArea));
+
+                std::vector<hwc2_layer_t> layers;
+                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers,
+                        layerCnt));
+                Hwc2TestLayers testLayers(layers, coverage, displayArea,
+                        coverageExceptions);
+
+                /*
+                 * Layouts that do not cover an entire virtual display will
+                 * cause undefined behavior.
+                 * Enable optimizeLayouts to avoid this.
+                 */
+                testLayers.optimizeLayouts();
+                do {
+                    // Items dependent on the testLayers properties
+                    std::set<hwc2_layer_t> clientLayers;
+                    std::set<hwc2_layer_t> clearLayers;
+                    uint32_t numTypes, numRequests;
+                    bool hasChanges, skip;
+                    bool flipClientTarget;
+                    int32_t presentFence;
+                    Hwc2TestClientTarget testClientTarget;
+                    buffer_handle_t outputBufferHandle;
+                    android::base::unique_fd outputBufferReleaseFence;
+
+                    ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+                            &testLayers, &skip));
+
+                    if (skip)
+                        continue;
+
+                    ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+                            &numRequests, &hasChanges));
+
+                    if (hasChanges)
+                        EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+                                << "wrong number of requests";
+
+                    ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
+                            testLayers, layers, numTypes, &clientLayers));
+
+                    ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
+                            numRequests, &clearLayers, &flipClientTarget));
+                    ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
+                            &testClientTarget, testLayers, clientLayers,
+                            clearLayers, flipClientTarget, displayArea));
+                    ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
+
+                    ASSERT_EQ(testVirtualDisplay.getOutputBuffer(
+                            &outputBufferHandle, &outputBufferReleaseFence), 0);
+                    ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display,
+                            outputBufferHandle, outputBufferReleaseFence));
+
+                    EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
+                            &presentFence));
+                    ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
+
+                    ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers,
+                            &layers, &clearLayers), 0);
+
+                    /*
+                     * Upscaling the image causes minor pixel differences.
+                     * Work around this by using some threshold.
+                     *
+                     * Fail test if we are off by more than 1% of our
+                     * pixels.
+                     */
+                    ComparatorResult& comparatorResult = ComparatorResult::get();
+                    int threshold = (dimension.width * dimension.height) / 100;
+                    double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) /
+                            (dimension.width * dimension.height);
+
+                    if (comparatorResult.getDifferentPixelCount() != 0)
+                        EXPECT_TRUE(false)
+                                << comparatorResult.getDifferentPixelCount() << " pixels ("
+                                << diffPercent << "%) are different.";
+
+                    if (comparatorResult.getDifferentPixelCount() > threshold) {
+                        EXPECT_TRUE(false)
+                                << "Mismatched pixel count exceeds threshold. "
+                                << "Writing buffers to file.";
+
+                        const ::testing::TestInfo* const test_info =
+                                ::testing::UnitTest::GetInstance()
+                                ->current_test_info();
+
+                        EXPECT_EQ(testVirtualDisplay.writeBuffersToFile(
+                                test_info->name()), 0)
+                                << "Failed to write buffers.";
+                    }
+
+                    ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold)
+                            << comparatorResult.getDifferentPixelCount() << " pixels ("
+                            << diffPercent << "%) are different. "
+                            << "Exceeds 1% threshold, terminating test. "
+                            << "Test case: " << testLayers.dump();
+
+                } while (testLayers.advance());
+
+                ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
+                        std::move(layers)));
+            }
+            ASSERT_NO_FATAL_FAILURE(disableVsync(display));
+            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+            ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+        } while (testVirtualDisplay.advance());
+    }
+
     hwc2_device_t* mHwc2Device = nullptr;
 
     enum class Hwc2TestHotplugStatus {
@@ -2895,7 +3042,6 @@
     ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
             [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
                     Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
                 const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
                 EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
                         cursorPosition.left, cursorPosition.top, outErr));
@@ -3571,7 +3717,7 @@
  * layer. */
 TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic)
 {
-    const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    const Dataspace dataspace = Dataspace::UNKNOWN;
     const hwc_region_t damage = { };
     const size_t layerCnt = 1;
 
@@ -3650,7 +3796,7 @@
     std::set<hwc2_layer_t> clientLayers;
     std::set<hwc2_layer_t> flipClientTargetLayers;
     bool flipClientTarget = true;
-    const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    const Dataspace dataspace = Dataspace::UNKNOWN;
     const hwc_region_t damage = { };
     buffer_handle_t handle;
     int32_t acquireFence;
@@ -4110,33 +4256,33 @@
     EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
 }
 
-static const std::array<android_color_mode, 9> androidColorModes = {{
-    HAL_COLOR_MODE_NATIVE,
-    HAL_COLOR_MODE_STANDARD_BT601_625,
-    HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED,
-    HAL_COLOR_MODE_STANDARD_BT601_525,
-    HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED,
-    HAL_COLOR_MODE_STANDARD_BT709,
-    HAL_COLOR_MODE_DCI_P3,
-    HAL_COLOR_MODE_SRGB,
-    HAL_COLOR_MODE_ADOBE_RGB,
+static const std::array<ColorMode, 9> androidColorModes = {{
+    ColorMode::NATIVE,
+    ColorMode::STANDARD_BT601_625,
+    ColorMode::STANDARD_BT601_625_UNADJUSTED,
+    ColorMode::STANDARD_BT601_525,
+    ColorMode::STANDARD_BT601_525_UNADJUSTED,
+    ColorMode::STANDARD_BT709,
+    ColorMode::DCI_P3,
+    ColorMode::SRGB,
+    ColorMode::ADOBE_RGB,
 }};
 
 /* TESTCASE: Tests that the HWC2 can get the color modes for a display. The
- * display must support HAL_COLOR_MODE_NATIVE */
+ * display must support ColorMode::NATIVE */
 TEST_F(Hwc2Test, GET_COLOR_MODES)
 {
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                std::vector<android_color_mode_t> colorModes;
+                std::vector<ColorMode> colorModes;
 
                 ASSERT_NO_FATAL_FAILURE(test->getColorModes(display,
                         &colorModes));
 
                 EXPECT_NE(std::count(colorModes.begin(), colorModes.end(),
-                        HAL_COLOR_MODE_NATIVE), 0) << "all displays"
-                        " must support HAL_COLOR_MODE_NATIVE";
+                        ColorMode::NATIVE), 0) << "all displays"
+                        " must support ColorMode::NATIVE";
             }
     ));
 }
@@ -4145,7 +4291,7 @@
 TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display)
 {
     hwc2_display_t display;
-    std::vector<android_color_mode_t> colorModes;
+    std::vector<ColorMode> colorModes;
     hwc2_error_t err = HWC2_ERROR_NONE;
 
     ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
@@ -4160,7 +4306,7 @@
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+                const ColorMode colorMode = ColorMode::NATIVE;
 
                 EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode));
             }
@@ -4171,7 +4317,7 @@
 TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display)
 {
     hwc2_display_t display;
-    const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+    const ColorMode colorMode = ColorMode::NATIVE;
     hwc2_error_t err = HWC2_ERROR_NONE;
 
     ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
@@ -4186,8 +4332,7 @@
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                const android_color_mode_t colorMode =
-                        static_cast<android_color_mode_t>(-1);
+                const ColorMode colorMode = static_cast<ColorMode>(-1);
                 hwc2_error_t err = HWC2_ERROR_NONE;
 
                 ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode,
@@ -4406,11 +4551,11 @@
 /* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
 TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
 {
-    hwc2_display_t display = HWC_DISPLAY_PRIMARY;
     hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+    for (auto display : mDisplays) {
+        ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
+        EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+    }
 }
 
 /* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
@@ -4476,7 +4621,7 @@
                 buffer_handle_t handle;
                 android::base::unique_fd acquireFence;
 
-                if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0)
+                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0)
                     EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
                             handle, acquireFence));
             }));
@@ -4496,7 +4641,7 @@
 
                 ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
 
-                if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0)
+                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0)
                     return;
 
                 ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
@@ -4536,7 +4681,7 @@
             android::base::unique_fd acquireFence;
             hwc2_error_t err = HWC2_ERROR_NONE;
 
-            if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0)
+            if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0)
                 continue;
 
             ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
@@ -4554,3 +4699,74 @@
 
     ASSERT_NO_FATAL_FAILURE(dump(&buffer));
 }
+
+/*
+ * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all
+ * virtual display tests as we don't handle this case correctly.
+ *
+ * Only default dataspace is supported in our drawing code.
+ */
+const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>
+        virtualDisplayExceptions =
+        {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default},
+        {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}};
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 1;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
+    const size_t layerCnt = 1;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 2;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 3;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 4;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 5;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 1d3a1d3..6484562 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -23,14 +23,17 @@
 #include <gui/BufferItemConsumer.h>
 
 #include <ui/GraphicBuffer.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 #include <math/vec4.h>
 
 #include <GLES3/gl3.h>
-
+#include <SkImageEncoder.h>
+#include <SkStream.h>
 #include "Hwc2TestBuffer.h"
 #include "Hwc2TestLayers.h"
 
 using namespace android;
+using android::hardware::graphics::common::V1_0::BufferUsage;
 
 /* Returns a fence from egl */
 typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
@@ -396,8 +399,9 @@
 {
     /* Create new graphic buffer with correct dimensions */
     mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
-            mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
-            "hwc2_test_buffer");
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
     int ret = mGraphicBuffer->initCheck();
     if (ret) {
         return ret;
@@ -408,7 +412,8 @@
 
     /* Locks the buffer for writing */
     uint8_t* img;
-    mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
 
     uint32_t stride = mGraphicBuffer->getStride();
 
@@ -458,31 +463,22 @@
 
 Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
 
-/* Generates a client target buffer using the layers assigned for client
- * composition. Takes into account the individual layer properties such as
+/* Generates a buffer from layersToDraw.
+ * Takes into account the individual layer properties such as
  * transform, blend mode, source crop, etc. */
-int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
-        int32_t* outFence, const Area& bufferArea,
+static void compositeBufferFromLayers(
+        const android::sp<android::GraphicBuffer>& graphicBuffer,
+        android_pixel_format_t format, const Area& bufferArea,
         const Hwc2TestLayers* testLayers,
-        const std::set<hwc2_layer_t>* clientLayers,
+        const std::set<hwc2_layer_t>* layersToDraw,
         const std::set<hwc2_layer_t>* clearLayers)
 {
-    /* Create new graphic buffer with correct dimensions */
-    mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
-            mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
-            "hwc2_test_buffer");
-    int ret = mGraphicBuffer->initCheck();
-    if (ret) {
-        return ret;
-    }
-    if (!mGraphicBuffer->handle) {
-        return -EINVAL;
-    }
-
+    /* Locks the buffer for writing */
     uint8_t* img;
-    mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
 
-    uint32_t stride = mGraphicBuffer->getStride();
+    uint32_t stride = graphicBuffer->getStride();
 
     float bWDiv3 = bufferArea.width / 3;
     float bW2Div3 = bufferArea.width * 2 / 3;
@@ -497,10 +493,10 @@
             uint8_t r = 0, g = 0, b = 0;
             float a = 0.0f;
 
-            /* Cycle through each client layer from back to front and
+            /* Cycle through each layer from back to front and
              * update the pixel color. */
-            for (auto layer = clientLayers->rbegin();
-                    layer != clientLayers->rend(); ++layer) {
+            for (auto layer = layersToDraw->rbegin();
+                    layer != layersToDraw->rend(); ++layer) {
 
                 const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
 
@@ -570,8 +566,8 @@
                      * (100x50) at the end of the transformation. */
                     if (transform & HWC_TRANSFORM_ROT_90) {
                         float tmp = xPos;
-                        xPos = -yPos * dfW / dfH;
-                        yPos = tmp * dfH / dfW;
+                        xPos = yPos * dfW / dfH;
+                        yPos = -tmp * dfH / dfW;
                     }
 
                     /* Change origin back to the top left corner of the
@@ -682,14 +678,114 @@
             }
 
             /* Set the pixel color */
-            setColor(x, y, mFormat, stride, img, r, g, b, a * 255);
+            setColor(x, y, format, stride, img, r, g, b, a * 255);
         }
     }
 
-    mGraphicBuffer->unlock();
+    graphicBuffer->unlock();
+}
+
+/* Generates a client target buffer using the layers assigned for client
+ * composition. Takes into account the individual layer properties such as
+ * transform, blend mode, source crop, etc. */
+int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
+        int32_t* outFence, const Area& bufferArea,
+        const Hwc2TestLayers* testLayers,
+        const std::set<hwc2_layer_t>* clientLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    /* Create new graphic buffer with correct dimensions */
+    mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
+            clientLayers, clearLayers);
 
     *outFence = mFenceGenerator->get();
     *outHandle = mGraphicBuffer->handle;
 
     return 0;
 }
+
+void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
+{
+    mBufferArea.width = bufferArea.width;
+    mBufferArea.height = bufferArea.height;
+}
+
+bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
+{
+    SkFILEWStream file(path.c_str());
+    const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
+            mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
+            SkAlphaType::kPremul_SkAlphaType);
+
+    uint8_t* img;
+    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
+
+    SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
+    bool result = file.isValid() && SkEncodeImage(&file, pixmap,
+            SkEncodedImageFormat::kPNG, 100);
+
+    mGraphicBuffer->unlock();
+    return result;
+}
+
+/* Generates a buffer that holds the expected result of compositing all of our
+ * layers */
+int Hwc2TestExpectedBuffer::generateExpectedBuffer(
+        const Hwc2TestLayers* testLayers,
+        const std::vector<hwc2_layer_t>* allLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+            "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
+            allLayers->end());
+
+    compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
+            &allLayerSet, clearLayers);
+
+    return 0;
+}
+
+int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
+        int32_t* outFence)
+{
+    if (mBufferArea.width == -1 || mBufferArea.height == -1)
+        return -EINVAL;
+
+    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN |
+            BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    *outFence = -1;
+    *outHandle = mGraphicBuffer->handle;
+
+    return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
index b2b3a66..fd54fef 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
@@ -71,4 +71,38 @@
     const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 };
 
+
+class Hwc2TestVirtualBuffer {
+public:
+    void updateBufferArea(const Area& bufferArea);
+
+    bool writeBufferToFile(std::string path);
+
+    android::sp<android::GraphicBuffer>& graphicBuffer()
+    {
+        return mGraphicBuffer;
+    }
+
+protected:
+    android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+    Area mBufferArea = {-1, -1};
+
+    const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+};
+
+
+class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer {
+public:
+    int generateExpectedBuffer(const Hwc2TestLayers* testLayers,
+            const std::vector<hwc2_layer_t>* allLayers,
+            const std::set<hwc2_layer_t>* clearLayers);
+};
+
+
+class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer {
+public:
+    int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence);
+};
+
 #endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
index 6925492..14c60a7 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
@@ -91,7 +91,7 @@
     return mBufferArea.get();
 }
 
-android_dataspace_t Hwc2TestClientTargetSupport::getDataspace() const
+android::ui::Dataspace Hwc2TestClientTargetSupport::getDataspace() const
 {
     return mDataspace.get();
 }
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
index 3b47978..6f4090f 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
@@ -53,7 +53,7 @@
     bool advance();
 
     Area getBufferArea() const;
-    android_dataspace_t getDataspace() const;
+    android::ui::Dataspace getDataspace() const;
     const hwc_region_t getSurfaceDamage() const;
 
 private:
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
index 937fce2..c1c9cc8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
@@ -146,7 +146,7 @@
     return mDisplayFrame.get();
 }
 
-android_dataspace_t Hwc2TestLayer::getDataspace() const
+android::ui::Dataspace Hwc2TestLayer::getDataspace() const
 {
     return mDataspace.get();
 }
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
index 0e7dd22..29ae521 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
@@ -54,7 +54,7 @@
     hwc_color_t            getColor() const;
     hwc2_composition_t     getComposition() const;
     hwc_rect_t             getCursorPosition() const;
-    android_dataspace_t    getDataspace() const;
+    android::ui::Dataspace     getDataspace() const;
     hwc_rect_t             getDisplayFrame() const;
     float                  getPlaneAlpha() const;
     hwc_frect_t            getSourceCrop() const;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
index 495ef79..90127a1 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
@@ -169,7 +169,7 @@
     return mTestLayers.at(layer).getCursorPosition();
 }
 
-android_dataspace_t Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
+android::ui::Dataspace Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
 {
     if (mTestLayers.count(layer) == 0) {
         []() { GTEST_FAIL(); }();
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
index d95a91f..909dd48 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
@@ -63,7 +63,7 @@
     hwc_color_t            getColor(hwc2_layer_t layer) const;
     hwc2_composition_t     getComposition(hwc2_layer_t layer) const;
     hwc_rect_t             getCursorPosition(hwc2_layer_t layer) const;
-    android_dataspace_t    getDataspace(hwc2_layer_t layer) const;
+    android::ui::Dataspace     getDataspace(hwc2_layer_t layer) const;
     hwc_rect_t             getDisplayFrame(hwc2_layer_t layer) const;
     android_pixel_format_t getFormat(hwc2_layer_t layer) const;
     float                  getPlaneAlpha(hwc2_layer_t layer) const;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
new file mode 100644
index 0000000..904b927
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <android/hardware/graphics/common/1.0/types.h>
+
+#include "Hwc2TestPixelComparator.h"
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
+uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride,
+        uint8_t* img) const
+{
+    uint32_t r = img[(y * stride + x) * 4 + 0];
+    uint32_t g = img[(y * stride + x) * 4 + 1];
+    uint32_t b = img[(y * stride + x) * 4 + 2];
+    uint32_t a = img[(y * stride + x) * 4 + 3];
+
+    uint32_t pixel = 0;
+    pixel |= r;
+    pixel |= g << 8;
+    pixel |= b << 16;
+    pixel |= a << 24;
+    return pixel;
+}
+
+void ComparatorResult::CompareBuffers(
+        android::sp<android::GraphicBuffer>& resultBuffer,
+        android::sp<android::GraphicBuffer>& expectedBuffer)
+{
+    uint8_t* resultBufferImg;
+    uint8_t* expectedBufferImg;
+    resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+            (void**)(&resultBufferImg));
+
+    expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+            (void**)(&expectedBufferImg));
+    mComparisons.clear();
+    int32_t mDifferentPixelCount = 0;
+    int32_t mBlankPixelCount = 0;
+
+    for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) {
+        for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) {
+            uint32_t result = getPixel(x, y, resultBuffer->getStride(),
+                    resultBufferImg);
+            uint32_t expected = getPixel(x, y, expectedBuffer->getStride(),
+                    expectedBufferImg);
+
+            if (result == 0)
+                mBlankPixelCount++;
+
+            if (result != expected)
+                mDifferentPixelCount++;
+
+            mComparisons.emplace_back(std::make_tuple(x, y, result, expected));
+        }
+    }
+    resultBuffer->unlock();
+    expectedBuffer->unlock();
+}
+
+std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y,
+        uint32_t resultPixel, uint32_t expectedPixel) const
+{
+    uint32_t resultAlpha = (resultPixel >> 24) & 0xFF;
+    uint32_t resultBlue = (resultPixel >> 16) & 0xFF;
+    uint32_t resultGreen = (resultPixel >> 8) & 0xFF;
+    uint32_t resultRed = resultPixel & 0xFF;
+
+    uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF;
+    uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF;
+    uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF;
+    uint32_t expectedRed = expectedPixel & 0xFF;
+
+    std::ostringstream stream;
+
+    stream << "x: " << x << " y: " << y << std::endl;
+    stream << std::hex;
+    stream << "Result pixel:   " << resultRed << "|" << resultGreen << "|"
+           << resultBlue << "|" << resultAlpha << std::endl;
+
+    stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|"
+           << expectedBlue << "|" << expectedAlpha << std::endl;
+
+    return stream.str();
+}
+
+std::string ComparatorResult::dumpComparison() const
+{
+    std::ostringstream stream;
+    stream << "Number of different pixels: " << mDifferentPixelCount;
+
+    for (const auto& comparison : mComparisons) {
+        if (std::get<2>(comparison) != std::get<3>(comparison))
+            stream << pixelDiff(std::get<0>(comparison),
+                    std::get<1>(comparison), std::get<2>(comparison),
+                    std::get<3>(comparison));
+    }
+    return stream.str();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
new file mode 100644
index 0000000..55fa936
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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 _HWC2_TEST_PIXEL_COMPARATOR_H
+#define _HWC2_TEST_PIXEL_COMPARATOR_H
+
+#include <ui/GraphicBuffer.h>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+class ComparatorResult {
+public:
+    static ComparatorResult& get()
+    {
+        static ComparatorResult instance;
+        return instance;
+    }
+
+    void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer,
+            android::sp<android::GraphicBuffer>& expectedBuffer);
+
+    std::string dumpComparison() const;
+
+    ComparatorResult(const ComparatorResult&) = delete;
+    ComparatorResult(ComparatorResult&&) = delete;
+    ComparatorResult& operator=(ComparatorResult const&) = delete;
+    ComparatorResult& operator=(ComparatorResult&&) = delete;
+
+    int32_t getDifferentPixelCount() const { return mDifferentPixelCount; }
+    int32_t getBlankPixelCount() const { return mBlankPixelCount; }
+
+private:
+    ComparatorResult() = default;
+    uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const;
+    std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel,
+            uint32_t expectedPixel) const;
+
+    int32_t mDifferentPixelCount;
+    int32_t mBlankPixelCount;
+    /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */
+    std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
+            mComparisons;
+};
+
+#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index b5522de..c5b92d0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -262,62 +262,62 @@
 std::string Hwc2TestDataspace::dump() const
 {
     std::stringstream dmp;
-    dmp << "\tdataspace: " << get() << "\n";
+    dmp << "\tdataspace: " << static_cast<int32_t>(get()) << "\n";
     return dmp.str();
 }
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::defaultDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
 };
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
-    HAL_DATASPACE_V0_SRGB,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::basicDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
+    android::ui::Dataspace::V0_SRGB,
 };
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
-    HAL_DATASPACE_ARBITRARY,
-    HAL_DATASPACE_STANDARD_SHIFT,
-    HAL_DATASPACE_STANDARD_MASK,
-    HAL_DATASPACE_STANDARD_UNSPECIFIED,
-    HAL_DATASPACE_STANDARD_BT709,
-    HAL_DATASPACE_STANDARD_BT601_625,
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT601_525,
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT2020,
-    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE,
-    HAL_DATASPACE_STANDARD_BT470M,
-    HAL_DATASPACE_STANDARD_FILM,
-    HAL_DATASPACE_TRANSFER_SHIFT,
-    HAL_DATASPACE_TRANSFER_MASK,
-    HAL_DATASPACE_TRANSFER_UNSPECIFIED,
-    HAL_DATASPACE_TRANSFER_LINEAR,
-    HAL_DATASPACE_TRANSFER_SRGB,
-    HAL_DATASPACE_TRANSFER_SMPTE_170M,
-    HAL_DATASPACE_TRANSFER_GAMMA2_2,
-    HAL_DATASPACE_TRANSFER_GAMMA2_8,
-    HAL_DATASPACE_TRANSFER_ST2084,
-    HAL_DATASPACE_TRANSFER_HLG,
-    HAL_DATASPACE_RANGE_SHIFT,
-    HAL_DATASPACE_RANGE_MASK,
-    HAL_DATASPACE_RANGE_UNSPECIFIED,
-    HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_SRGB_LINEAR,
-    HAL_DATASPACE_V0_SRGB_LINEAR,
-    HAL_DATASPACE_SRGB,
-    HAL_DATASPACE_V0_SRGB,
-    HAL_DATASPACE_JFIF,
-    HAL_DATASPACE_V0_JFIF,
-    HAL_DATASPACE_BT601_625,
-    HAL_DATASPACE_V0_BT601_625,
-    HAL_DATASPACE_BT601_525,
-    HAL_DATASPACE_V0_BT601_525,
-    HAL_DATASPACE_BT709,
-    HAL_DATASPACE_V0_BT709,
-    HAL_DATASPACE_DEPTH,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::completeDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
+    android::ui::Dataspace::ARBITRARY,
+    android::ui::Dataspace::STANDARD_SHIFT,
+    android::ui::Dataspace::STANDARD_MASK,
+    android::ui::Dataspace::STANDARD_UNSPECIFIED,
+    android::ui::Dataspace::STANDARD_BT709,
+    android::ui::Dataspace::STANDARD_BT601_625,
+    android::ui::Dataspace::STANDARD_BT601_625_UNADJUSTED,
+    android::ui::Dataspace::STANDARD_BT601_525,
+    android::ui::Dataspace::STANDARD_BT601_525_UNADJUSTED,
+    android::ui::Dataspace::STANDARD_BT2020,
+    android::ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE,
+    android::ui::Dataspace::STANDARD_BT470M,
+    android::ui::Dataspace::STANDARD_FILM,
+    android::ui::Dataspace::TRANSFER_SHIFT,
+    android::ui::Dataspace::TRANSFER_MASK,
+    android::ui::Dataspace::TRANSFER_UNSPECIFIED,
+    android::ui::Dataspace::TRANSFER_LINEAR,
+    android::ui::Dataspace::TRANSFER_SRGB,
+    android::ui::Dataspace::TRANSFER_SMPTE_170M,
+    android::ui::Dataspace::TRANSFER_GAMMA2_2,
+    android::ui::Dataspace::TRANSFER_GAMMA2_8,
+    android::ui::Dataspace::TRANSFER_ST2084,
+    android::ui::Dataspace::TRANSFER_HLG,
+    android::ui::Dataspace::RANGE_SHIFT,
+    android::ui::Dataspace::RANGE_MASK,
+    android::ui::Dataspace::RANGE_UNSPECIFIED,
+    android::ui::Dataspace::RANGE_FULL,
+    android::ui::Dataspace::RANGE_LIMITED,
+    android::ui::Dataspace::SRGB_LINEAR,
+    android::ui::Dataspace::V0_SRGB_LINEAR,
+    android::ui::Dataspace::SRGB,
+    android::ui::Dataspace::V0_SRGB,
+    android::ui::Dataspace::JFIF,
+    android::ui::Dataspace::V0_JFIF,
+    android::ui::Dataspace::BT601_625,
+    android::ui::Dataspace::V0_BT601_625,
+    android::ui::Dataspace::BT601_525,
+    android::ui::Dataspace::V0_BT601_525,
+    android::ui::Dataspace::BT709,
+    android::ui::Dataspace::V0_BT709,
+    android::ui::Dataspace::DEPTH,
 };
 
 
@@ -335,9 +335,9 @@
     return dmp.str();
 }
 
-void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer)
+void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer)
 {
-    mBuffer = buffer;
+    mBuffers.insert(buffer);
     updateDependents();
 }
 
@@ -345,8 +345,8 @@
 {
     const UnsignedArea& curr = get();
 
-    if (mBuffer)
-        mBuffer->updateBufferArea({static_cast<int32_t>(curr.width),
+    for (Hwc2TestVirtualBuffer* buffer : mBuffers)
+        buffer->updateBufferArea({static_cast<int32_t>(curr.width),
                 static_cast<int32_t>(curr.height)});
 }
 
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index c2029ab..d7082f3 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -20,6 +20,7 @@
 #include <array>
 #include <vector>
 
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #define HWC2_INCLUDE_STRINGIFICATION
@@ -229,20 +230,21 @@
 };
 
 
-class Hwc2TestDataspace : public Hwc2TestProperty<android_dataspace_t> {
+class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
 public:
     Hwc2TestDataspace(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
 protected:
-    static const std::vector<android_dataspace_t> defaultDataspaces;
-    static const std::vector<android_dataspace_t> basicDataspaces;
-    static const std::vector<android_dataspace_t> completeDataspaces;
+    static const std::vector<android::ui::Dataspace> defaultDataspaces;
+    static const std::vector<android::ui::Dataspace> basicDataspaces;
+    static const std::vector<android::ui::Dataspace> completeDataspaces;
 
     static const std::array<bool, 6> mCompositionSupport;
 };
 
+class Hwc2TestVirtualBuffer;
 
 class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
 public:
@@ -250,12 +252,12 @@
 
     std::string dump() const;
 
-    void setDependent(Hwc2TestBuffer* buffer);
+    void setDependent(Hwc2TestVirtualBuffer* buffer);
 
 private:
     void updateDependents();
 
-    Hwc2TestBuffer* mBuffer;
+    std::set<Hwc2TestVirtualBuffer*> mBuffers;
 
     static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
     static const std::vector<UnsignedArea> mBasicDisplayDimensions;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
index d0fbc0b..e6cceb8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
@@ -15,14 +15,18 @@
  */
 
 #include <sstream>
+#include <sys/stat.h>
 
 #include "Hwc2TestVirtualDisplay.h"
 
+#define DIR_NAME "images"
+
 Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
         Hwc2TestCoverage coverage)
     : mDisplayDimension(coverage)
 {
-    mDisplayDimension.setDependent(&mBuffer);
+    mDisplayDimension.setDependent(&mOutputBuffer);
+    mDisplayDimension.setDependent(&mExpectedBuffer);
 }
 
 std::string Hwc2TestVirtualDisplay::dump() const
@@ -36,11 +40,11 @@
     return dmp.str();
 }
 
-int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle,
+int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle,
         android::base::unique_fd* outAcquireFence)
 {
     int32_t acquireFence;
-    int ret = mBuffer.get(outHandle, &acquireFence);
+    int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence);
     outAcquireFence->reset(acquireFence);
     return ret;
 }
@@ -59,3 +63,36 @@
 {
     return mDisplayDimension.get();
 }
+
+int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+        const std::vector<hwc2_layer_t>* allLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers,
+            clearLayers);
+    if (ret)
+        return ret;
+
+    ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(),
+        mExpectedBuffer.graphicBuffer());
+
+    return 0;
+}
+
+int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name)
+{
+    std::ostringstream expectedPath;
+    std::ostringstream resultPath;
+    int ret = mkdir(DIR_NAME, DEFFILEMODE);
+    if (ret && errno != EEXIST)
+        return ret;
+
+    expectedPath << DIR_NAME << "/expected-" << name << ".png";
+    resultPath << DIR_NAME << "/result-" << name << ".png";
+
+    if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) ||
+            !mOutputBuffer.writeBufferToFile(resultPath.str()))
+        return -1;
+
+    return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
index 09420ef..10c8ef0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -18,6 +18,7 @@
 #define _HWC2_TEST_VIRTUAL_DISPLAY_H
 
 #include "Hwc2TestBuffer.h"
+#include "Hwc2TestPixelComparator.h"
 #include "Hwc2TestProperties.h"
 
 #define HWC2_INCLUDE_STRINGIFICATION
@@ -32,17 +33,22 @@
 
     std::string dump() const;
 
-    int getBuffer(buffer_handle_t* outHandle,
+    int getOutputBuffer(buffer_handle_t* outHandle,
             android::base::unique_fd* outAcquireFence);
 
+    int verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+            const std::vector<hwc2_layer_t>* allLayers,
+            const std::set<hwc2_layer_t>* clearLayers);
+
+    int writeBuffersToFile(std::string name);
     void reset();
     bool advance();
 
     UnsignedArea getDisplayDimension() const;
 
 private:
-    Hwc2TestBuffer mBuffer;
-
+    Hwc2TestOutputBuffer mOutputBuffer;
+    Hwc2TestExpectedBuffer mExpectedBuffer;
     Hwc2TestDisplayDimension mDisplayDimension;
 };
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
new file mode 100644
index 0000000..4a92780
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+cc_test {
+    name: "libsurfaceflinger_unittest",
+    tags: ["test"],
+    defaults: ["libsurfaceflinger_defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        ":libsurfaceflinger_sources",
+        "DisplayTransactionTest.cpp",
+        "EventControlThreadTest.cpp",
+        "EventThreadTest.cpp",
+        "mock/DisplayHardware/MockComposer.cpp",
+        "mock/DisplayHardware/MockDisplaySurface.cpp",
+        "mock/DisplayHardware/MockPowerAdvisor.cpp",
+        "mock/gui/MockGraphicBufferConsumer.cpp",
+        "mock/gui/MockGraphicBufferProducer.cpp",
+        "mock/MockEventControlThread.cpp",
+        "mock/MockEventThread.cpp",
+        "mock/MockMessageQueue.cpp",
+        "mock/MockNativeWindowSurface.cpp",
+        "mock/MockSurfaceInterceptor.cpp",
+        "mock/RenderEngine/MockRenderEngine.cpp",
+        "mock/system/window/MockNativeWindow.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    header_libs: [
+        "libsurfaceflinger_headers",
+    ],
+}
diff --git a/services/surfaceflinger/tests/unittests/AndroidTest.xml b/services/surfaceflinger/tests/unittests/AndroidTest.xml
new file mode 100644
index 0000000..5e8b03b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for libsurfaceflinger_unittest">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libsurfaceflinger_unittest->/data/local/tmp/libsurfaceflinger_unittest" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libsurfaceflinger_unittest" />
+    </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
new file mode 100644
index 0000000..2245ee1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <deque>
+#include <mutex>
+#include <optional>
+#include <thread>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include <android-base/thread_annotations.h>
+
+namespace android {
+
+// This class helps record calls made by another thread when they are made
+// asynchronously, with no other way for the tests to verify that the calls have
+// been made.
+//
+// A normal Google Mock recorder, while thread safe, does not allow you to wait
+// for asynchronous calls to be made.
+//
+// Usage:
+//
+// In the test, use a Google Mock expectation to invoke an instance of the
+// recorder:
+//
+//     AsyncCallRecorder<void(int)> recorder;
+//
+//     EXPECT_CALL(someMock, someFunction(_)).
+//             .WillRepeatedly(Invoke(recorder.getInvocable()));
+//
+// Then you can invoke the functionality being tested:
+//
+//     threadUnderTest.doSomethingAsync()
+//
+// And afterwards make a number of assertions using the recorder:
+//
+//     // Wait for one call (with reasonable default timeout), and get the args
+//     // as a std::tuple inside a std::optional.
+//     auto args = recorder.waitForCall();
+//     // The returned std::optional will have a value if the recorder function
+//     // was called.
+//     ASSERT_TRUE(args.has_value());
+//     // The arguments can be checked if needed using standard tuple
+//     // operations.
+//     EXPECT_EQ(123, std::get<0>(args.value()));
+//
+// Alternatively maybe you want to assert that a call was not made.
+//
+//     EXPECT_FALSE(recorder.waitForUnexpectedCall().has_value());
+//
+// However this check uses a really short timeout so as not to block the test
+// unnecessarily. And it could be possible for the check to return false and
+// then the recorder could observe a call being made after.
+template <typename Func>
+class AsyncCallRecorder;
+
+template <typename... Args>
+class AsyncCallRecorder<void (*)(Args...)> {
+public:
+    // For the tests, we expect the wait for an expected change to be signaled
+    // to be much shorter than this.
+    static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{10};
+
+    // The wait here is tricky. We don't expect a change, but we don't want to
+    // wait forever (or for longer than the typical test function runtime). As
+    // even the simplest Google Test can take 1ms (1000us) to run, we wait for
+    // half that time.
+    static constexpr std::chrono::microseconds UNEXPECTED_CALL_TIMEOUT{500};
+
+    using ArgTuple = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
+
+    void recordCall(Args... args) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mCalls.emplace_back(std::make_tuple(args...));
+        mCondition.notify_all();
+    }
+
+    // Returns a functor which can be used with the Google Mock Invoke()
+    // function, or as a std::function to record calls.
+    auto getInvocable() {
+        return [this](Args... args) { recordCall(args...); };
+    }
+
+    // Returns a set of arguments as a std::optional<std::tuple<...>> for the
+    // oldest call, waiting for the given timeout if necessary if there are no
+    // arguments in the FIFO.
+    std::optional<ArgTuple> waitForCall(
+            std::chrono::microseconds timeout = DEFAULT_CALL_EXPECTED_TIMEOUT)
+            NO_THREAD_SAFETY_ANALYSIS {
+        std::unique_lock<std::mutex> lock(mMutex);
+
+        // Wait if necessary for us to have a record from a call.
+        mCondition.wait_for(lock, timeout,
+                            [this]() NO_THREAD_SAFETY_ANALYSIS { return !mCalls.empty(); });
+
+        // Return the arguments from the oldest call, if one was made
+        bool called = !mCalls.empty();
+        std::optional<ArgTuple> result;
+        if (called) {
+            result.emplace(std::move(mCalls.front()));
+            mCalls.pop_front();
+        }
+        return result;
+    }
+
+    // Waits using a small default timeout for when a call is not expected to be
+    // made. The returned std::optional<std:tuple<...>> should not have a value
+    // except if a set of arguments was unexpectedly received because a call was
+    // actually made.
+    //
+    // Note this function uses a small timeout to not block test execution, and
+    // it is possible the code under test could make the call AFTER the timeout
+    // expires.
+    std::optional<ArgTuple> waitForUnexpectedCall() { return waitForCall(UNEXPECTED_CALL_TIMEOUT); }
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    std::deque<ArgTuple> mCalls GUARDED_BY(mMutex);
+};
+
+// Like AsyncCallRecorder, but for when the function being invoked
+// asynchronously is expected to return a value.
+//
+// This helper allows a single constant return value to be set to be returned by
+// all calls that were made.
+template <typename Func>
+class AsyncCallRecorderWithCannedReturn;
+
+template <typename Ret, typename... Args>
+class AsyncCallRecorderWithCannedReturn<Ret (*)(Args...)>
+      : public AsyncCallRecorder<void (*)(Args...)> {
+public:
+    explicit AsyncCallRecorderWithCannedReturn(Ret returnvalue) : mReturnValue(returnvalue) {}
+
+    auto getInvocable() {
+        return [this](Args... args) {
+            this->recordCall(args...);
+            return mReturnValue;
+        };
+    }
+
+private:
+    const Ret mReturnValue;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
new file mode 100644
index 0000000..9b308bf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -0,0 +1,2798 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/MockNativeWindowSurface.h"
+#include "mock/MockSurfaceInterceptor.h"
+#include "mock/RenderEngine/MockRenderEngine.h"
+#include "mock/gui/MockGraphicBufferConsumer.h"
+#include "mock/gui/MockGraphicBufferProducer.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+namespace android {
+namespace {
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::ColorMode;
+using android::Hwc2::Error;
+using android::Hwc2::Hdr;
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+using android::Hwc2::PerFrameMetadataKey;
+using android::Hwc2::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
+using HWC2Display = TestableSurfaceFlinger::HWC2Display;
+
+constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+constexpr int32_t DEFAULT_DPI = 320;
+constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
+
+constexpr int HWC_POWER_MODE_LEET = 1337; // An out of range power mode value
+
+/* ------------------------------------------------------------------------
+ * Boolean avoidance
+ *
+ * To make calls and template instantiations more readable, we define some
+ * local enums along with an implicit bool conversion.
+ */
+
+#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
+
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Secure);
+
+/* ------------------------------------------------------------------------
+ *
+ */
+
+class DisplayTransactionTest : public testing::Test {
+public:
+    DisplayTransactionTest();
+    ~DisplayTransactionTest() override;
+
+    // --------------------------------------------------------------------
+    // Mock/Fake injection
+
+    void injectMockComposer(int virtualDisplayCount);
+    void injectFakeBufferQueueFactory();
+    void injectFakeNativeWindowSurfaceFactory();
+
+    // --------------------------------------------------------------------
+    // Postcondition helpers
+
+    bool hasHwcDisplay(hwc2_display_t displayId);
+    bool hasTransactionFlagSet(int flag);
+    bool hasDisplayDevice(sp<IBinder> displayToken);
+    sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
+    bool hasCurrentDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
+    bool hasDrawingDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+
+    // --------------------------------------------------------------------
+    // Test instances
+
+    TestableSurfaceFlinger mFlinger;
+    mock::EventThread* mEventThread = new mock::EventThread();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    // These mocks are created by the test, but are destroyed by SurfaceFlinger
+    // by virtue of being stored into a std::unique_ptr. However we still need
+    // to keep a reference to them for use in setting up call expectations.
+    RE::mock::RenderEngine* mRenderEngine = new RE::mock::RenderEngine();
+    Hwc2::mock::Composer* mComposer = nullptr;
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+
+    // These mocks are created only when expected to be created via a factory.
+    sp<mock::GraphicBufferConsumer> mConsumer;
+    sp<mock::GraphicBufferProducer> mProducer;
+    mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
+    sp<mock::NativeWindow> mNativeWindow;
+    RE::mock::Surface* mRenderSurface = nullptr;
+};
+
+DisplayTransactionTest::DisplayTransactionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    // Default to no wide color display support configured
+    mFlinger.mutableHasWideColorDisplay() = false;
+    mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+
+    // Default to using HWC virtual displays
+    mFlinger.mutableUseHwcVirtualDisplays() = true;
+
+    mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) {
+        ADD_FAILURE() << "Unexpected request to create a buffer queue.";
+    });
+
+    mFlinger.setCreateNativeWindowSurface([](auto) {
+        ADD_FAILURE() << "Unexpected request to create a native window surface.";
+        return nullptr;
+    });
+
+    mFlinger.mutableEventControlThread().reset(mEventControlThread);
+    mFlinger.mutableEventThread().reset(mEventThread);
+    mFlinger.mutableEventQueue().reset(mMessageQueue);
+    mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
+    mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+
+    injectMockComposer(0);
+}
+
+DisplayTransactionTest::~DisplayTransactionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
+    mComposer = new Hwc2::mock::Composer();
+    EXPECT_CALL(*mComposer, getCapabilities())
+            .WillOnce(Return(std::vector<IComposer::Capability>()));
+    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+    Mock::VerifyAndClear(mComposer);
+}
+
+void DisplayTransactionTest::injectFakeBufferQueueFactory() {
+    // This setup is only expected once per test.
+    ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr);
+
+    mConsumer = new mock::GraphicBufferConsumer();
+    mProducer = new mock::GraphicBufferProducer();
+
+    mFlinger.setCreateBufferQueueFunction([this](auto outProducer, auto outConsumer, bool) {
+        *outProducer = mProducer;
+        *outConsumer = mConsumer;
+    });
+}
+
+void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() {
+    // This setup is only expected once per test.
+    ASSERT_TRUE(mNativeWindowSurface == nullptr);
+
+    mNativeWindowSurface = new mock::NativeWindowSurface();
+    mNativeWindow = new mock::NativeWindow();
+
+    mFlinger.setCreateNativeWindowSurface(
+            [this](auto) { return std::unique_ptr<NativeWindowSurface>(mNativeWindowSurface); });
+}
+
+bool DisplayTransactionTest::hasHwcDisplay(hwc2_display_t displayId) {
+    return mFlinger.mutableHwcDisplaySlots().count(displayId) == 1;
+}
+
+bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
+    return mFlinger.mutableTransactionFlags() & flag;
+}
+
+bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
+    return mFlinger.mutableDisplays().indexOfKey(displayToken) >= 0;
+}
+
+sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
+    return mFlinger.mutableDisplays().valueFor(displayToken);
+}
+
+bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableCurrentState().displays.indexOfKey(displayToken) >= 0;
+}
+
+const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableCurrentState().displays.valueFor(displayToken);
+}
+
+bool DisplayTransactionTest::hasDrawingDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableDrawingState().displays.indexOfKey(displayToken) >= 0;
+}
+
+const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
+}
+
+/* ------------------------------------------------------------------------
+ *
+ */
+
+template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType hwcId, int width, int height,
+          Critical critical, Async async, Secure secure, int grallocUsage>
+struct DisplayVariant {
+    // The display width and height
+    static constexpr int WIDTH = width;
+    static constexpr int HEIGHT = height;
+
+    static constexpr int GRALLOC_USAGE = grallocUsage;
+
+    // The type for this display
+    static constexpr DisplayDevice::DisplayType TYPE = type;
+    static constexpr DisplayDevice::DisplayType HWCOMPOSER_ID = hwcId;
+
+    // When creating native window surfaces for the framebuffer, whether those should be critical
+    static constexpr Critical CRITICAL = critical;
+
+    // When creating native window surfaces for the framebuffer, whether those should be async
+    static constexpr Async ASYNC = async;
+
+    // Whether the display should be treated as secure
+    static constexpr Secure SECURE = secure;
+
+    static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
+        auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, HWCOMPOSER_ID);
+        injector.setSecure(static_cast<bool>(SECURE));
+        return injector;
+    }
+
+    // Called by tests to set up any native window creation call expectations.
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
+                .WillOnce(Return(test->mNativeWindow));
+        EXPECT_CALL(*test->mNativeWindow, perform(19)).WillRepeatedly(Return(NO_ERROR));
+
+        // For simplicity, we only expect to create a single render surface for
+        // each test.
+        ASSERT_TRUE(test->mRenderSurface == nullptr);
+        test->mRenderSurface = new RE::mock::Surface();
+        EXPECT_CALL(*test->mRenderEngine, createSurface())
+                .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(test->mRenderSurface))));
+        EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
+        EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
+        EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
+        EXPECT_CALL(*test->mRenderSurface, queryWidth()).WillOnce(Return(WIDTH));
+        EXPECT_CALL(*test->mRenderSurface, queryHeight()).WillOnce(Return(HEIGHT));
+    }
+
+    static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
+                .WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
+                .WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
+                .WillRepeatedly(Return(NO_ERROR));
+    }
+
+    static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
+    }
+};
+
+template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant>
+struct HwcDisplayVariant {
+    // The display id supplied by the HWC
+    static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
+
+    // The HWC display type
+    static constexpr HWC2::DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
+
+    // The HWC active configuration id
+    static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+
+    static void injectPendingHotplugEvent(DisplayTransactionTest* test,
+                                          HWC2::Connection connection) {
+        test->mFlinger.mutablePendingHotplugEvents().emplace_back(
+                HotplugEvent{HWC_DISPLAY_ID, connection});
+    }
+
+    // Called by tests to inject a HWC display setup
+    static void injectHwcDisplay(DisplayTransactionTest* test) {
+        FakeHwcDisplayInjector(DisplayVariant::TYPE, HWC_DISPLAY_TYPE)
+                .setHwcDisplayId(HWC_DISPLAY_ID)
+                .setWidth(DisplayVariant::WIDTH)
+                .setHeight(DisplayVariant::HEIGHT)
+                .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
+                .inject(&test->mFlinger, test->mComposer);
+    }
+
+    static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
+                                        HWC_DISPLAY_TYPE)),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+        EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::WIDTH, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::HEIGHT, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::VSYNC_PERIOD, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::DPI_X, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::DPI_Y, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+    }
+
+    // Called by tests to set up HWC call expectations
+    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
+    }
+};
+
+struct NonHwcDisplayVariant {
+    static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+    }
+};
+
+// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
+constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
+        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
+
+template <hwc2_display_t hwcDisplayId, DisplayDevice::DisplayType type, int width, int height,
+          Critical critical>
+struct PhysicalDisplayVariant
+      : public DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE,
+                              GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+        public HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+                                 DisplayVariant<type, type, width, height, critical, Async::FALSE,
+                                                Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
+
+// An invalid display
+using InvalidDisplayVariant =
+        DisplayVariant<DisplayDevice::DISPLAY_ID_INVALID, DisplayDevice::DISPLAY_ID_INVALID, 0, 0,
+                       Critical::FALSE, Async::FALSE, Secure::FALSE, 0>;
+
+// A primary display is a physical display that is critical
+using PrimaryDisplayVariant =
+        PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
+
+// An external display is physical display that is not critical.
+using ExternalDisplayVariant =
+        PhysicalDisplayVariant<1002, DisplayDevice::DISPLAY_EXTERNAL, 1920, 1280, Critical::FALSE>;
+
+using TertiaryDisplayVariant =
+        PhysicalDisplayVariant<1003, DisplayDevice::DISPLAY_EXTERNAL, 1600, 1200, Critical::FALSE>;
+
+// A virtual display not supported by the HWC.
+constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
+
+template <int width, int height, Secure secure>
+struct NonHwcVirtualDisplayVariant
+      : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
+                              width, height, Critical::FALSE, Async::TRUE, secure,
+                              GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>,
+        public NonHwcDisplayVariant {
+    using Base = DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
+                                width, height, Critical::FALSE, Async::TRUE, secure,
+                                GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+    }
+};
+
+// A virtual display supported by the HWC.
+constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
+
+template <int width, int height, Secure secure>
+struct HwcVirtualDisplayVariant
+      : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
+                              height, Critical::FALSE, Async::TRUE, secure,
+                              GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+        public HwcDisplayVariant<1010, HWC2::DisplayType::Virtual,
+                                 NonHwcVirtualDisplayVariant<width, height, secure>> {
+    using Base =
+            DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
+                           height, Critical::FALSE, Async::TRUE, secure, GRALLOC_USAGE_HW_COMPOSER>;
+    using Self = HwcVirtualDisplayVariant<width, height, secure>;
+
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+    }
+
+    static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
+                .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+    }
+};
+
+// For this variant, SurfaceFlinger should not configure itself with wide
+// display support, so the display should not be configured for wide-color
+// support.
+struct WideColorSupportNotConfiguredVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableHasWideColorDisplay() = false;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+    }
+};
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, and the display should respond with an non-empty list of supported
+// color modes. Wide-color support should be configured.
+template <typename Display>
+struct WideColorP3ColorimetricSupportedVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = true;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableHasWideColorDisplay() = true;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
+                .WillOnce(DoAll(SetArgPointee<2>(
+                                        std::vector<RenderIntent>({RenderIntent::COLORIMETRIC})),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB,
+                                 RenderIntent::COLORIMETRIC))
+                .WillOnce(Return(Error::NONE));
+    }
+};
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, but the display should respond with an empty list of supported color
+// modes. Wide-color support for the display should not be configured.
+template <typename Display>
+struct WideColorNotSupportedVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableHasWideColorDisplay() = true;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+    }
+};
+
+// For this variant, the display is not a HWC display, so no HDR support should
+// be configured.
+struct NonHwcDisplayHdrSupportVariant {
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HDR10, so HDR10 support should be configured.
+template <typename Display>
+struct Hdr10SupportedVariant {
+    static constexpr bool HDR10_SUPPORTED = true;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HDR10})),
+                                Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HLG, so HLG support should be configured.
+template <typename Display>
+struct HdrHlgSupportedVariant {
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = true;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(
+                        DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HLG})), Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing DOLBY_VISION, so DOLBY_VISION support should be configured.
+template <typename Display>
+struct HdrDolbyVisionSupportedVariant {
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = true;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::DOLBY_VISION})),
+                                Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with am empty list of HDR
+// modes, so no HDR support should be configured.
+template <typename Display>
+struct HdrNotSupportedVariant {
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
+    }
+};
+
+struct NonHwcPerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = 0;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_, _)).Times(0);
+    }
+};
+
+template <typename Display>
+struct NoPerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = 0;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>()),
+                                Return(Error::NONE)));
+    }
+};
+
+template <typename Display>
+struct Smpte2086PerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+                                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
+                                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
+                                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
+                                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
+                                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
+                                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
+                                        PerFrameMetadataKey::WHITE_POINT_X,
+                                        PerFrameMetadataKey::WHITE_POINT_Y,
+                                        PerFrameMetadataKey::MAX_LUMINANCE,
+                                        PerFrameMetadataKey::MIN_LUMINANCE,
+                                })),
+                                Return(Error::NONE)));
+    }
+};
+
+template <typename Display>
+struct Cta861_3_PerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+                                        PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
+                                        PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+                                })),
+                                Return(Error::NONE)));
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Typical display configurations to test
+ */
+
+template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
+          typename PerFrameMetadataSupportPolicy>
+struct Case {
+    using Display = DisplayPolicy;
+    using WideColorSupport = WideColorSupportPolicy;
+    using HdrSupport = HdrSupportPolicy;
+    using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
+};
+
+using SimplePrimaryDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using SimpleExternalDisplayCase =
+        Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
+             HdrNotSupportedVariant<ExternalDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
+using SimpleTertiaryDisplayCase =
+        Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
+             HdrNotSupportedVariant<TertiaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
+using NonHwcVirtualDisplayCase =
+        Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
+             WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
+             NonHwcPerFrameMetadataSupportVariant>;
+using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
+using HwcVirtualDisplayCase =
+        Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
+             HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
+using WideColorP3ColorimetricDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using Hdr10DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             Hdr10SupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrHlgDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrHlgSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrDolbyVisionDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrSmpte2086DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             Smpte2086PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrCta861_3_DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using InvalidDisplayCase = Case<InvalidDisplayVariant, WideColorSupportNotConfiguredVariant,
+                                NonHwcDisplayHdrSupportVariant,
+                                NoPerFrameMetadataSupportVariant<InvalidDisplayVariant>>;
+/* ------------------------------------------------------------------------
+ *
+ * SurfaceFlinger::onHotplugReceived
+ */
+
+TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
+    constexpr int currentSequenceId = 123;
+    constexpr hwc2_display_t displayId1 = 456;
+    constexpr hwc2_display_t displayId2 = 654;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does not appear to be
+    // the main thread.
+    mFlinger.mutableMainThreadId() = std::thread::id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // Simulate two hotplug events (a connect and a disconnect)
+    mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Connected);
+    mFlinger.onHotplugReceived(currentSequenceId, displayId2, HWC2::Connection::Disconnected);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // All events should be in the pending event queue.
+    const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
+    ASSERT_EQ(2u, pendingEvents.size());
+    EXPECT_EQ(displayId1, pendingEvents[0].display);
+    EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
+    EXPECT_EQ(displayId2, pendingEvents[1].display);
+    EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
+}
+
+TEST_F(DisplayTransactionTest, hotplugDiscardsUnexpectedEvents) {
+    constexpr int currentSequenceId = 123;
+    constexpr int otherSequenceId = 321;
+    constexpr hwc2_display_t displayId = 456;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does not appear to be
+    // the main thread.
+    mFlinger.mutableMainThreadId() = std::thread::id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We do not expect any calls to invalidate().
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(0);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // Call with an unexpected sequence id
+    mFlinger.onHotplugReceived(otherSequenceId, displayId, HWC2::Connection::Invalid);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should not be set
+    EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // There should be no pending events
+    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+TEST_F(DisplayTransactionTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
+    constexpr int currentSequenceId = 123;
+    constexpr hwc2_display_t displayId1 = 456;
+
+    // --------------------------------------------------------------------
+    // Note:
+    // --------------------------------------------------------------------
+    // This test case is a bit tricky. We want to verify that
+    // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we
+    // don't really want to provide coverage for everything the later function
+    // does as there are specific tests for it.
+    // --------------------------------------------------------------------
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does appear to be the
+    // main thread.
+    mFlinger.mutableMainThreadId() = std::this_thread::get_id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // Simulate a disconnect on a display id that is not connected. This should
+    // be enqueued by onHotplugReceived(), and dequeued by
+    // processDisplayHotplugEventsLocked(), but then ignored as invalid.
+    mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Disconnected);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // There should be no event queued on return, as it should have been
+    // processed.
+    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::createDisplay
+ */
+
+TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
+    const String8 name("virtual.test");
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    sp<IBinder> displayToken = mFlinger.createDisplay(name, false);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been added to the current state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& display = getCurrentDisplayState(displayToken);
+    EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
+    EXPECT_EQ(false, display.isSecure);
+    EXPECT_EQ(name.string(), display.displayName);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForSecureDisplay) {
+    const String8 name("virtual.test");
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been added to the current state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& display = getCurrentDisplayState(displayToken);
+    EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
+    EXPECT_EQ(true, display.isSecure);
+    EXPECT_EQ(name.string(), display.displayName);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::destroyDisplay
+ */
+
+TEST_F(DisplayTransactionTest, destroyDisplayClearsCurrentStateForDisplay) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A virtual display exists
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.destroyDisplay(existing.token());
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been removed from the current state
+    EXPECT_FALSE(hasCurrentDisplayState(existing.token()));
+
+    // Ths display should still exist in the drawing state
+    EXPECT_TRUE(hasDrawingDisplayState(existing.token()));
+
+    // The display transaction needed flasg should be set
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+}
+
+TEST_F(DisplayTransactionTest, destroyDisplayHandlesUnknownDisplay) {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    sp<BBinder> displayToken = new BBinder();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.destroyDisplay(displayToken);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::resetDisplayState
+ */
+
+TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // vsync is enabled and available
+    mFlinger.mutablePrimaryHWVsyncEnabled() = true;
+    mFlinger.mutableHWVsyncAvailable() = true;
+
+    // A display exists
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call disable vsyncs
+    EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1);
+
+    // The call clears the current render engine surface
+    EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.resetDisplayState();
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // vsyncs should be off and not available.
+    EXPECT_FALSE(mFlinger.mutablePrimaryHWVsyncEnabled());
+    EXPECT_FALSE(mFlinger.mutableHWVsyncAvailable());
+
+    // The display should have been removed from the display map.
+    EXPECT_FALSE(hasDisplayDevice(existing.token()));
+
+    // The display should still exist in the current state
+    EXPECT_TRUE(hasCurrentDisplayState(existing.token()));
+
+    // The display should have been removed from the drawing state
+    EXPECT_FALSE(hasDrawingDisplayState(existing.token()));
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::setupNewDisplayDeviceInternal
+ */
+
+class SetupNewDisplayDeviceInternalTest : public DisplayTransactionTest {
+public:
+    template <typename T>
+    void setupNewDisplayDeviceInternalTest();
+};
+
+template <typename Case>
+void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
+    const sp<BBinder> displayToken = new BBinder();
+    const sp<mock::DisplaySurface> displaySurface = new mock::DisplaySurface();
+    const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Wide color displays support is configured appropriately
+    Case::WideColorSupport::injectConfigChange(this);
+
+    // The display is setup with the HWC.
+    Case::Display::injectHwcDisplay(this);
+
+    // SurfaceFlinger will use a test-controlled factory for native window
+    // surfaces.
+    injectFakeNativeWindowSurfaceFactory();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // Various native window calls will be made.
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    auto state = DisplayDeviceState(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+    auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
+                                                         displaySurface, producer);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    ASSERT_TRUE(device != nullptr);
+    EXPECT_EQ(Case::Display::TYPE, device->getDisplayType());
+    EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+    EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
+    EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
+    EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
+    EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
+    EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
+    EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
+    // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
+    // remapped, and the test only ever sets up one config. If there were an error
+    // looking up the remapped index, device->getActiveConfig() would be -1 instead.
+    EXPECT_EQ(0, device->getActiveConfig());
+    EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
+              device->getSupportedPerFrameMetadata());
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
+    setupNewDisplayDeviceInternalTest<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
+    setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
+    setupNewDisplayDeviceInternalTest<NonHwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
+    // We need to resize this so that the HWC thinks the virtual display
+    // is something it created.
+    mFlinger.mutableHwcDisplayData().resize(3);
+
+    setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
+    setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) {
+    setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrHlgDisplay) {
+    setupNewDisplayDeviceInternalTest<HdrHlgDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrDolbyVisionDisplay) {
+    setupNewDisplayDeviceInternalTest<HdrDolbyVisionDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrSmpte2086DisplayCase) {
+    setupNewDisplayDeviceInternalTest<HdrSmpte2086DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrCta816_3_DisplayCase) {
+    setupNewDisplayDeviceInternalTest<HdrCta861_3_DisplayCase>();
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::handleTransactionLocked(eDisplayTransactionNeeded)
+ */
+
+class HandleTransactionLockedTest : public DisplayTransactionTest {
+public:
+    template <typename Case>
+    void setupCommonPreconditions();
+
+    template <typename Case>
+    void setupCommonCallExpectationsForConnectProcessing();
+
+    template <typename Case>
+    void setupCommonCallExpectationsForDisconnectProcessing();
+
+    template <typename Case>
+    void processesHotplugConnectCommon();
+
+    template <typename Case>
+    void ignoresHotplugConnectCommon();
+
+    template <typename Case>
+    void processesHotplugDisconnectCommon();
+
+    template <typename Case>
+    void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
+
+    template <typename Case>
+    void verifyPhysicalDisplayIsConnected();
+
+    void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
+};
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonPreconditions() {
+    // Wide color displays support is configured appropriately
+    Case::WideColorSupport::injectConfigChange(this);
+
+    // SurfaceFlinger will use a test-controlled factory for BufferQueues
+    injectFakeBufferQueueFactory();
+
+    // SurfaceFlinger will use a test-controlled factory for native window
+    // surfaces.
+    injectFakeNativeWindowSurfaceFactory();
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
+    Case::Display::setupHwcHotplugCallExpectations(this);
+
+    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+    Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, true)).Times(1);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, false)).Times(1);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
+    // The display device should have been set up in the list of displays.
+    ASSERT_TRUE(hasDisplayDevice(displayToken));
+    const auto& device = getDisplayDevice(displayToken);
+    EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+    EXPECT_EQ(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY, device->isPrimary());
+
+    // The display should have been set up in the current display state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& current = getCurrentDisplayState(displayToken);
+    EXPECT_EQ(Case::Display::TYPE, current.type);
+
+    // The display should have been set up in the drawing display state
+    ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+    const auto& draw = getDrawingDisplayState(displayToken);
+    EXPECT_EQ(Case::Display::TYPE, draw.type);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
+    // HWComposer should have an entry for the display
+    EXPECT_TRUE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // The display should be set up as a built-in display.
+    static_assert(0 <= Case::Display::TYPE &&
+                          Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
+                  "Must use a valid physical display type index for the fixed-size array");
+    auto& displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    ASSERT_TRUE(displayToken != nullptr);
+
+    verifyDisplayIsConnected<Case>(displayToken);
+}
+
+void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
+    EXPECT_FALSE(hasDisplayDevice(displayToken));
+    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+    EXPECT_FALSE(hasDrawingDisplayState(displayToken));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugConnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillOnce(Return(false));
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    verifyPhysicalDisplayIsConnected<Case>();
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug disconnect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+
+    // The display is already completely set up.
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // The display should not be set up as a built-in display.
+    ASSERT_TRUE(0 <= Case::Display::TYPE &&
+                Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
+    auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    EXPECT_TRUE(displayToken == nullptr);
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
+    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest,
+       processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
+    // Inject an external display.
+    ExternalDisplayVariant::injectHwcDisplay(this);
+
+    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
+    // Inject a primary display.
+    PrimaryDisplayVariant::injectHwcDisplay(this);
+
+    processesHotplugConnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
+    // Inject both a primary and external display.
+    PrimaryDisplayVariant::injectHwcDisplay(this);
+    ExternalDisplayVariant::injectHwcDisplay(this);
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+
+    ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfExternalForVrComposer) {
+    // Inject a primary display.
+    PrimaryDisplayVariant::injectHwcDisplay(this);
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(true));
+
+    ignoresHotplugConnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processHotplugDisconnectPrimaryDisplay) {
+    processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processHotplugDisconnectExternalDisplay) {
+    processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+    // A hotplug disconnect event is also enqueued for the same display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // The display should not be set up as a primary built-in display.
+    ASSERT_TRUE(0 <= Case::Display::TYPE &&
+                Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
+    auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    EXPECT_TRUE(displayToken == nullptr);
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // The display is already completely set up.
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // A hotplug disconnect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+    // A hotplug connect event is also enqueued for the same display
+    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+    static_assert(0 <= Case::Display::TYPE &&
+                          Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
+                  "Display type must be a built-in display");
+    EXPECT_NE(existing.token(), mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE]);
+
+    // A new display should be connected in its place
+
+    verifyPhysicalDisplayIsConnected<Case>();
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // The HWC supports at least one virtual display
+    injectMockComposer(1);
+
+    setupCommonPreconditions<Case>();
+
+    // A virtual display was added to the current state, and it has a
+    // surface(producer)
+    sp<BBinder> displayToken = new BBinder();
+    DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+    sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
+    info.surface = surface;
+    mFlinger.mutableCurrentState().displays.add(displayToken, info);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
+                                  Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
+
+    EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
+
+    EXPECT_CALL(*mProducer, connect(_, _, _, _)).Times(1);
+    EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
+
+    Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display device should have been set up in the list of displays.
+    verifyDisplayIsConnected<Case>(displayToken);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // The HWC supports at least one virtual display
+    injectMockComposer(1);
+
+    setupCommonPreconditions<Case>();
+
+    // A virtual display was added to the current state, but it does not have a
+    // surface.
+    sp<BBinder> displayToken = new BBinder();
+    DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+    mFlinger.mutableCurrentState().displays.add(displayToken, info);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // There will not be a display device set up.
+    EXPECT_FALSE(hasDisplayDevice(displayToken));
+
+    // The drawing display state will be set from the current display state.
+    ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+    const auto& draw = getDrawingDisplayState(displayToken);
+    EXPECT_EQ(Case::Display::TYPE, draw.type);
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A virtual display is set up but is removed from the current state.
+    mFlinger.mutableHwcDisplayData().resize(3);
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+    mFlinger.mutableCurrentState().displays.removeItem(existing.token());
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr uint32_t oldLayerStack = 0u;
+    constexpr uint32_t newLayerStack = 123u;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the layerStack state
+    display.mutableDrawingDisplayState().layerStack = oldLayerStack;
+    display.mutableCurrentDisplayState().layerStack = newLayerStack;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr int oldTransform = 0;
+    constexpr int newTransform = 2;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the orientation state
+    display.mutableDrawingDisplayState().orientation = oldTransform;
+    display.mutableCurrentDisplayState().orientation = newTransform;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayViewportChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    const Rect oldViewport(0, 0, 0, 0);
+    const Rect newViewport(0, 0, 123, 456);
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the viewport state
+    display.mutableDrawingDisplayState().viewport = oldViewport;
+    display.mutableCurrentDisplayState().viewport = newViewport;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newViewport, display.mutableDisplayDevice()->getViewport());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    const Rect oldFrame(0, 0, 0, 0);
+    const Rect newFrame(0, 0, 123, 456);
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the viewport state
+    display.mutableDrawingDisplayState().frame = oldFrame;
+    display.mutableCurrentDisplayState().frame = newFrame;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getFrame());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr int oldWidth = 0;
+    constexpr int oldHeight = 10;
+    constexpr int newWidth = 123;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto nativeWindow = new mock::NativeWindow();
+    auto displaySurface = new mock::DisplaySurface();
+    auto renderSurface = new RE::mock::Surface();
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.setNativeWindow(nativeWindow);
+    display.setDisplaySurface(displaySurface);
+    display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+    display.inject();
+
+    // There is a change to the viewport state
+    display.mutableDrawingDisplayState().width = oldWidth;
+    display.mutableDrawingDisplayState().height = oldHeight;
+    display.mutableCurrentDisplayState().width = newWidth;
+    display.mutableCurrentDisplayState().height = oldHeight;
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
+    EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
+    EXPECT_CALL(*renderSurface, queryWidth()).WillOnce(Return(newWidth));
+    EXPECT_CALL(*renderSurface, queryHeight()).WillOnce(Return(oldHeight));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr int oldWidth = 0;
+    constexpr int oldHeight = 10;
+    constexpr int newHeight = 123;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto nativeWindow = new mock::NativeWindow();
+    auto displaySurface = new mock::DisplaySurface();
+    auto renderSurface = new RE::mock::Surface();
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.setNativeWindow(nativeWindow);
+    display.setDisplaySurface(displaySurface);
+    display.setRenderSurface(std::unique_ptr<RE::Surface>(renderSurface));
+    display.inject();
+
+    // There is a change to the viewport state
+    display.mutableDrawingDisplayState().width = oldWidth;
+    display.mutableDrawingDisplayState().height = oldHeight;
+    display.mutableCurrentDisplayState().width = oldWidth;
+    display.mutableCurrentDisplayState().height = newHeight;
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
+    EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
+    EXPECT_CALL(*renderSurface, queryWidth()).WillOnce(Return(oldWidth));
+    EXPECT_CALL(*renderSurface, queryHeight()).WillOnce(Return(newHeight));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::setDisplayStateLocked
+ */
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // We have an unknown display token not associated with a known display
+    sp<BBinder> displayToken = new BBinder();
+
+    // The requested display state references the unknown display.
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = displayToken;
+    state.layerStack = 456;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The display token still doesn't match anything known.
+    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithInvalidDisplay) {
+    using Case = InvalidDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // An invalid display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The invalid display has some state
+    display.mutableCurrentDisplayState().layerStack = 654u;
+
+    // The requested display state tries to change the display state.
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = display.token();
+    state.layerStack = 456;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display layer stack value is unchanged.
+    EXPECT_EQ(654u, getCurrentDisplayState(display.token()).layerStack);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // No changes are made to the display
+    DisplayState state;
+    state.what = 0;
+    state.token = display.token();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a surface that can be set.
+    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+    // The current display state has the surface set
+    display.mutableCurrentDisplayState().surface = surface;
+
+    // The incoming request sets the same surface
+    DisplayState state;
+    state.what = DisplayState::eSurfaceChanged;
+    state.token = display.token();
+    state.surface = surface;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged.
+    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a surface that can be set.
+    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+    // The current display state does not have a surface
+    display.mutableCurrentDisplayState().surface = nullptr;
+
+    // The incoming request sets a surface
+    DisplayState state;
+    state.what = DisplayState::eSurfaceChanged;
+    state.token = display.token();
+    state.surface = surface;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display layer stack state is set to the new value
+    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display has a layer stack set
+    display.mutableCurrentDisplayState().layerStack = 456u;
+
+    // The incoming request sets the same layer stack
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = display.token();
+    state.layerStack = 456u;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display has a layer stack set
+    display.mutableCurrentDisplayState().layerStack = 654u;
+
+    // The incoming request sets a different layer stack
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = display.token();
+    state.layerStack = 456u;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The desired display state has been set to the new value.
+    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr int initialOrientation = 180;
+    const Rect initialFrame = {1, 2, 3, 4};
+    const Rect initialViewport = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state projection state is all set
+    display.mutableCurrentDisplayState().orientation = initialOrientation;
+    display.mutableCurrentDisplayState().frame = initialFrame;
+    display.mutableCurrentDisplayState().viewport = initialViewport;
+
+    // The incoming request sets the same projection state
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.orientation = initialOrientation;
+    state.frame = initialFrame;
+    state.viewport = initialViewport;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
+
+    EXPECT_EQ(initialFrame, display.getCurrentDisplayState().frame);
+    EXPECT_EQ(initialViewport, display.getCurrentDisplayState().viewport);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr int initialOrientation = 90;
+    constexpr int desiredOrientation = 180;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state has an orientation set
+    display.mutableCurrentDisplayState().orientation = initialOrientation;
+
+    // The incoming request sets a different orientation
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.orientation = desiredOrientation;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    const Rect initialFrame = {0, 0, 0, 0};
+    const Rect desiredFrame = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state does not have a frame
+    display.mutableCurrentDisplayState().frame = initialFrame;
+
+    // The incoming request sets a frame
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.frame = desiredFrame;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredFrame, display.getCurrentDisplayState().frame);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfViewportChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    const Rect initialViewport = {0, 0, 0, 0};
+    const Rect desiredViewport = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state does not have a viewport
+    display.mutableCurrentDisplayState().viewport = initialViewport;
+
+    // The incoming request sets a viewport
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.viewport = desiredViewport;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredViewport, display.getCurrentDisplayState().viewport);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialWidth = 1024;
+    constexpr uint32_t initialHeight = 768;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state has a size set
+    display.mutableCurrentDisplayState().width = initialWidth;
+    display.mutableCurrentDisplayState().height = initialHeight;
+
+    // The incoming request sets the same display size
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.width = initialWidth;
+    state.height = initialHeight;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width);
+    EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialWidth = 0;
+    constexpr uint32_t desiredWidth = 1024;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display does not yet have a width
+    display.mutableCurrentDisplayState().width = initialWidth;
+
+    // The incoming request sets a display width
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.width = desiredWidth;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width);
+}
+
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialHeight = 0;
+    constexpr uint32_t desiredHeight = 768;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display does not yet have a height
+    display.mutableCurrentDisplayState().height = initialHeight;
+
+    // The incoming request sets a display height
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.height = desiredHeight;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::onInitializeDisplays
+ */
+
+TEST_F(DisplayTransactionTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A primary display is set up
+    Case::Display::injectHwcDisplay(this);
+    auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this);
+    primaryDisplay.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect the surface interceptor to possibly be used, but we treat it as
+    // disabled since it is called as a side effect rather than directly by this
+    // function.
+    EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
+
+    // We expect a call to get the active display config.
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onInitializeDisplays();
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The primary display should have a current state
+    ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
+    const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
+    // The layer stack state should be set to zero
+    EXPECT_EQ(0u, primaryDisplayState.layerStack);
+    // The orientation state should be set to zero
+    EXPECT_EQ(0, primaryDisplayState.orientation);
+
+    // The frame state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
+
+    // The viewport state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.viewport);
+
+    // The width and height should both be zero
+    EXPECT_EQ(0u, primaryDisplayState.width);
+    EXPECT_EQ(0u, primaryDisplayState.height);
+
+    // The display should be set to HWC_POWER_MODE_NORMAL
+    ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
+    auto displayDevice = primaryDisplay.mutableDisplayDevice();
+    EXPECT_EQ(HWC_POWER_MODE_NORMAL, displayDevice->getPowerMode());
+
+    // The display refresh period should be set in the frame tracker.
+    FrameStats stats;
+    mFlinger.getAnimFrameTracker().getStats(&stats);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // The compositor timing should be set to default values
+    const auto& compositorTiming = mFlinger.getCompositorTiming();
+    EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::setPowerModeInternal
+ */
+
+// Used when we simulate a display that supports doze.
+struct DozeIsSupportedVariant {
+    static constexpr bool DOZE_SUPPORTED = true;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+            IComposerClient::PowerMode::DOZE;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+            IComposerClient::PowerMode::DOZE_SUSPEND;
+};
+
+// Used when we simulate a display that does not support doze.
+struct DozeNotSupportedVariant {
+    static constexpr bool DOZE_SUPPORTED = false;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+            IComposerClient::PowerMode::ON;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+            IComposerClient::PowerMode::ON;
+};
+
+struct EventThreadBaseSupportedVariant {
+    static void setupEventAndEventControlThreadNoCallExpectations(DisplayTransactionTest* test) {
+        // The event control thread should not be notified.
+        EXPECT_CALL(*test->mEventControlThread, setVsyncEnabled(_)).Times(0);
+
+        // The event thread should not be notified.
+        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
+        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
+    }
+};
+
+struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
+    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // These calls are only expected for the primary display.
+
+        // Instead expect no calls.
+        setupEventAndEventControlThreadNoCallExpectations(test);
+    }
+
+    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // These calls are only expected for the primary display.
+
+        // Instead expect no calls.
+        setupEventAndEventControlThreadNoCallExpectations(test);
+    }
+};
+
+struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
+    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // The event control thread should be notified to enable vsyncs
+        EXPECT_CALL(*test->mEventControlThread, setVsyncEnabled(true)).Times(1);
+
+        // The event thread should be notified that the screen was acquired.
+        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
+    }
+
+    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // There should be a call to setVsyncEnabled(false)
+        EXPECT_CALL(*test->mEventControlThread, setVsyncEnabled(false)).Times(1);
+
+        // The event thread should not be notified that the screen was released.
+        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
+    }
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// There are a large number of transitions we could test, however we only test a
+// selected subset which provides complete test coverage of the implementation.
+// --------------------------------------------------------------------
+
+template <int initialPowerMode, int targetPowerMode>
+struct TransitionVariantCommon {
+    static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
+    static constexpr auto TARGET_POWER_MODE = targetPowerMode;
+
+    static void verifyPostconditions(DisplayTransactionTest*) {}
+};
+
+struct TransitionOffToOnVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_NORMAL> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::setupRepaintEverythingCallExpectations(test);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+    }
+};
+
+struct TransitionOffToDozeSuspendVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_DOZE_SUSPEND> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
+        Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
+        Case::setupRepaintEverythingCallExpectations(test);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+    }
+};
+
+struct TransitionOnToOffVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_OFF> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+    }
+};
+
+struct TransitionDozeSuspendToOffVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_OFF> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+    }
+};
+
+struct TransitionOnToDozeVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+    }
+};
+
+struct TransitionDozeSuspendToDozeVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_DOZE> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+    }
+};
+
+struct TransitionDozeToOnVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE, HWC_POWER_MODE_NORMAL> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+    }
+};
+
+struct TransitionDozeSuspendToOnVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_NORMAL> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+    }
+};
+
+struct TransitionOnToDozeSuspendVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE_SUSPEND> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
+    }
+};
+
+struct TransitionOnToUnknownVariant
+      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_LEET> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
+        Case::setupNoComposerPowerModeCallExpectations(test);
+    }
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// Rather than testing the cartesian product of of
+// DozeIsSupported/DozeNotSupported with all other options, we use one for one
+// display type, and the other for another display type.
+// --------------------------------------------------------------------
+
+template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
+          typename TransitionVariant>
+struct DisplayPowerCase {
+    using Display = DisplayVariant;
+    using Doze = DozeVariant;
+    using EventThread = EventThreadVariant;
+    using Transition = TransitionVariant;
+
+    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
+        Display::injectHwcDisplay(test);
+        auto display = Display::makeFakeExistingDisplayInjector(test);
+        display.inject();
+        display.mutableDisplayDevice()->setPowerMode(mode);
+        return display;
+    }
+
+    static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
+        test->mFlinger.mutablePrimaryHWVsyncEnabled() = enabled;
+    }
+
+    static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+    }
+
+    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, int mode) {
+        EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
+        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, mode)).Times(1);
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test,
+                                              IComposerClient::PowerMode mode) {
+        // Any calls to get the active config will return a default value.
+        EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
+                                      Return(Error::NONE)));
+
+        // Any calls to get whether the display supports dozing will return the value set by the
+        // policy variant.
+        EXPECT_CALL(*test->mComposer, getDozeSupport(Display::HWC_DISPLAY_ID, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(Doze::DOZE_SUPPORTED), Return(Error::NONE)));
+
+        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, mode)).Times(1);
+    }
+
+    static void setupNoComposerPowerModeCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, _)).Times(0);
+    }
+};
+
+// A sample configuration for the primary display.
+// In addition to having event thread support, we emulate doze support.
+template <typename TransitionVariant>
+using PrimaryDisplayPowerCase = DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant,
+                                                 EventThreadIsSupportedVariant, TransitionVariant>;
+
+// A sample configuration for the external display.
+// In addition to not having event thread support, we emulate not having doze
+// support.
+template <typename TransitionVariant>
+using ExternalDisplayPowerCase =
+        DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
+                         EventThreadNotSupportedVariant, TransitionVariant>;
+
+class SetPowerModeInternalTest : public DisplayTransactionTest {
+public:
+    template <typename Case>
+    void transitionDisplayCommon();
+};
+
+template <int PowerMode>
+struct PowerModeInitialVSyncEnabled : public std::false_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_NORMAL> : public std::true_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_DOZE> : public std::true_type {};
+
+template <typename Case>
+void SetPowerModeInternalTest::transitionDisplayCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    auto display =
+            Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
+    Case::setInitialPrimaryHWVsyncEnabled(this,
+                                          PowerModeInitialVSyncEnabled<
+                                                  Case::Transition::INITIAL_POWER_MODE>::value);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
+    Case::Transition::template setupCallExpectations<Case>(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
+                                  Case::Transition::TARGET_POWER_MODE);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    Case::Transition::verifyPostconditions(this);
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A primary display device is set up
+    Case::Display::injectHwcDisplay(this);
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The diplay is already set to HWC_POWER_MODE_NORMAL
+    display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalJustSetsInternalStateIfVirtualDisplay) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // We need to resize this so that the HWC thinks the virtual display
+    // is something it created.
+    mFlinger.mutableHwcDisplayData().resize(3);
+
+    // A virtual display device is set up
+    Case::Display::injectHwcDisplay(this);
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display is set to HWC_POWER_MODE_OFF
+    getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_OFF);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp
new file mode 100644
index 0000000..b346454
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/EventControlThreadTest.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include "AsyncCallRecorder.h"
+#include "EventControlThread.h"
+
+namespace android {
+namespace {
+
+using namespace std::chrono_literals;
+using testing::_;
+
+class EventControlThreadTest : public testing::Test {
+protected:
+    EventControlThreadTest();
+    ~EventControlThreadTest() override;
+
+    void createThread();
+
+    void expectVSyncEnableCallbackCalled(bool enable);
+
+    AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
+
+    std::unique_ptr<EventControlThread> mThread;
+};
+
+EventControlThreadTest::EventControlThreadTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+EventControlThreadTest::~EventControlThreadTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+void EventControlThreadTest::createThread() {
+    mThread = std::make_unique<android::impl::EventControlThread>(
+            mVSyncSetEnabledCallRecorder.getInvocable());
+}
+
+void EventControlThreadTest::expectVSyncEnableCallbackCalled(bool expectedEnabled) {
+    auto args = mVSyncSetEnabledCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    EXPECT_EQ(std::get<0>(args.value()), expectedEnabled);
+}
+
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+
+TEST_F(EventControlThreadTest, signalsVSyncDisabledOnStartup) {
+    createThread();
+
+    // On thread start, there should be an automatic explicit call to disable
+    // vsyncs
+    expectVSyncEnableCallbackCalled(false);
+}
+
+TEST_F(EventControlThreadTest, signalsVSyncDisabledOnce) {
+    createThread();
+    expectVSyncEnableCallbackCalled(false);
+
+    mThread->setVsyncEnabled(false);
+
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+}
+
+TEST_F(EventControlThreadTest, signalsVSyncEnabledThenDisabled) {
+    createThread();
+    expectVSyncEnableCallbackCalled(false);
+
+    mThread->setVsyncEnabled(true);
+
+    expectVSyncEnableCallbackCalled(true);
+
+    mThread->setVsyncEnabled(false);
+
+    expectVSyncEnableCallbackCalled(false);
+}
+
+TEST_F(EventControlThreadTest, signalsVSyncEnabledOnce) {
+    createThread();
+    expectVSyncEnableCallbackCalled(false);
+
+    mThread->setVsyncEnabled(true);
+
+    expectVSyncEnableCallbackCalled(true);
+
+    mThread->setVsyncEnabled(true);
+
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
new file mode 100644
index 0000000..80fdb80
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+
+#include <utils/Errors.h>
+
+#include "AsyncCallRecorder.h"
+#include "EventThread.h"
+
+using namespace std::chrono_literals;
+using namespace std::placeholders;
+
+using testing::_;
+using testing::Invoke;
+
+namespace android {
+namespace {
+
+class MockVSyncSource : public VSyncSource {
+public:
+    MOCK_METHOD1(setVSyncEnabled, void(bool));
+    MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
+    MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+};
+
+} // namespace
+
+class EventThreadTest : public testing::Test {
+protected:
+    class MockEventThreadConnection : public android::impl::EventThread::Connection {
+    public:
+        explicit MockEventThreadConnection(android::impl::EventThread* eventThread)
+              : android::impl::EventThread::Connection(eventThread) {}
+        MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
+    };
+
+    using ConnectionEventRecorder =
+            AsyncCallRecorderWithCannedReturn<status_t (*)(const DisplayEventReceiver::Event&)>;
+
+    EventThreadTest();
+    ~EventThreadTest() override;
+
+    void createThread();
+    sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder);
+
+    void expectVSyncSetEnabledCallReceived(bool expectedState);
+    void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
+    VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
+    void expectInterceptCallReceived(nsecs_t expectedTimestamp);
+    void expectVsyncEventReceivedByConnection(const char* name,
+                                              ConnectionEventRecorder& connectionEventRecorder,
+                                              nsecs_t expectedTimestamp, unsigned expectedCount);
+    void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
+    void expectHotplugEventReceivedByConnection(int expectedDisplayType, bool expectedConnected);
+
+    AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
+    AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
+    AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
+    ConnectionEventRecorder mConnectionEventCallRecorder{0};
+
+    MockVSyncSource mVSyncSource;
+    std::unique_ptr<android::impl::EventThread> mThread;
+    sp<MockEventThreadConnection> mConnection;
+};
+
+EventThreadTest::EventThreadTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    EXPECT_CALL(mVSyncSource, setVSyncEnabled(_))
+            .WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
+
+    EXPECT_CALL(mVSyncSource, setCallback(_))
+            .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
+
+    EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
+            .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
+
+    createThread();
+    mConnection = createConnection(mConnectionEventCallRecorder);
+}
+
+EventThreadTest::~EventThreadTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+void EventThreadTest::createThread() {
+    mThread =
+            std::make_unique<android::impl::EventThread>(&mVSyncSource,
+                                                         mResyncCallRecorder.getInvocable(),
+                                                         mInterceptVSyncCallRecorder.getInvocable(),
+                                                         "unit-test-event-thread");
+}
+
+sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
+        ConnectionEventRecorder& recorder) {
+    sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get());
+    EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
+    return connection;
+}
+
+void EventThreadTest::expectVSyncSetEnabledCallReceived(bool expectedState) {
+    auto args = mVSyncSetEnabledCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    EXPECT_EQ(expectedState, std::get<0>(args.value()));
+}
+
+void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset) {
+    auto args = mVSyncSetPhaseOffsetCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
+}
+
+VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
+    auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall();
+    return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
+}
+
+void EventThreadTest::expectInterceptCallReceived(nsecs_t expectedTimestamp) {
+    auto args = mInterceptVSyncCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    EXPECT_EQ(expectedTimestamp, std::get<0>(args.value()));
+}
+
+void EventThreadTest::expectVsyncEventReceivedByConnection(
+        const char* name, ConnectionEventRecorder& connectionEventRecorder,
+        nsecs_t expectedTimestamp, unsigned expectedCount) {
+    auto args = connectionEventRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value()) << name << " did not receive an event for timestamp "
+                                  << expectedTimestamp;
+    const auto& event = std::get<0>(args.value());
+    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_VSYNC, event.header.type)
+            << name << " did not get the correct event for timestamp " << expectedTimestamp;
+    EXPECT_EQ(expectedTimestamp, event.header.timestamp)
+            << name << " did not get the expected timestamp for timestamp " << expectedTimestamp;
+    EXPECT_EQ(expectedCount, event.vsync.count)
+            << name << " did not get the expected count for timestamp " << expectedTimestamp;
+}
+
+void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp,
+                                                           unsigned expectedCount) {
+    expectVsyncEventReceivedByConnection("mConnectionEventCallRecorder",
+                                         mConnectionEventCallRecorder, expectedTimestamp,
+                                         expectedCount);
+}
+
+void EventThreadTest::expectHotplugEventReceivedByConnection(int expectedDisplayType,
+                                                             bool expectedConnected) {
+    auto args = mConnectionEventCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    const auto& event = std::get<0>(args.value());
+    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
+    EXPECT_EQ(static_cast<unsigned>(expectedDisplayType), event.header.id);
+    EXPECT_EQ(expectedConnected, event.hotplug.connected);
+}
+
+namespace {
+
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+
+TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) {
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+    EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
+}
+
+TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
+    // Signal that we want the next vsync event to be posted to the connection
+    mThread->requestNextVsync(mConnection);
+
+    // EventThread should immediately request a resync.
+    EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // Use the received callback to signal a first vsync event.
+    // The interceptor should receive the event, as well as the connection.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    expectVsyncEventReceivedByConnection(123, 1u);
+
+    // Use the received callback to signal a second vsync event.
+    // The interceptor should receive the event, but the the connection should
+    // not as it was only interested in the first.
+    callback->onVSyncEvent(456);
+    expectInterceptCallReceived(456);
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+
+    // EventThread should also detect that at this point that it does not need
+    // any more vsync events, and should disable their generation.
+    expectVSyncSetEnabledCallReceived(false);
+}
+
+TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
+    // Create a first connection, register it, and request a vsync rate of zero.
+    ConnectionEventRecorder firstConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
+    mThread->setVsyncRate(0, firstConnection);
+
+    // By itself, this should not enable vsync events
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+    EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
+
+    // However if there is another connection which wants events at a nonzero rate.....
+    ConnectionEventRecorder secondConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> secondConnection =
+            createConnection(secondConnectionEventRecorder);
+    mThread->setVsyncRate(1, secondConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // Send a vsync event. EventThread should then make a call to the
+    // interceptor, and the second connection. The first connection should not
+    // get the event.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
+    expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
+                                         1u);
+}
+
+TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) {
+    mThread->setVsyncRate(1, mConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // Send a vsync event. EventThread should then make a call to the
+    // interceptor, and the connection.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    expectVsyncEventReceivedByConnection(123, 1u);
+
+    // A second event should go to the same places.
+    callback->onVSyncEvent(456);
+    expectInterceptCallReceived(456);
+    expectVsyncEventReceivedByConnection(456, 2u);
+
+    // A third event should go to the same places.
+    callback->onVSyncEvent(789);
+    expectInterceptCallReceived(789);
+    expectVsyncEventReceivedByConnection(789, 3u);
+}
+
+TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
+    mThread->setVsyncRate(2, mConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // The first event will be seen by the interceptor, and not the connection.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+
+    // The second event will be seen by the interceptor and the connection.
+    callback->onVSyncEvent(456);
+    expectInterceptCallReceived(456);
+    expectVsyncEventReceivedByConnection(456, 2u);
+
+    // The third event will be seen by the interceptor, and not the connection.
+    callback->onVSyncEvent(789);
+    expectInterceptCallReceived(789);
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+
+    // The fourth event will be seen by the interceptor and the connection.
+    callback->onVSyncEvent(101112);
+    expectInterceptCallReceived(101112);
+    expectVsyncEventReceivedByConnection(101112, 4u);
+}
+
+TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) {
+    mThread->setVsyncRate(1, mConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // Destroy the only (strong) reference to the connection.
+    mConnection = nullptr;
+
+    // The first event will be seen by the interceptor, and not the connection.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+
+    // EventThread should disable vsync callbacks
+    expectVSyncSetEnabledCallReceived(false);
+}
+
+TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
+    ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
+    sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+    mThread->setVsyncRate(1, errorConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // The first event will be seen by the interceptor, and by the connection,
+    // which then returns an error.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+
+    // A subsequent event will be seen by the interceptor and not by the
+    // connection.
+    callback->onVSyncEvent(456);
+    expectInterceptCallReceived(456);
+    EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
+
+    // EventThread should disable vsync callbacks with the second event
+    expectVSyncSetEnabledCallReceived(false);
+}
+
+TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
+    ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
+    sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+    mThread->setVsyncRate(1, errorConnection);
+
+    // EventThread should enable vsync callbacks, and set a callback interface
+    // pointer to use them with the VSync source.
+    expectVSyncSetEnabledCallReceived(true);
+    auto callback = expectVSyncSetCallbackCallReceived();
+    ASSERT_TRUE(callback);
+
+    // The first event will be seen by the interceptor, and by the connection,
+    // which then returns an non-fatal error.
+    callback->onVSyncEvent(123);
+    expectInterceptCallReceived(123);
+    expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+
+    // A subsequent event will be seen by the interceptor, and by the connection,
+    // which still then returns an non-fatal error.
+    callback->onVSyncEvent(456);
+    expectInterceptCallReceived(456);
+    expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
+
+    // EventThread will not disable vsync callbacks as the errors are non-fatal.
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+}
+
+TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) {
+    mThread->setPhaseOffset(321);
+    expectVSyncSetPhaseOffsetCallReceived(321);
+}
+
+TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
+    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, false);
+    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, false);
+}
+
+TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
+    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true);
+    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, true);
+}
+
+TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
+    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, false);
+    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, false);
+}
+
+TEST_F(EventThreadTest, postHotplugExternalConnect) {
+    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, true);
+    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, true);
+}
+
+TEST_F(EventThreadTest, postHotplugVirtualDisconnectIsFilteredOut) {
+    mThread->onHotplugReceived(DisplayDevice::DISPLAY_VIRTUAL, false);
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
new file mode 100644
index 0000000..acd16fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "DisplayDevice.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+class EventThread;
+
+namespace RE {
+class RenderEngine;
+}
+
+namespace Hwc2 {
+class Composer;
+}
+
+class TestableSurfaceFlinger {
+public:
+    // Extend this as needed for accessing SurfaceFlinger private (and public)
+    // functions.
+
+    void setupRenderEngine(std::unique_ptr<RE::RenderEngine> renderEngine) {
+        mFlinger->getBE().mRenderEngine = std::move(renderEngine);
+    }
+
+    void setupComposer(std::unique_ptr<Hwc2::Composer> composer) {
+        mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer)));
+    }
+
+    using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction;
+    void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
+        mFlinger->mCreateBufferQueue = f;
+    }
+
+    using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction;
+    void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) {
+        mFlinger->mCreateNativeWindowSurface = f;
+    }
+
+    using HotplugEvent = SurfaceFlinger::HotplugEvent;
+
+    /* ------------------------------------------------------------------------
+     * Forwarding for functions being tested
+     */
+
+    auto createDisplay(const String8& displayName, bool secure) {
+        return mFlinger->createDisplay(displayName, secure);
+    }
+
+    auto destroyDisplay(const sp<IBinder>& display) { return mFlinger->destroyDisplay(display); }
+
+    auto resetDisplayState() { return mFlinger->resetDisplayState(); }
+
+    auto setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+                                       const DisplayDeviceState& state,
+                                       const sp<DisplaySurface>& dispSurface,
+                                       const sp<IGraphicBufferProducer>& producer) {
+        return mFlinger->setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+                                                       producer);
+    }
+
+    auto handleTransactionLocked(uint32_t transactionFlags) {
+        return mFlinger->handleTransactionLocked(transactionFlags);
+    }
+
+    auto onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+                           HWC2::Connection connection) {
+        return mFlinger->onHotplugReceived(sequenceId, display, connection);
+    }
+
+    auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); }
+
+    auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
+
+    auto setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, bool stateLockHeld = false) {
+        return mFlinger->setPowerModeInternal(hw, mode, stateLockHeld);
+    }
+
+    /* ------------------------------------------------------------------------
+     * Read-only access to private data to assert post-conditions.
+     */
+
+    const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
+    const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
+    const auto& getHWVsyncAvailable() const { return mFlinger->mHWVsyncAvailable; }
+    const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
+
+    const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
+
+    /* ------------------------------------------------------------------------
+     * Read-write access to private data to set up preconditions and assert
+     * post-conditions.
+     */
+
+    auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
+
+    auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; }
+    auto& mutableCurrentState() { return mFlinger->mCurrentState; }
+    auto& mutableDisplays() { return mFlinger->mDisplays; }
+    auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
+    auto& mutableDrawingState() { return mFlinger->mDrawingState; }
+    auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
+    auto& mutableEventQueue() { return mFlinger->mEventQueue; }
+    auto& mutableEventThread() { return mFlinger->mEventThread; }
+    auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
+    auto& mutableInterceptor() { return mFlinger->mInterceptor; }
+    auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
+    auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+    auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
+    auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
+    auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
+
+    auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
+    auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
+    auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
+
+    ~TestableSurfaceFlinger() {
+        // All these pointer and container clears help ensure that GMock does
+        // not report a leaked object, since the SurfaceFlinger instance may
+        // still be referenced by something despite our best efforts to destroy
+        // it after each test is done.
+        mutableDisplays().clear();
+        mutableEventControlThread().reset();
+        mutableEventQueue().reset();
+        mutableEventThread().reset();
+        mutableInterceptor().reset();
+        mFlinger->getBE().mHwc.reset();
+        mFlinger->getBE().mRenderEngine.reset();
+    }
+
+    /* ------------------------------------------------------------------------
+     * Wrapper classes for Read-write access to private data to set up
+     * preconditions and assert post-conditions.
+     */
+    class FakePowerAdvisor : public Hwc2::PowerAdvisor {
+    public:
+        FakePowerAdvisor() = default;
+        ~FakePowerAdvisor() override = default;
+        void setExpensiveRenderingExpected(hwc2_display_t, bool) override { }
+    };
+
+    struct HWC2Display : public HWC2::Display {
+        HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
+                    const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
+                    HWC2::DisplayType type)
+              : HWC2::Display(composer, advisor, capabilities, id, type) {}
+        ~HWC2Display() {
+            // Prevents a call to disable vsyncs.
+            mType = HWC2::DisplayType::Invalid;
+        }
+
+        auto& mutableIsConnected() { return this->mIsConnected; }
+        auto& mutableConfigs() { return this->mConfigs; }
+    };
+
+    class FakeHwcDisplayInjector {
+    public:
+        static constexpr hwc2_display_t DEFAULT_HWC_DISPLAY_ID = 1000;
+        static constexpr int32_t DEFAULT_WIDTH = 1920;
+        static constexpr int32_t DEFAULT_HEIGHT = 1280;
+        static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+        static constexpr int32_t DEFAULT_DPI = 320;
+        static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
+
+        FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType)
+              : mType(type), mHwcDisplayType(hwcDisplayType) {}
+
+        auto& setHwcDisplayId(hwc2_display_t displayId) {
+            mHwcDisplayId = displayId;
+            return *this;
+        }
+
+        auto& setWidth(int32_t width) {
+            mWidth = width;
+            return *this;
+        }
+
+        auto& setHeight(int32_t height) {
+            mHeight = height;
+            return *this;
+        }
+
+        auto& setRefreshRate(int32_t refreshRate) {
+            mRefreshRate = refreshRate;
+            return *this;
+        }
+
+        auto& setDpiX(int32_t dpi) {
+            mDpiX = dpi;
+            return *this;
+        }
+
+        auto& setDpiY(int32_t dpi) {
+            mDpiY = dpi;
+            return *this;
+        }
+
+        auto& setActiveConfig(int32_t config) {
+            mActiveConfig = config;
+            return *this;
+        }
+
+        auto& addCapability(HWC2::Capability cap) {
+            mCapabilities.emplace(cap);
+            return *this;
+        }
+
+        void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
+            auto display = std::make_unique<HWC2Display>(*composer, mPowerAdvisor, mCapabilities,
+                                                         mHwcDisplayId, mHwcDisplayType);
+
+            auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
+            config.setWidth(mWidth);
+            config.setHeight(mHeight);
+            config.setVsyncPeriod(mRefreshRate);
+            config.setDpiX(mDpiX);
+            config.setDpiY(mDpiY);
+            display->mutableConfigs().emplace(mActiveConfig, config.build());
+            display->mutableIsConnected() = true;
+
+            ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
+            flinger->mutableHwcDisplayData()[mType].reset();
+            flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
+            flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
+
+            flinger->mFakeHwcDisplays.push_back(std::move(display));
+        }
+
+    private:
+        DisplayDevice::DisplayType mType;
+        HWC2::DisplayType mHwcDisplayType;
+        hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
+        int32_t mWidth = DEFAULT_WIDTH;
+        int32_t mHeight = DEFAULT_HEIGHT;
+        int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
+        int32_t mDpiX = DEFAULT_DPI;
+        int32_t mDpiY = DEFAULT_DPI;
+        int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
+        std::unordered_set<HWC2::Capability> mCapabilities;
+        FakePowerAdvisor mPowerAdvisor;
+    };
+
+    class FakeDisplayDeviceInjector {
+    public:
+        FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
+                                  int hwcId)
+              : mFlinger(flinger), mType(type), mHwcId(hwcId) {}
+
+        sp<IBinder> token() const { return mDisplayToken; }
+
+        DisplayDeviceState& mutableDrawingDisplayState() {
+            return mFlinger.mutableDrawingState().displays.editValueFor(mDisplayToken);
+        }
+
+        DisplayDeviceState& mutableCurrentDisplayState() {
+            return mFlinger.mutableCurrentState().displays.editValueFor(mDisplayToken);
+        }
+
+        const auto& getDrawingDisplayState() {
+            return mFlinger.mutableDrawingState().displays.valueFor(mDisplayToken);
+        }
+
+        const auto& getCurrentDisplayState() {
+            return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken);
+        }
+
+        auto& mutableDisplayDevice() { return mFlinger.mutableDisplays().valueFor(mDisplayToken); }
+
+        auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
+            mNativeWindow = nativeWindow;
+            return *this;
+        }
+
+        auto& setDisplaySurface(const sp<DisplaySurface>& displaySurface) {
+            mDisplaySurface = displaySurface;
+            return *this;
+        }
+
+        auto& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) {
+            mRenderSurface = std::move(renderSurface);
+            return *this;
+        }
+
+        auto& setSecure(bool secure) {
+            mSecure = secure;
+            return *this;
+        }
+
+        sp<DisplayDevice> inject() {
+            std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents;
+            sp<DisplayDevice> device =
+                    new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, mSecure, mDisplayToken,
+                                      mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0,
+                                      0, false, HdrCapabilities(), 0, hdrAndRenderIntents,
+                                      HWC_POWER_MODE_NORMAL);
+            mFlinger.mutableDisplays().add(mDisplayToken, device);
+
+            DisplayDeviceState state(mType, mSecure);
+            mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
+            mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
+
+            if (mType >= DisplayDevice::DISPLAY_PRIMARY && mType < DisplayDevice::DISPLAY_VIRTUAL) {
+                mFlinger.mutableBuiltinDisplays()[mType] = mDisplayToken;
+            }
+
+            return device;
+        }
+
+    private:
+        TestableSurfaceFlinger& mFlinger;
+        sp<BBinder> mDisplayToken = new BBinder();
+        DisplayDevice::DisplayType mType;
+        int mHwcId;
+        sp<ANativeWindow> mNativeWindow;
+        sp<DisplaySurface> mDisplaySurface;
+        std::unique_ptr<RE::Surface> mRenderSurface;
+        bool mSecure = false;
+    };
+
+    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
+
+    // We need to keep a reference to these so they are properly destroyed.
+    std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
+};
+
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 0eda0af..7ed57b9 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/DisplayHardware/MockComposer.h"
 
-using namespace vulkan;
+namespace android {
+namespace Hwc2 {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+Composer::Composer() = default;
+Composer::~Composer() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
new file mode 100644
index 0000000..267670a
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace android {
+
+class GraphicBuffer;
+
+namespace Hwc2 {
+namespace mock {
+
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::common::V1_1::RenderIntent;
+
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposer;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+class Composer : public Hwc2::Composer {
+public:
+    Composer();
+    ~Composer() override;
+
+    MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
+    MOCK_METHOD0(dumpDebugInfo, std::string());
+    MOCK_METHOD1(registerCallback, void(const sp<IComposerCallback>&));
+    MOCK_METHOD0(isRemote, bool());
+    MOCK_METHOD0(resetCommands, void());
+    MOCK_METHOD0(executeCommands, Error());
+    MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
+    MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+    MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
+    MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
+    MOCK_METHOD1(acceptDisplayChanges, Error(Display));
+    MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer));
+    MOCK_METHOD2(destroyLayer, Error(Display, Layer));
+    MOCK_METHOD2(getActiveConfig, Error(Display, Config*));
+    MOCK_METHOD3(getChangedCompositionTypes,
+                 Error(Display, std::vector<Layer>*, std::vector<IComposerClient::Composition>*));
+    MOCK_METHOD2(getColorModes, Error(Display, std::vector<ColorMode>*));
+    MOCK_METHOD4(getDisplayAttribute,
+                 Error(Display, Config config, IComposerClient::Attribute, int32_t*));
+    MOCK_METHOD2(getDisplayConfigs, Error(Display, std::vector<Config>*));
+    MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
+    MOCK_METHOD4(getDisplayRequests,
+                 Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
+    MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
+    MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
+    MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
+    MOCK_METHOD2(getPerFrameMetadataKeys,
+                 Error(Display, std::vector<IComposerClient::PerFrameMetadataKey>*));
+    MOCK_METHOD2(getDataspaceSaturationMatrix, Error(Dataspace, mat4*));
+    MOCK_METHOD3(getReleaseFences, Error(Display, std::vector<Layer>*, std::vector<int>*));
+    MOCK_METHOD2(presentDisplay, Error(Display, int*));
+    MOCK_METHOD2(setActiveConfig, Error(Display, Config));
+    MOCK_METHOD6(setClientTarget,
+                 Error(Display, uint32_t, const sp<GraphicBuffer>&, int, Dataspace,
+                       const std::vector<IComposerClient::Rect>&));
+    MOCK_METHOD3(setColorMode, Error(Display, ColorMode, RenderIntent));
+    MOCK_METHOD3(setColorTransform, Error(Display, const float*, ColorTransform));
+    MOCK_METHOD3(setOutputBuffer, Error(Display, const native_handle_t*, int));
+    MOCK_METHOD2(setPowerMode, Error(Display, IComposerClient::PowerMode));
+    MOCK_METHOD2(setVsyncEnabled, Error(Display, IComposerClient::Vsync));
+    MOCK_METHOD1(setClientTargetSlotCount, Error(Display));
+    MOCK_METHOD3(validateDisplay, Error(Display, uint32_t*, uint32_t*));
+    MOCK_METHOD5(presentOrValidateDisplay, Error(Display, uint32_t*, uint32_t*, int*, uint32_t*));
+    MOCK_METHOD4(setCursorPosition, Error(Display, Layer, int32_t, int32_t));
+    MOCK_METHOD5(setLayerBuffer, Error(Display, Layer, uint32_t, const sp<GraphicBuffer>&, int));
+    MOCK_METHOD3(setLayerSurfaceDamage,
+                 Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
+    MOCK_METHOD3(setLayerBlendMode, Error(Display, Layer, IComposerClient::BlendMode));
+    MOCK_METHOD3(setLayerColor, Error(Display, Layer, const IComposerClient::Color&));
+    MOCK_METHOD3(setLayerCompositionType, Error(Display, Layer, IComposerClient::Composition));
+    MOCK_METHOD3(setLayerDataspace, Error(Display, Layer, Dataspace));
+    MOCK_METHOD3(setLayerPerFrameMetadata,
+                 Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadata>&));
+    MOCK_METHOD3(setLayerDisplayFrame, Error(Display, Layer, const IComposerClient::Rect&));
+    MOCK_METHOD3(setLayerPlaneAlpha, Error(Display, Layer, float));
+    MOCK_METHOD3(setLayerSidebandStream, Error(Display, Layer, const native_handle_t*));
+    MOCK_METHOD3(setLayerSourceCrop, Error(Display, Layer, const IComposerClient::FRect&));
+    MOCK_METHOD3(setLayerTransform, Error(Display, Layer, Transform));
+    MOCK_METHOD3(setLayerVisibleRegion,
+                 Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
+    MOCK_METHOD3(setLayerZOrder, Error(Display, Layer, uint32_t));
+    MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t));
+    MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector<RenderIntent>*));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
index 0eda0af..e6ac6bf 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/DisplayHardware/MockDisplaySurface.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+DisplaySurface::DisplaySurface() = default;
+DisplaySurface::~DisplaySurface() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
new file mode 100644
index 0000000..d6c9aa4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <utils/String8.h>
+
+#include "DisplayHardware/DisplaySurface.h"
+
+namespace android {
+namespace mock {
+
+class DisplaySurface : public android::DisplaySurface {
+public:
+    DisplaySurface();
+    ~DisplaySurface() override;
+
+    MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+    MOCK_METHOD1(prepareFrame, status_t(CompositionType compositionType));
+    MOCK_METHOD0(advanceFrame, status_t());
+    MOCK_METHOD0(onFrameCommitted, void());
+    MOCK_CONST_METHOD1(dumpAsString, void(String8& result));
+    MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t));
+    MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp
index 0eda0af..8be7077 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "MockPowerAdvisor.h"
 
-using namespace vulkan;
+namespace android {
+namespace Hwc2 {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
new file mode 100644
index 0000000..dc6d83b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    MOCK_METHOD2(setExpensiveRenderingExpected, void(hwc2_display_t displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/MockEventControlThread.cpp
index 0eda0af..f9bacc8 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/MockEventControlThread.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+EventControlThread::EventControlThread() = default;
+EventControlThread::~EventControlThread() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h
new file mode 100644
index 0000000..8ac09a9
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventControlThread.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "EventControlThread.h"
+
+namespace android {
+namespace mock {
+
+class EventControlThread : public android::EventControlThread {
+public:
+    EventControlThread();
+    ~EventControlThread() override;
+
+    MOCK_METHOD1(setVsyncEnabled, void(bool));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp
similarity index 65%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp
index 0eda0af..408cd35 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/MockEventThread.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+EventThread::EventThread() = default;
+EventThread::~EventThread() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
new file mode 100644
index 0000000..e6ea663
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "EventThread.h"
+
+namespace android {
+namespace mock {
+
+class EventThread : public android::EventThread {
+public:
+    EventThread();
+    ~EventThread() override;
+
+    MOCK_CONST_METHOD0(createEventConnection, sp<BnDisplayEventConnection>());
+    MOCK_METHOD0(onScreenReleased, void());
+    MOCK_METHOD0(onScreenAcquired, void());
+    MOCK_METHOD2(onHotplugReceived, void(int, bool));
+    MOCK_CONST_METHOD1(dump, void(String8&));
+    MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
similarity index 64%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
index 0eda0af..97a13e4 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/MockMessageQueue.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+MessageQueue::MessageQueue() = default;
+MessageQueue::~MessageQueue() = default;
+
+} // namespace mock
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
new file mode 100644
index 0000000..cf07cf7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+namespace mock {
+
+class MessageQueue : public android::MessageQueue {
+public:
+    MessageQueue();
+    ~MessageQueue() override;
+
+    MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
+    MOCK_METHOD1(setEventThread, void(android::EventThread*));
+    MOCK_METHOD0(waitMessage, void());
+    MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+    MOCK_METHOD0(invalidate, void());
+    MOCK_METHOD0(refresh, void());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.cpp
index 0eda0af..25ff39b 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/MockNativeWindowSurface.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+NativeWindowSurface::NativeWindowSurface() = default;
+NativeWindowSurface::~NativeWindowSurface() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.h b/services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.h
new file mode 100644
index 0000000..88d1a9f
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockNativeWindowSurface.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <system/window.h> // for ANativeWindow
+
+#include "SurfaceFlinger.h" // for base NativeWindowSurface
+
+namespace android {
+namespace mock {
+
+class NativeWindowSurface : public android::NativeWindowSurface {
+public:
+    NativeWindowSurface();
+    ~NativeWindowSurface();
+
+    MOCK_CONST_METHOD0(getNativeWindow, sp<ANativeWindow>());
+    MOCK_METHOD0(preallocateBuffers, void());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
similarity index 62%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
index 0eda0af..4129328 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/MockSurfaceInterceptor.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+SurfaceInterceptor::SurfaceInterceptor() = default;
+SurfaceInterceptor::~SurfaceInterceptor() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
new file mode 100644
index 0000000..458b2f3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "SurfaceInterceptor.h"
+
+namespace android {
+namespace mock {
+
+class SurfaceInterceptor : public android::SurfaceInterceptor {
+public:
+    SurfaceInterceptor();
+    ~SurfaceInterceptor() override;
+
+    MOCK_METHOD2(enable,
+                 void(const SortedVector<sp<Layer>>&,
+                      const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
+    MOCK_METHOD0(disable, void());
+    MOCK_METHOD0(isEnabled, bool());
+    MOCK_METHOD4(saveTransaction,
+                 void(const Vector<ComposerState>&,
+                      const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
+                      const Vector<DisplayState>&, uint32_t));
+    MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
+    MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
+    MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+    MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
+    MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
+    MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));
+    MOCK_METHOD1(saveVSyncEvent, void(nsecs_t));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
new file mode 100644
index 0000000..a98bece
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "mock/RenderEngine/MockRenderEngine.h"
+
+namespace android {
+namespace RE {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+RenderEngine::RenderEngine() = default;
+RenderEngine::~RenderEngine() = default;
+
+Surface::Surface() = default;
+Surface::~Surface() = default;
+
+Image::Image() = default;
+Image::~Image() = default;
+
+} // namespace mock
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
new file mode 100644
index 0000000..ac08293
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "RenderEngine/Image.h"
+#include "RenderEngine/Mesh.h"
+#include "RenderEngine/RenderEngine.h"
+#include "RenderEngine/Surface.h"
+#include "RenderEngine/Texture.h"
+
+namespace android {
+namespace RE {
+namespace mock {
+
+class RenderEngine : public RE::RenderEngine {
+public:
+    RenderEngine();
+    ~RenderEngine() override;
+
+    MOCK_METHOD0(createSurface, std::unique_ptr<RE::Surface>());
+    MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
+    MOCK_CONST_METHOD0(primeCache, void());
+    MOCK_METHOD1(dump, void(String8&));
+    MOCK_CONST_METHOD0(supportsImageCrop, bool());
+    MOCK_CONST_METHOD0(isCurrent, bool());
+    MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
+    MOCK_METHOD0(resetCurrentSurface, void());
+    MOCK_METHOD0(flush, base::unique_fd());
+    MOCK_METHOD0(finish, bool());
+    MOCK_METHOD1(waitFence, bool(base::unique_fd*));
+    bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
+    MOCK_METHOD4(clearWithColor, void(float, float, float, float));
+    MOCK_METHOD6(fillRegionWithColor, void(const Region&, uint32_t, float, float, float, float));
+    MOCK_METHOD4(setScissor, void(uint32_t, uint32_t, uint32_t, uint32_t));
+    MOCK_METHOD0(disableScissor, void());
+    MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
+    MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
+    MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const RE::Image&));
+    MOCK_METHOD5(readPixels, void(size_t, size_t, size_t, size_t, uint32_t*));
+    MOCK_CONST_METHOD0(checkErrors, void());
+    MOCK_METHOD6(setViewportAndProjection,
+                 void(size_t, size_t, Rect, size_t, bool, Transform::orientation_flags));
+    MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
+    MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
+    MOCK_METHOD0(setupLayerBlackedOut, void());
+    MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
+    MOCK_METHOD1(setupColorTransform, void(const mat4&));
+    MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
+    MOCK_METHOD0(disableTexturing, void());
+    MOCK_METHOD0(disableBlending, void());
+    MOCK_METHOD1(setSourceY410BT2020, void(bool));
+    MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
+    MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
+                 void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
+    MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
+    MOCK_METHOD1(drawMesh, void(const Mesh&));
+    MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
+    MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
+};
+
+class Surface : public RE::Surface {
+public:
+    Surface();
+    ~Surface() override;
+
+    MOCK_METHOD1(setCritical, void(bool));
+    MOCK_METHOD1(setAsync, void(bool));
+    MOCK_METHOD1(setNativeWindow, void(ANativeWindow*));
+    MOCK_CONST_METHOD0(swapBuffers, void());
+    MOCK_CONST_METHOD0(queryRedSize, int32_t());
+    MOCK_CONST_METHOD0(queryGreenSize, int32_t());
+    MOCK_CONST_METHOD0(queryBlueSize, int32_t());
+    MOCK_CONST_METHOD0(queryAlphaSize, int32_t());
+    MOCK_CONST_METHOD0(queryWidth, int32_t());
+    MOCK_CONST_METHOD0(queryHeight, int32_t());
+};
+
+class Image : public RE::Image {
+public:
+    Image();
+    ~Image() override;
+
+    MOCK_METHOD4(setNativeWindowBuffer,
+                 bool(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                      int32_t cropHeight));
+};
+
+} // namespace mock
+} // namespace RE
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
similarity index 61%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
index 0eda0af..a17b73f 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/gui/MockGraphicBufferConsumer.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+GraphicBufferConsumer::GraphicBufferConsumer() = default;
+GraphicBufferConsumer::~GraphicBufferConsumer() = default;
+
+} // namespace mock
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
new file mode 100644
index 0000000..98f24c2
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <gui/IGraphicBufferConsumer.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+namespace mock {
+
+class GraphicBufferConsumer : public BnGraphicBufferConsumer, public virtual android::RefBase {
+public:
+    GraphicBufferConsumer();
+    ~GraphicBufferConsumer() override;
+
+    MOCK_METHOD3(acquireBuffer, status_t(BufferItem*, nsecs_t, uint64_t));
+    MOCK_METHOD1(detachBuffer, status_t(int));
+    MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
+    MOCK_METHOD5(releaseBuffer, status_t(int, uint64_t, EGLDisplay, EGLSyncKHR, const sp<Fence>&));
+    MOCK_METHOD2(consumerConnect, status_t(const sp<IConsumerListener>&, bool));
+    MOCK_METHOD0(consumerDisconnect, status_t());
+    MOCK_METHOD1(getReleasedBuffers, status_t(uint64_t*));
+    MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t));
+    MOCK_METHOD1(setMaxBufferCount, status_t(int));
+    MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int));
+    MOCK_METHOD1(setConsumerName, status_t(const String8&));
+    MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat));
+    MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace));
+    MOCK_METHOD1(setConsumerUsageBits, status_t(uint64_t));
+    MOCK_METHOD1(setConsumerIsProtected, status_t(bool));
+    MOCK_METHOD1(setTransformHint, status_t(uint32_t));
+    MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
+    MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
+    MOCK_METHOD0(discardFreeBuffers, status_t());
+    MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
similarity index 61%
copy from vulkan/libvulkan/vulkan_loader_data.cpp
copy to services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
index 0eda0af..a7fd667 100644
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-#include <vulkan/vulkan_loader_data.h>
+#include "mock/gui/MockGraphicBufferProducer.h"
 
-using namespace vulkan;
+namespace android {
+namespace mock {
 
-LoaderData& LoaderData::GetInstance() {
-    static LoaderData loader_data = {};
-    return loader_data;
-}
+// Explicit default instantiation is recommended.
+GraphicBufferProducer::GraphicBufferProducer() = default;
+GraphicBufferProducer::~GraphicBufferProducer() = default;
+
+} // namespace mock
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
new file mode 100644
index 0000000..c98f39f
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <gui/IGraphicBufferProducer.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+namespace mock {
+
+class GraphicBufferProducer : public BnGraphicBufferProducer, public virtual android::RefBase {
+public:
+    GraphicBufferProducer();
+    ~GraphicBufferProducer() override;
+
+    MOCK_METHOD2(requestBuffer, status_t(int, sp<GraphicBuffer>*));
+    MOCK_METHOD1(setMaxDequeuedBufferCount, status_t(int));
+    MOCK_METHOD1(setAsyncMode, status_t(bool));
+    MOCK_METHOD8(dequeueBuffer,
+                 status_t(int*, sp<Fence>*, uint32_t, uint32_t, PixelFormat, uint64_t, uint64_t*,
+                          FrameEventHistoryDelta*));
+    MOCK_METHOD1(detachBuffer, status_t(int));
+    MOCK_METHOD2(detachNextBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*));
+    MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
+    MOCK_METHOD3(queueBuffer, status_t(int, const QueueBufferInput&, QueueBufferOutput*));
+    MOCK_METHOD2(cancelBuffer, status_t(int, const sp<Fence>&));
+    MOCK_METHOD2(query, int(int, int*));
+    MOCK_METHOD4(connect, status_t(const sp<IProducerListener>&, int, bool, QueueBufferOutput*));
+    MOCK_METHOD2(disconnect, status_t(int, DisconnectMode));
+    MOCK_METHOD1(setSidebandStream, status_t(const sp<NativeHandle>&));
+    MOCK_METHOD4(allocateBuffers, void(uint32_t, uint32_t, PixelFormat, uint64_t));
+    MOCK_METHOD1(allowAllocation, status_t(bool));
+    MOCK_METHOD1(setGenerationNumber, status_t(uint32_t));
+    MOCK_CONST_METHOD0(getConsumerName, String8());
+    MOCK_METHOD1(setSharedBufferMode, status_t(bool));
+    MOCK_METHOD1(setAutoRefresh, status_t(bool));
+    MOCK_METHOD1(setDequeueTimeout, status_t(nsecs_t));
+    MOCK_METHOD3(getLastQueuedBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*, float[16]));
+    MOCK_METHOD1(getFrameTimestamps, void(FrameEventHistoryDelta*));
+    MOCK_CONST_METHOD1(getUniqueId, status_t(uint64_t*));
+    MOCK_CONST_METHOD1(getConsumerUsage, status_t(uint64_t*));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.cpp b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.cpp
new file mode 100644
index 0000000..a490b92
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include "mock/system/window/MockNativeWindow.h"
+
+namespace android {
+namespace mock {
+namespace {
+
+int dispatch_setSwapInterval(struct ANativeWindow* window, int interval) {
+    return static_cast<NativeWindow*>(window)->setSwapInterval(interval);
+}
+
+int dispatch_dequeueBuffer_DEPRECATED(struct ANativeWindow* window,
+                                      struct ANativeWindowBuffer** buffer) {
+    return static_cast<NativeWindow*>(window)->dequeueBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_lockBuffer_DEPRECATED(struct ANativeWindow* window,
+                                   struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->lockBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_queueBuffer_DEPRECATED(struct ANativeWindow* window,
+                                    struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->queueBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_query(const struct ANativeWindow* window, int what, int* value) {
+    return static_cast<const NativeWindow*>(window)->query(what, value);
+}
+
+int dispatch_perform(struct ANativeWindow* window, int operation, ...) {
+    // TODO: Handle the various operations and their varargs better.
+    return static_cast<NativeWindow*>(window)->perform(operation);
+}
+
+int dispatch_cancelBuffer_DEPRECATED(struct ANativeWindow* window,
+                                     struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->cancelBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_dequeueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer,
+                           int* fenceFd) {
+    return static_cast<NativeWindow*>(window)->dequeueBuffer(buffer, fenceFd);
+}
+
+int dispatch_queueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer,
+                         int fenceFd) {
+    return static_cast<NativeWindow*>(window)->queueBuffer(buffer, fenceFd);
+}
+
+int dispatch_cancelBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer,
+                          int fenceFd) {
+    return static_cast<NativeWindow*>(window)->cancelBuffer(buffer, fenceFd);
+}
+
+} // namespace
+
+NativeWindow::NativeWindow() {
+    // ANativeWindow is a structure with function pointers and not a C++ class.
+    // Set all the pointers to dispatch functions, which will invoke the mock
+    // interface functions.
+    ANativeWindow::setSwapInterval = &dispatch_setSwapInterval;
+    ANativeWindow::dequeueBuffer_DEPRECATED = &dispatch_dequeueBuffer_DEPRECATED;
+    ANativeWindow::lockBuffer_DEPRECATED = &dispatch_lockBuffer_DEPRECATED;
+    ANativeWindow::queueBuffer_DEPRECATED = &dispatch_queueBuffer_DEPRECATED;
+    ANativeWindow::query = &dispatch_query;
+    ANativeWindow::perform = &dispatch_perform;
+    ANativeWindow::cancelBuffer_DEPRECATED = &dispatch_cancelBuffer_DEPRECATED;
+    ANativeWindow::dequeueBuffer = &dispatch_dequeueBuffer;
+    ANativeWindow::queueBuffer = &dispatch_queueBuffer;
+    ANativeWindow::cancelBuffer = &dispatch_cancelBuffer;
+}
+
+// Explicit default instantiation is recommended.
+NativeWindow::~NativeWindow() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
new file mode 100644
index 0000000..561fd58
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <system/window.h>
+
+#include <ui/ANativeObjectBase.h>
+
+namespace android {
+namespace mock {
+
+class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow, RefBase> {
+public:
+    NativeWindow();
+    ~NativeWindow();
+
+    MOCK_METHOD1(setSwapInterval, int(int interval));
+    MOCK_METHOD1(dequeueBuffer_DEPRECATED, int(struct ANativeWindowBuffer**));
+    MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_CONST_METHOD2(query, int(int, int*));
+    MOCK_METHOD1(perform, int(int));
+    MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+    MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+    MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
new file mode 100644
index 0000000..d04efda
--- /dev/null
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+cc_binary {
+    name: "test-vsync-events",
+    defaults: ["surfaceflinger_defaults"],
+    tags: ["test"],
+    srcs: [
+        "vsync.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libui",
+        "libutils",
+    ]
+
+}
diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk
deleted file mode 100644
index 8e41617..0000000
--- a/services/surfaceflinger/tests/vsync/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	vsync.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	libbinder \
-    libui \
-    libgui
-
-LOCAL_MODULE:= test-vsync-events
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
new file mode 100644
index 0000000..cb6d0fd
--- /dev/null
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+cc_binary {
+    name: "test-waitforvsync",
+    cflags: [
+        "-Werror",
+    ],
+    srcs: [
+        "waitforvsync.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+    ]
+}
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk
deleted file mode 100644
index 932d2be..0000000
--- a/services/surfaceflinger/tests/waitforvsync/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	waitforvsync.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-
-LOCAL_MODULE:= test-waitforvsync
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt
new file mode 100644
index 0000000..2340785
--- /dev/null
+++ b/services/surfaceflinger/version-script32.txt
@@ -0,0 +1,12 @@
+{
+global:
+  EnsureFrontOfChain;
+  AddSpecialSignalHandlerFn;
+  RemoveSpecialSignalHandlerFn;
+  bsd_signal;
+  sigaction;
+  signal;
+  sigprocmask;
+local:
+  *;
+};
diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt
new file mode 100644
index 0000000..acf3630
--- /dev/null
+++ b/services/surfaceflinger/version-script64.txt
@@ -0,0 +1,11 @@
+{
+global:
+  EnsureFrontOfChain;
+  AddSpecialSignalHandlerFn;
+  RemoveSpecialSignalHandlerFn;
+  sigaction;
+  signal;
+  sigprocmask;
+local:
+  *;
+};
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
index b9836ce..94c2c78 100644
--- a/services/thermalservice/thermalservice.rc
+++ b/services/thermalservice/thermalservice.rc
@@ -1,2 +1,4 @@
 service thermalservice /system/bin/thermalserviced
     class core
+    user system
+    group system
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
new file mode 100644
index 0000000..6132956
--- /dev/null
+++ b/services/utils/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 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.
+
+//
+// Static library used in testing and executables
+//
+cc_library_static {
+    name: "libserviceutils",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "PriorityDumper.cpp",
+    ],
+
+    clang: true,
+    export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
new file mode 100644
index 0000000..967dee5
--- /dev/null
+++ b/services/utils/PriorityDumper.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/serviceutils/PriorityDumper.h"
+
+namespace android {
+
+const char16_t PriorityDumper::PROTO_ARG[] = u"--proto";
+const char16_t PriorityDumper::PRIORITY_ARG[] = u"--dump-priority";
+const char16_t PriorityDumper::PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
+const char16_t PriorityDumper::PRIORITY_ARG_HIGH[] = u"HIGH";
+const char16_t PriorityDumper::PRIORITY_ARG_NORMAL[] = u"NORMAL";
+
+enum class PriorityType { INVALID, CRITICAL, HIGH, NORMAL };
+
+static PriorityType getPriorityType(const String16& arg) {
+    if (arg == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+        return PriorityType::CRITICAL;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_HIGH) {
+        return PriorityType::HIGH;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_NORMAL) {
+        return PriorityType::NORMAL;
+    }
+    return PriorityType::INVALID;
+}
+
+status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+    status_t status;
+    status = dumpCritical(fd, args, asProto);
+    if (status != OK) return status;
+    status = dumpHigh(fd, args, asProto);
+    if (status != OK) return status;
+    status = dumpNormal(fd, args, asProto);
+    if (status != OK) return status;
+    return status;
+}
+
+status_t PriorityDumper::priorityDump(int fd, const Vector<String16>& args) {
+    status_t status;
+    bool asProto = false;
+    PriorityType priority = PriorityType::INVALID;
+
+    Vector<String16> strippedArgs;
+    for (uint32_t argIndex = 0; argIndex < args.size(); argIndex++) {
+        if (args[argIndex] == PROTO_ARG) {
+            asProto = true;
+        } else if (args[argIndex] == PRIORITY_ARG) {
+            if (argIndex + 1 < args.size()) {
+                argIndex++;
+                priority = getPriorityType(args[argIndex]);
+            }
+        } else {
+            strippedArgs.add(args[argIndex]);
+        }
+    }
+
+    switch (priority) {
+        case PriorityType::CRITICAL:
+            status = dumpCritical(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::HIGH:
+            status = dumpHigh(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::NORMAL:
+            status = dumpNormal(fd, strippedArgs, asProto);
+            break;
+        default:
+            status = dumpAll(fd, strippedArgs, asProto);
+            break;
+    }
+    return status;
+}
+} // namespace android
diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h
new file mode 100644
index 0000000..d01a102
--- /dev/null
+++ b/services/utils/include/serviceutils/PriorityDumper.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_UTILS_PRIORITYDUMPER_H
+#define ANDROID_UTILS_PRIORITYDUMPER_H
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+// Helper class to parse common arguments responsible for splitting dumps into
+// various priority buckets and changing the output format of the dump.
+class PriorityDumper {
+public:
+    static const char16_t PRIORITY_ARG[];
+    static const char16_t PRIORITY_ARG_CRITICAL[];
+    static const char16_t PRIORITY_ARG_HIGH[];
+    static const char16_t PRIORITY_ARG_NORMAL[];
+    static const char16_t PROTO_ARG[];
+
+    // Parses the argument list searching for --dump_priority with a priority type
+    // (HIGH, CRITICAL or NORMAL) and --proto. Matching arguments are stripped.
+    // If a valid priority type is found, the associated PriorityDumper
+    // method is called otherwise all supported sections are dumped.
+    // If --proto is found, the dumpAsProto flag is set to dump sections in proto
+    // format.
+    status_t priorityDump(int fd, const Vector<String16>& args);
+
+    // Dumps CRITICAL priority sections.
+    virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
+
+    // Dumps HIGH priority sections.
+    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
+
+    // Dumps normal priority sections.
+    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
+
+    // Dumps all sections.
+    // This method is called when priorityDump is called without priority
+    // arguments. By default, it calls all three dump methods.
+    virtual status_t dumpAll(int fd, const Vector<String16>& args, bool asProto);
+    virtual ~PriorityDumper() = default;
+};
+
+} // namespace android
+
+#endif // ANDROID_UTILS_PRIORITYDUMPER_H
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
new file mode 100644
index 0000000..f21254c
--- /dev/null
+++ b/services/utils/tests/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 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.
+
+// Build unit tests.
+
+cc_test {
+    name: "prioritydumper_test",
+    test_suites: ["device-tests"],
+    srcs: ["PriorityDumper_test.cpp"],
+    shared_libs: [
+        "libutils",
+    ],
+    static_libs: [
+        "libgmock",
+        "libserviceutils",
+    ],
+    clang: true,
+}
diff --git a/services/utils/tests/AndroidTest.xml b/services/utils/tests/AndroidTest.xml
new file mode 100644
index 0000000..83c890d
--- /dev/null
+++ b/services/utils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for prioritydumper_test">
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="cleanup" value="true" />
+    <option name="push" value="prioritydumper_test->/data/local/tmp/prioritydumper_test" />
+  </target_preparer>
+  <option name="test-suite-tag" value="apct" />
+  <test class="com.android.tradefed.testtype.GTest" >
+    <option name="native-test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="prioritydumper_test" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
new file mode 100644
index 0000000..90cc6de
--- /dev/null
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "serviceutils/PriorityDumper.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::ElementsAreArray;
+using ::testing::Mock;
+using ::testing::Test;
+
+class PriorityDumperMock : public PriorityDumper {
+public:
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpAll, status_t(int, const Vector<String16>&, bool));
+};
+
+class DumpAllMock : public PriorityDumper {
+public:
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+};
+
+class PriorityDumperTest : public Test {
+public:
+    PriorityDumperTest() : dumper_(), dumpAlldumper_(), fd(1) {}
+    PriorityDumperMock dumper_;
+    DumpAllMock dumpAlldumper_;
+    int fd;
+};
+
+static void addAll(Vector<String16>& av, const std::vector<std::string>& v) {
+    for (auto element : v) {
+        av.add(String16(element.c_str()));
+    }
+}
+
+TEST_F(PriorityDumperTest, noArgsPassed) {
+    Vector<String16> args;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
+    Vector<String16> args;
+    addAll(args, {"bunch", "of", "args"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgsOnly) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCritical) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCriticalInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "--dump-priority", "CRITICAL", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHigh) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "HIGH", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHighInEnd) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "behind", "--dump-priority", "HIGH"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpNormal) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpAll) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args), /*asProto=*/false));
+
+    dumpAlldumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "REALLY_HIGH"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArg) {
+    Vector<String16> args;
+    addAll(args, {"--proto"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgs) {
+    Vector<String16> args;
+    addAll(args, {"--proto", "args", "--dump-priority", "NORMAL", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgsInReverseOrder) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgAtEnd) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "args", "left", "behind", "--proto"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithInvalidPriorityType) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NOT_SO_HIGH", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
\ No newline at end of file
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
new file mode 100644
index 0000000..6122846
--- /dev/null
+++ b/services/vr/bufferhubd/Android.bp
@@ -0,0 +1,56 @@
+// Copyright (C) 2016 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.
+
+sourceFiles = [
+    "buffer_hub.cpp",
+    "bufferhubd.cpp",
+    "consumer_channel.cpp",
+    "producer_channel.cpp",
+    "detached_buffer_channel.cpp",
+    "consumer_queue_channel.cpp",
+    "producer_queue_channel.cpp",
+]
+
+headerLibraries = ["libdvr_headers"]
+
+staticLibraries = [
+    "libperformance",
+    "libbufferhub",
+]
+
+sharedLibraries = [
+    "libbase",
+    "libbinder",
+    "libcutils",
+    "liblog",
+    "libsync",
+    "libutils",
+    "libgui",
+    "libui",
+    "libpdx_default_transport",
+]
+
+cc_binary {
+    srcs: sourceFiles,
+    cflags: [
+        "-DLOG_TAG=\"bufferhubd\"",
+        "-DTRACE=0",
+        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+    ],
+    header_libs: headerLibraries,
+    static_libs: staticLibraries,
+    shared_libs: sharedLibraries,
+    name: "bufferhubd",
+    init_rc: ["bufferhubd.rc"],
+}
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
deleted file mode 100644
index 28cf53d..0000000
--- a/services/vr/bufferhubd/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-sourceFiles := \
-    buffer_hub.cpp \
-    bufferhubd.cpp \
-    consumer_channel.cpp \
-    producer_channel.cpp \
-    consumer_queue_channel.cpp \
-    producer_queue_channel.cpp \
-
-headerLibraries := \
-	libdvr_headers
-
-staticLibraries := \
-	libperformance \
-	libpdx_default_transport \
-	libbufferhub
-
-sharedLibraries := \
-	libbase \
-	libcutils \
-	liblog \
-	libsync \
-	libutils \
-        libgui \
-        libui
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(sourceFiles)
-LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\"
-LOCAL_CFLAGS += -DTRACE=0
-LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
-LOCAL_HEADER_LIBRARIES := $(headerLibraries)
-LOCAL_STATIC_LIBRARIES := $(staticLibraries)
-LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
-LOCAL_MODULE := bufferhubd
-LOCAL_INIT_RC := bufferhubd.rc
-include $(BUILD_EXECUTABLE)
-
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index cdb1f91..e57c8ed 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -6,6 +6,7 @@
 #include <utils/Trace.h>
 
 #include <iomanip>
+#include <memory>
 #include <sstream>
 #include <string>
 #include <thread>
@@ -13,6 +14,7 @@
 #include <pdx/default_transport/service_endpoint.h>
 #include <private/dvr/bufferhub_rpc.h>
 #include "consumer_channel.h"
+#include "detached_buffer_channel.h"
 #include "producer_channel.h"
 #include "producer_queue_channel.h"
 
@@ -62,8 +64,6 @@
   stream << std::setw(18) << "Signaled";
   stream << " ";
   stream << std::setw(10) << "Index";
-  stream << " ";
-  stream << "Name";
   stream << std::endl;
 
   for (const auto& channel : channels) {
@@ -100,8 +100,41 @@
       stream << std::dec << std::setfill(' ');
       stream << " ";
       stream << std::setw(8) << info.index;
+      stream << std::endl;
+    }
+
+    if (channel->channel_type() == BufferHubChannel::kDetachedBufferType) {
+      BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
+
+      stream << std::right;
+      stream << std::setw(6) << info.id;
       stream << " ";
-      stream << info.name;
+      stream << std::setw(9) << "N/A";
+      stream << " ";
+      if (info.format == HAL_PIXEL_FORMAT_BLOB) {
+        std::string size = std::to_string(info.width) + " B";
+        stream << std::setw(14) << size;
+      } else {
+        std::string dimensions = std::to_string(info.width) + "x" +
+                                 std::to_string(info.height) + "x" +
+                                 std::to_string(info.layer_count);
+        stream << std::setw(14) << dimensions;
+      }
+      stream << " ";
+      stream << std::setw(6) << info.format;
+      stream << " ";
+      stream << "0x" << std::hex << std::setfill('0');
+      stream << std::setw(8) << info.usage;
+      stream << std::dec << std::setfill(' ');
+      stream << " ";
+      stream << std::setw(9) << "N/A";
+      stream << " ";
+      stream << std::hex << std::setfill(' ');
+      stream << std::setw(18) << "Detached";
+      stream << " ";
+      stream << std::setw(18) << "N/A";
+      stream << " ";
+      stream << std::setw(10) << "N/A";
       stream << std::endl;
     }
   }
@@ -166,9 +199,7 @@
   stream << std::right;
   stream << std::setw(6) << "Id";
   stream << " ";
-  stream << std::setw(14) << "Geometry";
-  stream << " ";
-  stream << "Name";
+  stream << std::setw(14) << "Info";
   stream << std::endl;
 
   for (const auto& channel : channels) {
@@ -216,14 +247,9 @@
           *this, &BufferHubService::OnCreateBuffer, message);
       return {};
 
-    case BufferHubRPC::CreatePersistentBuffer::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
-          *this, &BufferHubService::OnCreatePersistentBuffer, message);
-      return {};
-
-    case BufferHubRPC::GetPersistentBuffer::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::GetPersistentBuffer>(
-          *this, &BufferHubService::OnGetPersistentBuffer, message);
+    case DetachedBufferRPC::Create::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Create>(
+          *this, &BufferHubService::OnCreateDetachedBuffer, message);
       return {};
 
     case BufferHubRPC::CreateProducerQueue::Opcode:
@@ -231,17 +257,28 @@
           *this, &BufferHubService::OnCreateProducerQueue, message);
       return {};
 
+    case BufferHubRPC::ProducerBufferDetach::Opcode:
+      // In addition to the message handler in the ProducerChannel's
+      // HandleMessage method, we also need to invalid the producer channel (and
+      // all associated consumer channels). Note that this has to be done after
+      // HandleMessage returns to make sure the IPC request has went back to the
+      // client first.
+      SetChannel(channel->channel_id(), nullptr);
+      return {};
+
+    case DetachedBufferRPC::Promote::Opcode:
+      // In addition to the message handler in the DetachedBufferChannel's
+      // HandleMessage method, we also need to invalid the channel. Note that
+      // this has to be done after HandleMessage returns to make sure the IPC
+      // request has went back to the client first.
+      SetChannel(channel->channel_id(), nullptr);
+      return {};
+
     default:
       return DefaultHandleMessage(message);
   }
 }
 
-void BufferHubService::OnChannelClose(Message&,
-                                      const std::shared_ptr<Channel>& channel) {
-  if (auto buffer = std::static_pointer_cast<BufferHubChannel>(channel))
-    buffer->Detach();
-}
-
 Status<void> BufferHubService::OnCreateBuffer(Message& message, uint32_t width,
                                               uint32_t height, uint32_t format,
                                               uint64_t usage,
@@ -273,115 +310,41 @@
   }
 }
 
-Status<void> BufferHubService::OnCreatePersistentBuffer(
-    Message& message, const std::string& name, int user_id, int group_id,
-    uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
-    size_t meta_size_bytes) {
-  const uint32_t kDefaultLayerCount = 1;
-  const int channel_id = message.GetChannelId();
+pdx::Status<void> BufferHubService::OnCreateDetachedBuffer(
+    pdx::Message& message, uint32_t width, uint32_t height,
+    uint32_t layer_count, uint32_t format, uint64_t usage,
+    size_t user_metadata_size) {
+  // Use the producer channel id as the global buffer id.
+  const int buffer_id = message.GetChannelId();
   ALOGD_IF(TRACE,
-           "BufferHubService::OnCreatePersistentBuffer: channel_id=%d name=%s "
-           "user_id=%d group_id=%d width=%u height=%u format=%u "
-           "usage=%" PRIx64 " meta_size_bytes=%zu",
-           channel_id, name.c_str(), user_id, group_id, width, height, format,
-           usage, meta_size_bytes);
+           "BufferHubService::OnCreateDetachedBuffer: buffer_id=%d width=%u "
+           "height=%u layer_count=%u format=%u usage=%" PRIx64
+           " user_metadata_size=%zu",
+           buffer_id, width, height, layer_count, format, usage,
+           user_metadata_size);
 
   // See if this channel is already attached to a buffer.
   if (const auto channel = message.GetChannel<BufferHubChannel>()) {
     ALOGE(
-        "BufferHubService::OnCreatePersistentBuffer: Channel already attached "
-        "to buffer: channel_id=%d buffer_id=%d",
-        channel_id, channel->buffer_id());
+        "BufferHubService::OnCreateDetachedBuffer: Buffer already created: "
+        "buffer=%d",
+        buffer_id);
     return ErrorStatus(EALREADY);
   }
 
-  const int euid = message.GetEffectiveUserId();
-  const int egid = message.GetEffectiveGroupId();
-
-  if (auto buffer = GetNamedBuffer(name)) {
-    if (!buffer->CheckAccess(euid, egid)) {
-      ALOGE(
-          "BufferHubService::OnCreatePersistentBuffer: Requesting process does "
-          "not have permission to access named buffer: name=%s euid=%d egid=%d",
-          name.c_str(), euid, euid);
-      return ErrorStatus(EPERM);
-    } else if (!buffer->CheckParameters(width, height, kDefaultLayerCount,
-                                        format, usage, meta_size_bytes)) {
-      ALOGE(
-          "BufferHubService::OnCreatePersistentBuffer: Requested an existing "
-          "buffer with different parameters: name=%s",
-          name.c_str());
-      return ErrorStatus(EINVAL);
-    } else if (!buffer->IsDetached()) {
-      ALOGE(
-          "BufferHubService::OnCreatePersistentBuffer: Requesting a persistent "
-          "buffer that is already attached to a channel: name=%s",
-          name.c_str());
-      return ErrorStatus(EINVAL);
-    } else {
-      buffer->Attach(channel_id);
-      message.SetChannel(buffer);
-      return {};
-    }
-  } else {
-    auto status = ProducerChannel::Create(this, channel_id, width, height,
-                                          kDefaultLayerCount, format, usage,
-                                          meta_size_bytes);
-    if (!status) {
-      ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
-      return status.error_status();
-    }
-    auto persistent_buffer = status.take();
-    auto make_persistent_status = persistent_buffer->OnProducerMakePersistent(
-        message, name, user_id, group_id);
-    if (make_persistent_status)
-      message.SetChannel(persistent_buffer);
-    return make_persistent_status;
-  }
-}
-
-Status<void> BufferHubService::OnGetPersistentBuffer(Message& message,
-                                                     const std::string& name) {
-  const int channel_id = message.GetChannelId();
-  ALOGD_IF(TRACE,
-           "BufferHubService::OnGetPersistentBuffer: channel_id=%d name=%s",
-           channel_id, name.c_str());
-
-  // See if this channel is already attached to a buffer.
-  if (const auto channel = message.GetChannel<BufferHubChannel>()) {
+  std::unique_ptr<DetachedBufferChannel> channel =
+      DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
+                                    format, usage, user_metadata_size);
+  if (!channel) {
     ALOGE(
-        "BufferHubService::OnGetPersistentBuffer: Channel already attached to "
-        "buffer: channel_id=%d buffer_id=%d",
-        channel_id, channel->buffer_id());
-    return ErrorStatus(EALREADY);
+        "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
+        "buffer=%d.",
+        buffer_id);
+    return ErrorStatus(ENOMEM);
   }
 
-  const int euid = message.GetEffectiveUserId();
-  const int egid = message.GetEffectiveGroupId();
-
-  if (auto buffer = GetNamedBuffer(name)) {
-    if (!buffer->CheckAccess(euid, egid)) {
-      ALOGE(
-          "BufferHubService::OnGetPersistentBuffer: Requesting process does "
-          "not have permission to access named buffer: name=%s euid=%d egid=%d",
-          name.c_str(), euid, egid);
-      return ErrorStatus(EPERM);
-    } else if (!buffer->IsDetached()) {
-      ALOGE(
-          "BufferHubService::OnGetPersistentBuffer: Requesting a persistent "
-          "buffer that is already attached to a channel: name=%s",
-          name.c_str());
-      return ErrorStatus(EINVAL);
-    } else {
-      buffer->Attach(channel_id);
-      message.SetChannel(buffer);
-      return {};
-    }
-  } else {
-    ALOGE("BufferHubService::OnGetPersistentBuffer: Buffer \"%s\" not found!",
-          name.c_str());
-    return ErrorStatus(ENOENT);
-  }
+  message.SetChannel(std::move(channel));
+  return {};
 }
 
 Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
@@ -410,52 +373,17 @@
   }
 }
 
-bool BufferHubService::AddNamedBuffer(
-    const std::string& name, const std::shared_ptr<ProducerChannel>& buffer) {
-  auto search = named_buffers_.find(name);
-  if (search == named_buffers_.end()) {
-    named_buffers_.emplace(name, buffer);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-std::shared_ptr<ProducerChannel> BufferHubService::GetNamedBuffer(
-    const std::string& name) {
-  auto search = named_buffers_.find(name);
-  if (search != named_buffers_.end())
-    return search->second;
-  else
-    return nullptr;
-}
-
-bool BufferHubService::RemoveNamedBuffer(const ProducerChannel& buffer) {
-  for (auto it = named_buffers_.begin(); it != named_buffers_.end();) {
-    if (it->second.get() == &buffer) {
-      named_buffers_.erase(it);
-      return true;
-    }
-    ++it;
-  }
-  return false;
-}
-
 void BufferHubChannel::SignalAvailable() {
   ATRACE_NAME("BufferHubChannel::SignalAvailable");
   ALOGD_IF(TRACE,
            "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
-  if (!IsDetached()) {
-    signaled_ = true;
-    const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
-    ALOGE_IF(!status,
-             "BufferHubChannel::SignalAvailable: failed to signal availability "
-             "channel_id=%d: %s",
-             channel_id_, status.GetErrorMessage().c_str());
-  } else {
-    ALOGD_IF(TRACE, "BufferHubChannel::SignalAvailable: detached buffer.");
-  }
+  signaled_ = true;
+  const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
+  ALOGE_IF(!status,
+           "BufferHubChannel::SignalAvailable: failed to signal availability "
+           "channel_id=%d: %s",
+           channel_id_, status.GetErrorMessage().c_str());
 }
 
 void BufferHubChannel::ClearAvailable() {
@@ -463,31 +391,23 @@
   ALOGD_IF(TRACE,
            "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
-  if (!IsDetached()) {
-    signaled_ = false;
-    const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
-    ALOGE_IF(!status,
-             "BufferHubChannel::ClearAvailable: failed to clear availability "
-             "channel_id=%d: %s",
-             channel_id_, status.GetErrorMessage().c_str());
-  } else {
-    ALOGD_IF(TRACE, "BufferHubChannel::ClearAvailable: detached buffer.");
-  }
+  signaled_ = false;
+  const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
+  ALOGE_IF(!status,
+           "BufferHubChannel::ClearAvailable: failed to clear availability "
+           "channel_id=%d: %s",
+           channel_id_, status.GetErrorMessage().c_str());
 }
 
 void BufferHubChannel::Hangup() {
   ATRACE_NAME("BufferHubChannel::Hangup");
   ALOGD_IF(TRACE, "BufferHubChannel::Hangup: channel_id=%d buffer_id=%d",
            channel_id(), buffer_id());
-  if (!IsDetached()) {
-    const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP);
-    ALOGE_IF(
-        !status,
-        "BufferHubChannel::Hangup: failed to signal hangup channel_id=%d: %s",
-        channel_id_, status.GetErrorMessage().c_str());
-  } else {
-    ALOGD_IF(TRACE, "BufferHubChannel::Hangup: detached buffer.");
-  }
+  const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP);
+  ALOGE_IF(
+      !status,
+      "BufferHubChannel::Hangup: failed to signal hangup channel_id=%d: %s",
+      channel_id_, status.GetErrorMessage().c_str());
 }
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index 270ac95..e47ffa3 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -23,12 +23,11 @@
   enum ChannelType {
     kProducerType,
     kConsumerType,
+    kDetachedBufferType,
     kProducerQueueType,
     kConsumerQueueType,
   };
 
-  enum : int { kDetachedId = -1 };
-
   BufferHubChannel(BufferHubService* service, int buffer_id, int channel_id,
                    ChannelType channel_type)
       : service_(service),
@@ -57,7 +56,6 @@
     uint64_t state = 0;
     uint64_t signaled_mask = 0;
     uint64_t index = 0;
-    std::string name;
 
     // Data filed for producer queue.
     size_t capacity = 0;
@@ -66,7 +64,7 @@
     BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height,
                uint32_t layer_count, uint32_t format, uint64_t usage,
                size_t pending_count, uint64_t state, uint64_t signaled_mask,
-               uint64_t index, const std::string& name)
+               uint64_t index)
         : id(id),
           type(kProducerType),
           consumer_count(consumer_count),
@@ -78,8 +76,7 @@
           pending_count(pending_count),
           state(state),
           signaled_mask(signaled_mask),
-          index(index),
-          name(name) {}
+          index(index) {}
 
     BufferInfo(int id, size_t consumer_count, size_t capacity,
                const UsagePolicy& usage_policy)
@@ -109,19 +106,9 @@
   int buffer_id() const { return buffer_id_; }
 
   int channel_id() const { return channel_id_; }
-  bool IsDetached() const { return channel_id_ == kDetachedId; }
 
   bool signaled() const { return signaled_; }
 
-  void Detach() {
-    if (channel_type_ == kProducerType)
-      channel_id_ = kDetachedId;
-  }
-  void Attach(int channel_id) {
-    if (channel_type_ == kProducerType && channel_id_ == kDetachedId)
-      channel_id_ = channel_id;
-  }
-
  private:
   BufferHubService* service_;
 
@@ -132,8 +119,7 @@
   // general because channel ids are not used for any lookup in this service.
   int buffer_id_;
 
-  // The channel id of the buffer. This may change for a persistent producer
-  // buffer if it is detached and re-attached to another channel.
+  // The channel id of the buffer.
   int channel_id_;
 
   bool signaled_;
@@ -152,34 +138,20 @@
   pdx::Status<void> HandleMessage(pdx::Message& message) override;
   void HandleImpulse(pdx::Message& message) override;
 
-  void OnChannelClose(pdx::Message& message,
-                      const std::shared_ptr<pdx::Channel>& channel) override;
-
   bool IsInitialized() const override;
   std::string DumpState(size_t max_length) override;
 
-  bool AddNamedBuffer(const std::string& name,
-                      const std::shared_ptr<ProducerChannel>& buffer);
-  std::shared_ptr<ProducerChannel> GetNamedBuffer(const std::string& name);
-  bool RemoveNamedBuffer(const ProducerChannel& buffer);
-
  private:
   friend BASE;
 
-  std::unordered_map<std::string, std::shared_ptr<ProducerChannel>>
-      named_buffers_;
-
   pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width,
                                    uint32_t height, uint32_t format,
                                    uint64_t usage, size_t meta_size_bytes);
-  pdx::Status<void> OnCreatePersistentBuffer(pdx::Message& message,
-                                             const std::string& name,
-                                             int user_id, int group_id,
-                                             uint32_t width, uint32_t height,
-                                             uint32_t format, uint64_t usage,
-                                             size_t meta_size_bytes);
-  pdx::Status<void> OnGetPersistentBuffer(pdx::Message& message,
-                                          const std::string& name);
+  pdx::Status<void> OnCreateDetachedBuffer(pdx::Message& message,
+                                           uint32_t width, uint32_t height,
+                                           uint32_t layer_count,
+                                           uint32_t format, uint64_t usage,
+                                           size_t user_metadata_size);
   pdx::Status<QueueInfo> OnCreateProducerQueue(
       pdx::Message& message, const ProducerQueueConfig& producer_config,
       const UsagePolicy& usage_policy);
diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc
index 46fe5f9..c470de5 100644
--- a/services/vr/bufferhubd/bufferhubd.rc
+++ b/services/vr/bufferhubd/bufferhubd.rc
@@ -2,5 +2,4 @@
   class core
   user system
   group system
-  writepid /dev/cpuset/tasks
   socket pdx/system/buffer_hub/client stream 0660 system system u:object_r:pdx_bufferhub_client_endpoint_socket:s0
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
new file mode 100644
index 0000000..a5cf68d
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -0,0 +1,159 @@
+#include "detached_buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
+                                             int buffer_id, int channel_id,
+                                             IonBuffer buffer,
+                                             IonBuffer metadata_buffer,
+                                             size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+      buffer_(std::move(buffer)),
+      metadata_buffer_(std::move(metadata_buffer)),
+      user_metadata_size_(user_metadata_size) {
+}
+
+DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
+                                             int buffer_id, uint32_t width,
+                                             uint32_t height,
+                                             uint32_t layer_count,
+                                             uint32_t format, uint64_t usage,
+                                             size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+      user_metadata_size_(user_metadata_size) {
+  // The size the of metadata buffer is used as the "width" parameter during
+  // allocation. Thus it cannot overflow uint32_t.
+  if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
+                              BufferHubDefs::kMetadataHeaderSize)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
+    return;
+  }
+
+  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+        "buffer: %s",
+        strerror(-ret));
+    return;
+  }
+
+  // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
+  // user requested metadata.
+  const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
+  if (int ret = metadata_buffer_.Alloc(size,
+                                       /*height=*/1,
+                                       /*layer_count=*/1,
+                                       BufferHubDefs::kMetadataFormat,
+                                       BufferHubDefs::kMetadataUsage)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+        "metadata: %s",
+        strerror(-ret));
+    return;
+  }
+}
+
+DetachedBufferChannel::~DetachedBufferChannel() {
+  ALOGD_IF(TRACE,
+           "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
+           "buffer_id=%d.",
+           channel_id(), buffer_id());
+  Hangup();
+}
+
+BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
+  return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
+                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
+                    buffer_.usage(), /*pending_count=*/0, /*state=*/0,
+                    /*signaled_mask=*/0, /*index=*/0);
+}
+
+void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
+  ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
+}
+
+bool DetachedBufferChannel::HandleMessage(Message& message) {
+  ATRACE_NAME("DetachedBufferChannel::HandleMessage");
+  switch (message.GetOp()) {
+    case DetachedBufferRPC::Import::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Import>(
+          *this, &DetachedBufferChannel::OnImport, message);
+      return true;
+
+    case DetachedBufferRPC::Promote::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+          *this, &DetachedBufferChannel::OnPromote, message);
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
+    Message& /*message*/) {
+  ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
+  ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
+           buffer_id());
+
+  return BufferDescription<BorrowedHandle>{buffer_,
+                                           metadata_buffer_,
+                                           buffer_id(),
+                                           /*buffer_state_bit=*/0,
+                                           BorrowedHandle{},
+                                           BorrowedHandle{}};
+}
+
+Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
+    Message& message) {
+  ATRACE_NAME("DetachedBufferChannel::OnPromote");
+  ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
+           buffer_id());
+
+  // Note that the new ProducerChannel will have different channel_id, but
+  // inherits the buffer_id from the DetachedBuffer.
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+      service(), buffer_id(), channel_id, std::move(buffer_),
+      std::move(metadata_buffer_), user_metadata_size_);
+  if (!channel) {
+    ALOGE(
+        "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
+        "from a DetachedBufferChannel, buffer_id=%d.",
+        buffer_id());
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
+        "channel: %s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
new file mode 100644
index 0000000..8b6dab8
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.h
@@ -0,0 +1,63 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class DetachedBufferChannel : public BufferHubChannel {
+ public:
+  ~DetachedBufferChannel() override;
+
+  template <typename... Args>
+  static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
+    auto buffer = std::unique_ptr<DetachedBufferChannel>(
+        new DetachedBufferChannel(std::forward<Args>(args)...));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
+  }
+
+  // Returns whether the object holds a valid graphic buffer.
+  bool IsValid() const {
+    return buffer_.IsValid() && metadata_buffer_.IsValid();
+  }
+
+  size_t user_metadata_size() const { return user_metadata_size_; }
+
+  // Captures buffer info for use by BufferHubService::DumpState().
+  BufferInfo GetBufferInfo() const override;
+
+  bool HandleMessage(pdx::Message& message) override;
+  void HandleImpulse(pdx::Message& message) override;
+
+ private:
+  // Creates a detached buffer from existing IonBuffers.
+  DetachedBufferChannel(BufferHubService* service, int buffer_id,
+                        int channel_id, IonBuffer buffer,
+                        IonBuffer metadata_buffer, size_t user_metadata_size);
+
+  // Allocates a new detached buffer.
+  DetachedBufferChannel(BufferHubService* service, int buffer_id,
+                        uint32_t width, uint32_t height, uint32_t layer_count,
+                        uint32_t format, uint64_t usage,
+                        size_t user_metadata_size);
+
+  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+      pdx::Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+  // Gralloc buffer handles.
+  IonBuffer buffer_;
+  IonBuffer metadata_buffer_;
+
+  // Size of user requested metadata.
+  const size_t user_metadata_size_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 716db5e..b6977aa 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -13,6 +13,7 @@
 
 #include <private/dvr/bufferhub_rpc.h>
 #include "consumer_channel.h"
+#include "detached_buffer_channel.h"
 
 using android::pdx::BorrowedHandle;
 using android::pdx::ErrorStatus;
@@ -34,6 +35,30 @@
 
 }  // namespace
 
+ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
+                                 int channel_id, IonBuffer buffer,
+                                 IonBuffer metadata_buffer,
+                                 size_t user_metadata_size, int* error)
+    : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
+      buffer_(std::move(buffer)),
+      metadata_buffer_(std::move(metadata_buffer)),
+      user_metadata_size_(user_metadata_size),
+      metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
+                         user_metadata_size) {
+  if (!buffer_.IsValid()) {
+    ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
+    *error = -EINVAL;
+    return;
+  }
+  if (!metadata_buffer_.IsValid()) {
+    ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
+    *error = -EINVAL;
+    return;
+  }
+
+  *error = InitializeBuffer();
+}
+
 ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
                                  uint32_t width, uint32_t height,
                                  uint32_t layer_count, uint32_t format,
@@ -62,13 +87,16 @@
     return;
   }
 
+  *error = InitializeBuffer();
+}
+
+int ProducerChannel::InitializeBuffer() {
   void* metadata_ptr = nullptr;
   if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
                                       /*y=*/0, metadata_buf_size_,
                                       /*height=*/1, &metadata_ptr)) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
-    *error = -ret;
-    return;
+    return ret;
   }
   metadata_header_ =
       reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
@@ -84,15 +112,13 @@
   release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!acquire_fence_fd_ || !release_fence_fd_) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
-    *error = -EIO;
-    return;
+    return -EIO;
   }
 
   dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   if (!dummy_fence_fd_) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
-    *error = -EIO;
-    return;
+    return EIO;
   }
 
   epoll_event event;
@@ -104,12 +130,25 @@
         "ProducerChannel::ProducerChannel: Failed to modify the shared "
         "release fence to include the dummy fence: %s",
         strerror(errno));
-    *error = -EIO;
-    return;
+    return -EIO;
   }
 
   // Success.
-  *error = 0;
+  return 0;
+}
+
+std::unique_ptr<ProducerChannel> ProducerChannel::Create(
+    BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
+    IonBuffer metadata_buffer, size_t user_metadata_size) {
+  int error = 0;
+  std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
+      service, buffer_id, channel_id, std::move(buffer),
+      std::move(metadata_buffer), user_metadata_size, &error));
+
+  if (error < 0)
+    return nullptr;
+  else
+    return producer;
 }
 
 Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
@@ -131,8 +170,10 @@
            "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
            "state=%" PRIx64 ".",
            channel_id(), buffer_id(), buffer_state_->load());
-  for (auto consumer : consumer_channels_)
+  for (auto consumer : consumer_channels_) {
     consumer->OnProducerClosed();
+  }
+  Hangup();
 }
 
 BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
@@ -145,7 +186,7 @@
   return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
                     buffer_.height(), buffer_.layer_count(), buffer_.format(),
                     buffer_.usage(), pending_consumers_, buffer_state_->load(),
-                    signaled_mask, metadata_header_->queue_index, name_);
+                    signaled_mask, metadata_header_->queue_index);
 }
 
 void ProducerChannel::HandleImpulse(Message& message) {
@@ -183,14 +224,9 @@
           *this, &ProducerChannel::OnProducerGain, message);
       return true;
 
-    case BufferHubRPC::ProducerMakePersistent::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
-          *this, &ProducerChannel::OnProducerMakePersistent, message);
-      return true;
-
-    case BufferHubRPC::ProducerRemovePersistence::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
-          *this, &ProducerChannel::OnRemovePersistence, message);
+    case BufferHubRPC::ProducerBufferDetach::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
+          *this, &ProducerChannel::OnProducerDetach, message);
       return true;
 
     default:
@@ -347,6 +383,61 @@
   return {std::move(returned_fence_)};
 }
 
+Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+    Message& message) {
+  ATRACE_NAME("ProducerChannel::OnProducerDetach");
+  ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
+           buffer_id());
+
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a BufferProducer when it's in gained state.
+    ALOGW(
+        "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
+        ") is not in gained state.",
+        buffer_id(), buffer_state);
+    return {};
+  }
+
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
+        "channel: %s",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  // Make sure we unlock the buffer.
+  if (int ret = metadata_buffer_.Unlock()) {
+    ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
+    return ErrorStatus(-ret);
+  };
+
+  std::unique_ptr<DetachedBufferChannel> channel =
+      DetachedBufferChannel::Create(
+          service(), buffer_id(), channel_id, std::move(buffer_),
+          std::move(metadata_buffer_), user_metadata_size_);
+  if (!channel) {
+    ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
+    return ErrorStatus(EINVAL);
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
+        "channel: %s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
 Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
@@ -459,50 +550,6 @@
       buffer_state_->load(), fence_state_->load());
 }
 
-Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
-                                                       const std::string& name,
-                                                       int user_id,
-                                                       int group_id) {
-  ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
-  ALOGD_IF(TRACE,
-           "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
-           "user_id=%d group_id=%d",
-           buffer_id(), name.c_str(), user_id, group_id);
-
-  if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
-      (group_id < 0 && group_id != kNoCheckId)) {
-    return ErrorStatus(EINVAL);
-  }
-
-  // Try to add this buffer with the requested name.
-  if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
-                                          shared_from_this()))) {
-    // If successful, set the requested permissions.
-
-    // A value of zero indicates that the ids from the sending process should be
-    // used.
-    if (user_id == kUseCallerId)
-      user_id = message.GetEffectiveUserId();
-    if (group_id == kUseCallerId)
-      group_id = message.GetEffectiveGroupId();
-
-    owner_user_id_ = user_id;
-    owner_group_id_ = group_id;
-    name_ = name;
-    return {};
-  } else {
-    // Otherwise a buffer with that name already exists.
-    return ErrorStatus(EALREADY);
-  }
-}
-
-Status<void> ProducerChannel::OnRemovePersistence(Message&) {
-  if (service()->RemoveNamedBuffer(*this))
-    return {};
-  else
-    return ErrorStatus(ENOENT);
-}
-
 void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
   consumer_channels_.push_back(channel);
 }
@@ -546,16 +593,6 @@
   }
 }
 
-// Returns true if either the user or group ids match the owning ids or both
-// owning ids are not set, in which case access control does not apply.
-bool ProducerChannel::CheckAccess(int euid, int egid) {
-  const bool no_check =
-      owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
-  const bool euid_check = euid == owner_user_id_ || euid == kRootId;
-  const bool egid_check = egid == owner_group_id_ || egid == kRootId;
-  return no_check || euid_check || egid_check;
-}
-
 // Returns true if the given parameters match the underlying buffer parameters.
 bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
                                       uint32_t layer_count, uint32_t format,
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index e280f4d..67fdf15 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -30,6 +30,12 @@
   template <typename T>
   using BufferWrapper = pdx::rpc::BufferWrapper<T>;
 
+  static std::unique_ptr<ProducerChannel> Create(BufferHubService* service,
+                                                 int buffer_id, int channel_id,
+                                                 IonBuffer buffer,
+                                                 IonBuffer metadata_buffer,
+                                                 size_t user_metadata_size);
+
   static pdx::Status<std::shared_ptr<ProducerChannel>> Create(
       BufferHubService* service, int channel_id, uint32_t width,
       uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage,
@@ -57,16 +63,10 @@
   void AddConsumer(ConsumerChannel* channel);
   void RemoveConsumer(ConsumerChannel* channel);
 
-  bool CheckAccess(int euid, int egid);
   bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count,
                        uint32_t format, uint64_t usage,
                        size_t user_metadata_size);
 
-  pdx::Status<void> OnProducerMakePersistent(Message& message,
-                                             const std::string& name,
-                                             int user_id, int group_id);
-  pdx::Status<void> OnRemovePersistence(Message& message);
-
  private:
   std::vector<ConsumerChannel*> consumer_channels_;
   // This counts the number of consumers left to process this buffer. If this is
@@ -98,23 +98,18 @@
   pdx::LocalHandle release_fence_fd_;
   pdx::LocalHandle dummy_fence_fd_;
 
-  static constexpr int kNoCheckId = -1;
-  static constexpr int kUseCallerId = 0;
-  static constexpr int kRootId = 0;
-
-  // User and group id to check when obtaining a persistent buffer.
-  int owner_user_id_ = kNoCheckId;
-  int owner_group_id_ = kNoCheckId;
-
-  std::string name_;
-
+  ProducerChannel(BufferHubService* service, int buffer_id, int channel_id,
+                  IonBuffer buffer, IonBuffer metadata_buffer,
+                  size_t user_metadata_size, int* error);
   ProducerChannel(BufferHubService* service, int channel, uint32_t width,
                   uint32_t height, uint32_t layer_count, uint32_t format,
                   uint64_t usage, size_t user_metadata_size, int* error);
 
+  int InitializeBuffer();
   pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
   pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
   pdx::Status<LocalFence> OnProducerGain(Message& message);
+  pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
 
   ProducerChannel(const ProducerChannel&) = delete;
   void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 9201520..90edf69 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -8,11 +8,7 @@
 
   static_libs: [
     "libbroadcastring",
-    "libhwcomposer-client",
     "libdisplay",
-    "libbufferhubqueue",
-    "libbufferhub",
-    "libpdx_default_transport",
   ],
 
   shared_libs: [
@@ -20,6 +16,8 @@
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.mapper@2.0",
     "libbase",
+    "libbufferhubqueue",
+    "libbinder",
     "libcutils",
     "libfmq",
     "libhardware",
@@ -29,10 +27,16 @@
     "libsync",
     "libui",
     "libutils",
+    "libpdx_default_transport",
   ],
 
-  export_static_lib_headers: [
-    "libhwcomposer-client",
+  header_libs: [
+    "android.hardware.graphics.composer@2.1-command-buffer",
+    "android.hardware.graphics.composer@2.1-hal",
+  ],
+
+  export_header_lib_headers: [
+    "android.hardware.graphics.composer@2.1-hal",
   ],
 
   export_shared_lib_headers: [
@@ -44,6 +48,13 @@
 
   cflags: [
     "-DLOG_TAG=\"vr_hwc\"",
+    "-Wall",
+    "-Werror",
+    // mVrClient unused in vr_composer_client.cpp
+    "-Wno-error=unused-private-field",
+    // Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
+    "-Wno-sign-compare",
+    "-Wno-unused-parameter",
   ],
 
 }
@@ -63,6 +74,11 @@
   },
   export_include_dirs: ["aidl"],
 
+  cflags: [
+    "-Wall",
+    "-Werror",
+  ],
+
   shared_libs: [
     "libbinder",
     "libui",
@@ -92,6 +108,8 @@
   ],
   cflags: [
     "-DLOG_TAG=\"vr_hwc\"",
+    "-Wall",
+    "-Werror",
   ],
 }
 
@@ -120,6 +138,8 @@
   ],
   cflags: [
     "-DLOG_TAG=\"vr_hwc\"",
+    "-Wall",
+    "-Werror",
   ],
   init_rc: [
     "vr_hwc.rc",
@@ -137,6 +157,13 @@
     // symbols in the *-binder library get optimized out.
     "libvr_hwc-binder",
   ],
+  cflags: [
+    "-Wall",
+    "-Werror",
+    // warnings in vr_composer_test.cpp to be fixed after merge of goog/master
+    "-Wno-sign-compare",
+    "-Wno-unused-parameter",
+  ],
   shared_libs: [
     "libbase",
     "libbinder",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index abe571a..4b90031 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -24,84 +24,52 @@
 
 namespace android {
 namespace dvr {
-namespace {
 
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::frameworks::vr::composer::V1_0::IVrComposerClient;
 
-class ComposerClientImpl : public ComposerClient {
- public:
-  ComposerClientImpl(android::dvr::VrHwc& hal);
-  virtual ~ComposerClientImpl();
-
- private:
-  class VrCommandReader : public ComposerClient::CommandReader {
-   public:
-    VrCommandReader(ComposerClientImpl& client);
-    ~VrCommandReader() override;
-
-    bool parseCommand(IComposerClient::Command command,
-                      uint16_t length) override;
-
-   private:
-    bool parseSetLayerInfo(uint16_t length);
-    bool parseSetClientTargetMetadata(uint16_t length);
-    bool parseSetLayerBufferMetadata(uint16_t length);
-
-    IVrComposerClient::BufferMetadata readBufferMetadata();
-
-    ComposerClientImpl& mVrClient;
-    android::dvr::VrHwc& mVrHal;
-
-    VrCommandReader(const VrCommandReader&) = delete;
-    void operator=(const VrCommandReader&) = delete;
-  };
-
-  std::unique_ptr<CommandReader> createCommandReader() override;
-
-  dvr::VrHwc& mVrHal;
-
-  ComposerClientImpl(const ComposerClientImpl&) = delete;
-  void operator=(const ComposerClientImpl&) = delete;
-};
-
-ComposerClientImpl::ComposerClientImpl(android::dvr::VrHwc& hal)
-    : ComposerClient(hal), mVrHal(hal) {}
-
-ComposerClientImpl::~ComposerClientImpl() {}
-
-std::unique_ptr<ComposerClient::CommandReader>
-ComposerClientImpl::createCommandReader() {
-  return std::unique_ptr<CommandReader>(new VrCommandReader(*this));
+VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
+    : ComposerClient(&hal), mVrHal(hal) {
+  if (!init()) {
+      LOG_ALWAYS_FATAL("failed to initialize VrComposerClient");
+  }
 }
 
-ComposerClientImpl::VrCommandReader::VrCommandReader(ComposerClientImpl& client)
-    : CommandReader(client), mVrClient(client), mVrHal(client.mVrHal) {}
+VrComposerClient::~VrComposerClient() {}
 
-ComposerClientImpl::VrCommandReader::~VrCommandReader() {}
+std::unique_ptr<ComposerCommandEngine>
+VrComposerClient::createCommandEngine() {
+  return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+}
 
-bool ComposerClientImpl::VrCommandReader::parseCommand(
+VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
+    : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+      mVrHal(client.mVrHal) {}
+
+VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
+
+bool VrComposerClient::VrCommandEngine::executeCommand(
     IComposerClient::Command command, uint16_t length) {
   IVrComposerClient::VrCommand vrCommand =
       static_cast<IVrComposerClient::VrCommand>(command);
   switch (vrCommand) {
     case IVrComposerClient::VrCommand::SET_LAYER_INFO:
-      return parseSetLayerInfo(length);
+      return executeSetLayerInfo(length);
     case IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA:
-      return parseSetClientTargetMetadata(length);
+      return executeSetClientTargetMetadata(length);
     case IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA:
-      return parseSetLayerBufferMetadata(length);
+      return executeSetLayerBufferMetadata(length);
     default:
-      return CommandReader::parseCommand(command, length);
+      return ComposerCommandEngine::executeCommand(command, length);
   }
 }
 
-bool ComposerClientImpl::VrCommandReader::parseSetLayerInfo(uint16_t length) {
+bool VrComposerClient::VrCommandEngine::executeSetLayerInfo(uint16_t length) {
   if (length != 2) {
     return false;
   }
 
-  auto err = mVrHal.setLayerInfo(mDisplay, mLayer, read(), read());
+  auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read());
   if (err != Error::NONE) {
     mWriter.setError(getCommandLoc(), err);
   }
@@ -109,24 +77,24 @@
   return true;
 }
 
-bool ComposerClientImpl::VrCommandReader::parseSetClientTargetMetadata(
+bool VrComposerClient::VrCommandEngine::executeSetClientTargetMetadata(
     uint16_t length) {
   if (length != 7)
     return false;
 
-  auto err = mVrHal.setClientTargetMetadata(mDisplay, readBufferMetadata());
+  auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata());
   if (err != Error::NONE)
     mWriter.setError(getCommandLoc(), err);
 
   return true;
 }
 
-bool ComposerClientImpl::VrCommandReader::parseSetLayerBufferMetadata(
+bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata(
     uint16_t length) {
   if (length != 7)
     return false;
 
-  auto err = mVrHal.setLayerBufferMetadata(mDisplay, mLayer,
+  auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer,
                                            readBufferMetadata());
   if (err != Error::NONE)
     mWriter.setError(getCommandLoc(), err);
@@ -135,7 +103,7 @@
 }
 
 IVrComposerClient::BufferMetadata
-ComposerClientImpl::VrCommandReader::readBufferMetadata() {
+VrComposerClient::VrCommandEngine::readBufferMetadata() {
   IVrComposerClient::BufferMetadata metadata = {
     .width = read(),
     .height = read(),
@@ -147,136 +115,5 @@
   return metadata;
 }
 
-}  // namespace
-
-VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
-    : client_(new ComposerClientImpl(hal)) {
-  client_->initialize();
-}
-
-VrComposerClient::~VrComposerClient() {}
-
-void VrComposerClient::onHotplug(Display display,
-    IComposerCallback::Connection connected) {
-  client_->onHotplug(display, connected);
-}
-
-void VrComposerClient::onRefresh(Display display) {
-  client_->onRefresh(display);
-}
-
-Return<void> VrComposerClient::registerCallback(
-    const sp<IComposerCallback>& callback) {
-  return client_->registerCallback(callback);
-}
-
-Return<uint32_t> VrComposerClient::getMaxVirtualDisplayCount() {
-  return client_->getMaxVirtualDisplayCount();
-}
-
-Return<void> VrComposerClient::createVirtualDisplay(uint32_t width,
-    uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
-    createVirtualDisplay_cb hidl_cb) {
-  return client_->createVirtualDisplay(
-      width, height, formatHint, outputBufferSlotCount, hidl_cb);
-}
-
-Return<Error> VrComposerClient::destroyVirtualDisplay(Display display) {
-  return client_->destroyVirtualDisplay(display);
-}
-
-Return<void> VrComposerClient::createLayer(Display display,
-    uint32_t bufferSlotCount, createLayer_cb hidl_cb) {
-  return client_->createLayer(display, bufferSlotCount, hidl_cb);
-}
-
-Return<Error> VrComposerClient::destroyLayer(Display display, Layer layer) {
-  return client_->destroyLayer(display, layer);
-}
-
-Return<void> VrComposerClient::getActiveConfig(Display display,
-    getActiveConfig_cb hidl_cb) {
-  return client_->getActiveConfig(display, hidl_cb);
-}
-
-Return<Error> VrComposerClient::getClientTargetSupport(Display display,
-    uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) {
-  return client_->getClientTargetSupport(display, width, height, format,
-                                         dataspace);
-}
-
-Return<void> VrComposerClient::getColorModes(Display display,
-    getColorModes_cb hidl_cb) {
-  return client_->getColorModes(display, hidl_cb);
-}
-
-Return<void> VrComposerClient::getDisplayAttribute(Display display,
-    Config config, Attribute attribute, getDisplayAttribute_cb hidl_cb) {
-  return client_->getDisplayAttribute(display, config, attribute, hidl_cb);
-}
-
-Return<void> VrComposerClient::getDisplayConfigs(Display display,
-    getDisplayConfigs_cb hidl_cb) {
-  return client_->getDisplayConfigs(display, hidl_cb);
-}
-
-Return<void> VrComposerClient::getDisplayName(Display display,
-    getDisplayName_cb hidl_cb) {
-  return client_->getDisplayName(display, hidl_cb);
-}
-
-Return<void> VrComposerClient::getDisplayType(Display display,
-    getDisplayType_cb hidl_cb) {
-  return client_->getDisplayType(display, hidl_cb);
-}
-
-Return<void> VrComposerClient::getDozeSupport(
-    Display display, getDozeSupport_cb hidl_cb) {
-  return client_->getDozeSupport(display, hidl_cb);
-}
-
-Return<void> VrComposerClient::getHdrCapabilities(
-    Display display, getHdrCapabilities_cb hidl_cb) {
-  return client_->getHdrCapabilities(display, hidl_cb);
-}
-
-Return<Error> VrComposerClient::setActiveConfig(Display display,
-    Config config) {
-  return client_->setActiveConfig(display, config);
-}
-
-Return<Error> VrComposerClient::setColorMode(Display display, ColorMode mode) {
-  return client_->setColorMode(display, mode);
-}
-
-Return<Error> VrComposerClient::setPowerMode(Display display, PowerMode mode) {
-  return client_->setPowerMode(display, mode);
-}
-
-Return<Error> VrComposerClient::setVsyncEnabled(Display display,
-    Vsync enabled) {
-  return client_->setVsyncEnabled(display, enabled);
-}
-
-Return<Error> VrComposerClient::setClientTargetSlotCount(
-    Display display, uint32_t clientTargetSlotCount) {
-  return client_->setClientTargetSlotCount(display, clientTargetSlotCount);
-}
-
-Return<Error> VrComposerClient::setInputCommandQueue(
-    const hardware::MQDescriptorSync<uint32_t>& descriptor) {
-  return client_->setInputCommandQueue(descriptor);
-}
-
-Return<void> VrComposerClient::getOutputCommandQueue(
-    getOutputCommandQueue_cb hidl_cb) {
-  return client_->getOutputCommandQueue(hidl_cb);
-}
-
-Return<void> VrComposerClient::executeCommands(uint32_t inLength,
-    const hidl_vec<hidl_handle>& inHandles, executeCommands_cb hidl_cb) {
-  return client_->executeCommands(inLength, inHandles, hidl_cb);
-}
-
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index dfc656a..76b1c4f 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -18,74 +18,54 @@
 #define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
 
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <ComposerClient.h>
-#include <IComposerCommandBuffer.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
 
 namespace android {
 namespace dvr {
 
 class VrHwc;
 
-using hardware::graphics::common::V1_0::PixelFormat;
-using hardware::graphics::composer::V2_1::implementation::ComposerClient;
+using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine;
+using hardware::graphics::composer::V2_1::hal::ComposerHal;
+using hardware::graphics::composer::V2_1::hal::detail::ComposerClientImpl;
 
-class VrComposerClient : public IVrComposerClient {
+using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>;
+
+class VrComposerClient : public ComposerClient {
  public:
   VrComposerClient(android::dvr::VrHwc& hal);
   virtual ~VrComposerClient();
 
-  void onHotplug(Display display, IComposerCallback::Connection connected);
-  void onRefresh(Display display);
-
-  // IComposerClient
-  Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
-  Return<uint32_t> getMaxVirtualDisplayCount() override;
-  Return<void> createVirtualDisplay(
-      uint32_t width, uint32_t height, PixelFormat formatHint,
-      uint32_t outputBufferSlotCount, createVirtualDisplay_cb hidl_cb) override;
-  Return<Error> destroyVirtualDisplay(Display display) override;
-  Return<void> createLayer(Display display, uint32_t bufferSlotCount,
-                           createLayer_cb hidl_cb) override;
-  Return<Error> destroyLayer(Display display, Layer layer) override;
-  Return<void> getActiveConfig(Display display,
-                               getActiveConfig_cb hidl_cb) override;
-  Return<Error> getClientTargetSupport(
-      Display display, uint32_t width, uint32_t height, PixelFormat format,
-      Dataspace dataspace) override;
-  Return<void> getColorModes(Display display,
-                             getColorModes_cb hidl_cb) override;
-  Return<void> getDisplayAttribute(
-      Display display, Config config, Attribute attribute,
-      getDisplayAttribute_cb hidl_cb) override;
-  Return<void> getDisplayConfigs(Display display,
-                                 getDisplayConfigs_cb hidl_cb) override;
-  Return<void> getDisplayName(Display display,
-                              getDisplayName_cb hidl_cb) override;
-  Return<void> getDisplayType(Display display,
-                              getDisplayType_cb hidl_cb) override;
-  Return<void> getDozeSupport(Display display,
-                              getDozeSupport_cb hidl_cb) override;
-  Return<void> getHdrCapabilities(Display display,
-                                  getHdrCapabilities_cb hidl_cb) override;
-  Return<Error> setActiveConfig(Display display, Config config) override;
-  Return<Error> setColorMode(Display display, ColorMode mode) override;
-  Return<Error> setPowerMode(Display display, PowerMode mode) override;
-  Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
-  Return<Error> setClientTargetSlotCount(
-      Display display, uint32_t clientTargetSlotCount) override;
-  Return<Error> setInputCommandQueue(
-      const hardware::MQDescriptorSync<uint32_t>& descriptor) override;
-  Return<void> getOutputCommandQueue(
-      getOutputCommandQueue_cb hidl_cb) override;
-  Return<void> executeCommands(
-      uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
-      executeCommands_cb hidl_cb) override;
-
  private:
-  std::unique_ptr<ComposerClient> client_;
+  class VrCommandEngine : public ComposerCommandEngine {
+   public:
+    VrCommandEngine(VrComposerClient& client);
+    ~VrCommandEngine() override;
+
+    bool executeCommand(IComposerClient::Command command,
+                        uint16_t length) override;
+
+   private:
+    bool executeSetLayerInfo(uint16_t length);
+    bool executeSetClientTargetMetadata(uint16_t length);
+    bool executeSetLayerBufferMetadata(uint16_t length);
+
+    IVrComposerClient::BufferMetadata readBufferMetadata();
+
+    VrComposerClient& mVrClient;
+    android::dvr::VrHwc& mVrHal;
+
+    VrCommandEngine(const VrCommandEngine&) = delete;
+    void operator=(const VrCommandEngine&) = delete;
+  };
 
   VrComposerClient(const VrComposerClient&) = delete;
   void operator=(const VrComposerClient&) = delete;
+
+  std::unique_ptr<ComposerCommandEngine> createCommandEngine() override;
+  dvr::VrHwc& mVrHal;
 };
 
 } // namespace dvr
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 5e32af0..4af47d2 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
  */
 #include "impl/vr_hwc.h"
 
+#include "android-base/stringprintf.h"
 #include <cutils/properties.h>
 #include <private/dvr/display_client.h>
 #include <ui/Fence.h>
@@ -26,6 +27,7 @@
 using namespace android::hardware::graphics::common::V1_0;
 using namespace android::hardware::graphics::composer::V2_1;
 
+using android::base::StringPrintf;
 using android::hardware::hidl_handle;
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
@@ -225,6 +227,20 @@
     memcpy(color_transform_, matrix, sizeof(color_transform_));
 }
 
+void HwcDisplay::dumpDebugInfo(std::string* result) const {
+  if (!result) {
+    return;
+  }
+  *result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\
+      , config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_);
+  *result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\
+      layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height,
+      buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format);
+  for (const auto& layer : layers_) {
+    layer.dumpDebugInfo(result);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // VrHwcClient
 
@@ -232,26 +248,25 @@
 
 VrHwc::~VrHwc() {}
 
-bool VrHwc::hasCapability(Capability capability) const { return false; }
+bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
 
-void VrHwc::removeClient() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  client_ = nullptr;
+void VrHwc::registerEventCallback(EventCallback* callback) {
+  {
+    std::lock_guard<std::mutex> guard(mutex_);
+    event_callback_ = callback;
+    int32_t width, height;
+    GetPrimaryDisplaySize(&width, &height);
+    // Create the primary display late to avoid initialization issues between
+    // VR HWC and SurfaceFlinger.
+    displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+  }
+  event_callback_->onHotplug(kDefaultDisplayId,
+                             IComposerCallback::Connection::CONNECTED);
 }
 
-void VrHwc::enableCallback(bool enable) {
-  if (enable && client_ != nullptr) {
-    {
-      int32_t width, height;
-      GetPrimaryDisplaySize(&width, &height);
-      std::lock_guard<std::mutex> guard(mutex_);
-      // Create the primary display late to avoid initialization issues between
-      // VR HWC and SurfaceFlinger.
-      displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
-    }
-    client_.promote()->onHotplug(kDefaultDisplayId,
-                                 IComposerCallback::Connection::CONNECTED);
-  }
+void VrHwc::unregisterEventCallback() {
+  std::lock_guard<std::mutex> guard(mutex_);
+  event_callback_ = nullptr;
 }
 
 uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
@@ -306,13 +321,15 @@
   return Error::NONE;
 }
 
-Error VrHwc::getClientTargetSupport(Display display, uint32_t width,
-                                    uint32_t height, PixelFormat format,
-                                    Dataspace dataspace) {
+Error VrHwc::getClientTargetSupport(Display /* display */, uint32_t /* width */,
+                                    uint32_t /* height */,
+                                    PixelFormat /* format */,
+                                    Dataspace /* dataspace */) {
   return Error::NONE;
 }
 
-Error VrHwc::getColorModes(Display display, hidl_vec<ColorMode>* outModes) {
+Error VrHwc::getColorModes(Display /* display */,
+                           hidl_vec<ColorMode>* outModes) {
   std::vector<ColorMode> color_modes(1, ColorMode::NATIVE);
   *outModes = hidl_vec<ColorMode>(color_modes);
   return Error::NONE;
@@ -379,7 +396,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::getDisplayName(Display display, hidl_string* outName) {
+Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
   *outName = hidl_string();
   return Error::NONE;
 }
@@ -409,7 +426,8 @@
   return Error::NONE;
 }
 
-Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
+Error VrHwc::getHdrCapabilities(Display /* display */,
+                                hidl_vec<Hdr>* /* outTypes */,
                                 float* outMaxLuminance,
                                 float* outMaxAverageLuminance,
                                 float* outMinLuminance) {
@@ -473,8 +491,8 @@
 }
 
 Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
-                             int32_t acquireFence, int32_t dataspace,
-                             const std::vector<hwc_rect_t>& damage) {
+                             int32_t acquireFence, int32_t /* dataspace */,
+                             const std::vector<hwc_rect_t>& /* damage */) {
   base::unique_fd fence(acquireFence);
   std::lock_guard<std::mutex> guard(mutex_);
   auto display_ptr = FindDisplay(display);
@@ -490,7 +508,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer,
+Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
                              int32_t releaseFence) {
   base::unique_fd fence(releaseFence);
   std::lock_guard<std::mutex> guard(mutex_);
@@ -505,8 +523,9 @@
 Error VrHwc::validateDisplay(
     Display display, std::vector<Layer>* outChangedLayers,
     std::vector<IComposerClient::Composition>* outCompositionTypes,
-    uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
-    std::vector<uint32_t>* outRequestMasks) {
+    uint32_t* /* outDisplayRequestMask */,
+    std::vector<Layer>* /* outRequestedLayers */,
+    std::vector<uint32_t>* /* outRequestMasks */) {
   std::lock_guard<std::mutex> guard(mutex_);
   auto display_ptr = FindDisplay(display);
   if (!display_ptr)
@@ -517,7 +536,7 @@
   return Error::NONE;
 }
 
-Error VrHwc::acceptDisplayChanges(Display display) { return Error::NONE; }
+Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
 
 Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
                             std::vector<Layer>* outLayers,
@@ -709,8 +728,8 @@
   return Error::NONE;
 }
 
-Error VrHwc::setLayerSidebandStream(Display display, Layer layer,
-                                    buffer_handle_t stream) {
+Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
+                                    buffer_handle_t /* stream */) {
   std::lock_guard<std::mutex> guard(mutex_);
   if (!FindDisplay(display))
     return Error::BAD_DISPLAY;
@@ -830,7 +849,19 @@
 }
 
 Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
-  hidl_cb(hidl_string());
+  std::string result;
+
+  {
+    std::lock_guard<std::mutex> guard(mutex_);
+    result = "\nVrHwc states:\n";
+    for (const auto& pair : displays_) {
+      result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first);
+      pair.second->dumpDebugInfo(&result);
+    }
+    result += "\n";
+  }
+
+  hidl_cb(hidl_string(result));
   return Void();
 }
 
@@ -839,7 +870,7 @@
 
   Error status = Error::NONE;
   sp<VrComposerClient> client;
-  if (client_ == nullptr) {
+  if (!client_.promote().get()) {
     client = new VrComposerClient(*this);
   } else {
     ALOGE("Already have a client");
@@ -853,9 +884,9 @@
 
 void VrHwc::ForceDisplaysRefresh() {
   std::lock_guard<std::mutex> guard(mutex_);
-  if (client_ != nullptr) {
+  if (event_callback_ != nullptr) {
     for (const auto& pair : displays_)
-      client_.promote()->onRefresh(pair.first);
+      event_callback_->onRefresh(pair.first);
   }
 }
 
@@ -880,5 +911,22 @@
   return iter == displays_.end() ? nullptr : iter->second.get();
 }
 
+void HwcLayer::dumpDebugInfo(std::string* result) const {
+  if (!result) {
+    return;
+  }
+  *result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\
+      cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\
+      display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n",
+      composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y,
+      info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform,
+      info.display_frame.left, info.display_frame.top, info.display_frame.right,
+      info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right,
+      info.crop.bottom, info.blend_mode);
+  *result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\
+      , pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride,
+      buffer_metadata.layerCount, buffer_metadata.format);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index fce9a06..85e587a 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -19,7 +19,7 @@
 #include <android-base/unique_fd.h>
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <ComposerBase.h>
+#include <composer-hal/2.1/ComposerHal.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
@@ -46,7 +46,7 @@
 class VrComposerClient;
 
 using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::composer::V2_1::implementation::ComposerBase;
+using android::hardware::graphics::composer::V2_1::hal::ComposerHal;
 
 class ComposerView {
  public:
@@ -116,6 +116,8 @@
     info.id = new_id;
   }
 
+  void dumpDebugInfo(std::string* result) const;
+
   Composition composition_type;
   ComposerView::ComposerLayer info;
   IVrComposerClient::BufferMetadata buffer_metadata;
@@ -163,6 +165,8 @@
   int32_t color_transform_hint() const { return color_transform_hint_; }
   void SetColorTransform(const float* matrix, int32_t hint);
 
+  void dumpDebugInfo(std::string* result) const;
+
  private:
   // The client target buffer and the associated fence.
   sp<GraphicBuffer> buffer_;
@@ -191,13 +195,11 @@
   void operator=(const HwcDisplay&) = delete;
 };
 
-class VrHwc : public IComposer, public ComposerBase, public ComposerView {
+class VrHwc : public IComposer, public ComposerHal, public ComposerView {
  public:
   VrHwc();
   ~VrHwc() override;
 
-  bool hasCapability(Capability capability) const;
-
   Error setLayerInfo(Display display, Layer layer, uint32_t type,
                      uint32_t appId);
   Error setClientTargetMetadata(
@@ -206,9 +208,12 @@
       Display display, Layer layer,
       const IVrComposerClient::BufferMetadata& metadata);
 
-  // ComposerBase
-  void removeClient() override;
-  void enableCallback(bool enable) override;
+  // ComposerHal
+  bool hasCapability(hwc2_capability_t capability) override;
+
+  std::string dumpDebugInfo() override { return {}; }
+  void registerEventCallback(EventCallback* callback) override;
+  void unregisterEventCallback() override;
 
   uint32_t getMaxVirtualDisplayCount() override;
   Error createVirtualDisplay(uint32_t width, uint32_t height,
@@ -304,6 +309,7 @@
   std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
   Display display_count_ = 2;
 
+  EventCallback* event_callback_ = nullptr;
   Observer* observer_ = nullptr;
 
   VrHwc(const VrHwc&) = delete;
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
index 52d4da8..645ab80 100644
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -1,5 +1,6 @@
 service vr_hwc /system/bin/vr_hwc
-  class hal
+  class hal animation
   user system
   group system graphics
   onrestart restart surfaceflinger
+  writepid /dev/cpuset/system-background/tasks
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index dbc66f1..a548ef0 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -22,7 +22,6 @@
 
 staticLibraries := \
 	libperformance \
-	libpdx_default_transport \
 	libvr_manager
 
 sharedLibraries := \
@@ -30,12 +29,14 @@
 	libbase \
 	libcutils \
 	liblog \
-	libutils
+	libutils \
+	libpdx_default_transport \
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(sourceFiles)
 LOCAL_CFLAGS := -DLOG_TAG=\"performanced\"
 LOCAL_CFLAGS += -DTRACE=0
+LOCAL_CFLAGS += -Wall -Werror
 LOCAL_STATIC_LIBRARIES := $(staticLibraries)
 LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
 LOCAL_MODULE := performanced
diff --git a/services/vr/performanced/directory_reader.h b/services/vr/performanced/directory_reader.h
index 7d7ecc5..b9d27c3 100644
--- a/services/vr/performanced/directory_reader.h
+++ b/services/vr/performanced/directory_reader.h
@@ -19,7 +19,7 @@
     directory_ = fdopendir(directory_fd.get());
     error_ = errno;
     if (directory_ != nullptr)
-      directory_fd.release();
+      (void) directory_fd.release(); // ignore return result?
   }
 
   ~DirectoryReader() {
diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc
index 2605a47..af9760e 100644
--- a/services/vr/performanced/performanced.rc
+++ b/services/vr/performanced/performanced.rc
@@ -2,5 +2,4 @@
   class core
   user root
   group system readproc
-  writepid /dev/cpuset/tasks
   socket pdx/system/performance/client stream 0666 system system u:object_r:pdx_performance_client_endpoint_socket:s0
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 6b11ce3..513fcc1 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,7 +14,7 @@
 ]
 
 header_libraries = [
-    "libdvr_headers"
+    "libdvr_headers",
 ]
 
 cc_library {
@@ -23,7 +23,11 @@
     shared_libs: shared_libs,
     header_libs: header_libraries,
     cppflags: ["-std=c++11"],
-    cflags: ["-DLOG_TAG=\"VrVirtualTouchpad\""],
+    cflags: [
+        "-DLOG_TAG=\"VrVirtualTouchpad\"",
+        "-Wall",
+        "-Werror",
+    ],
     name: "libvirtualtouchpad",
     tags: ["optional"],
 }
@@ -44,15 +48,19 @@
     srcs: test_src_files,
     static_libs: test_static_libs,
     header_libs: header_libraries,
-    cppflags = [
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: [
         "-std=c++11",
     ],
-    host_ldlibs = [
+    host_ldlibs: [
         "-llog",
     ],
     name: "VirtualTouchpad_test",
     stl: "libc++_static",
-    tags: [ "optional" ],
+    tags: ["optional"],
 }
 
 // Service.
@@ -83,6 +91,8 @@
     cppflags: ["-std=c++11"],
     cflags: [
         "-DLOG_TAG=\"VrVirtualTouchpad\"",
+        "-Wall",
+        "-Werror",
     ],
     host_ldlibs: ["-llog"],
     name: "virtual_touchpad",
@@ -112,7 +122,11 @@
     shared_libs: client_shared_libs,
     header_libs: header_libraries,
     cppflags: ["-std=c++11"],
-    cflags: ["-DLOG_TAG=\"VirtualTouchpadClient\""],
+    cflags: [
+        "-DLOG_TAG=\"VirtualTouchpadClient\"",
+        "-Wall",
+        "-Werror",
+    ],
     host_ldlibs: ["-llog"],
     name: "libvirtualtouchpadclient",
     tags: ["optional"],
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index b19b018..198ed06 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -110,17 +110,6 @@
   EvdevInjectorForTesting injector[kTouchpads];
 };
 
-void DumpDifference(const char* expect, const char* actual) {
-  printf("  common: ");
-  while (*expect && *expect == *actual) {
-    putchar(*expect);
-    ++expect;
-    ++actual;
-  }
-  printf("\n  expect: %s\n", expect);
-  printf("  actual: %s\n", actual);
-}
-
 }  // anonymous namespace
 
 class VirtualTouchpadTest : public testing::Test {};
@@ -153,7 +142,6 @@
   }
   const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
   const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
-  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
 
   for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
     SCOPED_TRACE(t);
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 6107088..b15bed9 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -19,6 +19,8 @@
     srcs: [
         "include/vulkan/vk_platform.h",
         "include/vulkan/vulkan.h",
+        "include/vulkan/vulkan_core.h",
+        "include/vulkan/vulkan_android.h",
     ],
     license: "include/vulkan/NOTICE",
 }
@@ -43,8 +45,15 @@
     sdk_version: "24",
 }
 
+llndk_library {
+    name: "libvulkan",
+    symbol_file: "libvulkan/libvulkan.map.txt",
+    export_include_dirs: ["include"],
+}
+
 subdirs = [
     "nulldrv",
     "libvulkan",
     "tools",
+    "vkjson",
 ]
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index eb0124d..41f398d 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -43,6 +43,7 @@
 
 // VK_USE_PLATFORM_ANDROID_KHR
 @internal class ANativeWindow {}
+@internal class AHardwareBuffer {}
 @internal type void* buffer_handle_t
 
 // VK_USE_PLATFORM_WIN32_KHR
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 3a2b1ef..d0e8346 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -27,8 +27,8 @@
 
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
-define VERSION_MINOR 0
-define VERSION_PATCH 54
+define VERSION_MINOR 1
+define VERSION_PATCH 68
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -37,11 +37,14 @@
 define VK_MAX_DESCRIPTION_SIZE          256
 define VK_MAX_MEMORY_TYPES              32
 define VK_MAX_MEMORY_HEAPS              16    /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types.
-define VK_MAX_DEVICE_GROUP_SIZE_KHX     32
-//@extension("VK_KHR_external_memory_capabilities")
-define VK_LUID_SIZE_KHR                 8
-//@extension("VK_KHR_external_memory")
-define VK_QUEUE_FAMILY_EXTERNAL_KHR     -2
+@vulkan1_1
+define VK_MAX_DEVICE_GROUP_SIZE         32
+@vulkan1_1
+define VK_LUID_SIZE                     8
+@vulkan1_1
+define VK_QUEUE_FAMILY_EXTERNAL         -2
+@extension("VK_EXT_queue_family_foreign")
+define VK_QUEUE_FAMILY_FOREIGN_EXT      -3
 
 // API keywords
 define VK_TRUE        1
@@ -55,7 +58,7 @@
 @extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME               "VK_KHR_surface"
 
 // 2
-@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION             68
+@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION             70
 @extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME           "VK_KHR_swapchain"
 
 // 3
@@ -95,13 +98,17 @@
 @extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME             "VK_ANDROID_native_buffer"
 
 // 12
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       8
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       9
 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME               "VK_EXT_debug_report"
 
 // 13
 @extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION           1
 @extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME                   "VK_NV_glsl_shader"
 
+// 14
+@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION   1
+@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_NAME           "VK_EXT_depth_range_unrestricted"
+
 // 15
 @extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION   1
 @extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME           "VK_KHR_sampler_mirror_clamp_to_edge"
@@ -158,9 +165,17 @@
 @extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
 @extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
 
+// 43
+@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_SPEC_VERSION 1
+@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info"
+
+// 47
+@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1
+@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod"
+
 // 54
-@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_SPEC_VERSION 1
-@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview"
+@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_SPEC_VERSION 1
+@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview"
 
 // 56
 @extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
@@ -183,8 +198,8 @@
 @extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
 
 // 61
-@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_SPEC_VERSION 1
-@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
+@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3
+@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
 
 // 62
 @extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
@@ -211,8 +226,8 @@
 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
 
 // 71
-@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
-@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
+@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
 
 // 72
 @extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
@@ -251,7 +266,7 @@
 @extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
 
 // 81
-@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
+@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2
 @extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
 
 // 84
@@ -267,7 +282,7 @@
 @extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
 
 // 87
-@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
+@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3
 @extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
 
 // 88
@@ -318,8 +333,12 @@
 @extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
 @extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
 
+// 102
+@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1
+@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization"
+
 // 105
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 2
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 3
 @extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
 // 106
@@ -346,6 +365,10 @@
 @extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
 @extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
 
+// 118
+@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_SPEC_VERSION 1
+@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2"
+
 // 120
 @extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
 @extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
@@ -362,10 +385,26 @@
 @extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_SPEC_VERSION 1
 @extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
 
+// 126
+@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1
+@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf"
+
+// 127
+@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1
+@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign"
+
 // 128
-@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 1
+@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3
 @extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
 
+// 128
+@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1
+@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils"
+
+// 130
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 2
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer"
+
 // 131
 @extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
 @extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
@@ -378,10 +417,34 @@
 @extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
 @extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
 
+// 137
+@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1
+@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples"
+
+// 138
+@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
+@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
+
+// 141
+@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
+@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
+
+// 144
+@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1
+@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations"
+
+// 145
+@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1
+@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout"
+
 // 147
 @extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_SPEC_VERSION 1
 @extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
 
+// 148
+@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1
+@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list"
+
 // 149
 @extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
 @extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
@@ -398,6 +461,38 @@
 @extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
 @extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
 
+// 156
+@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1
+@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
+
+// 157
+@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1
+@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion"
+
+// 158
+@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
+@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
+
+// 161
+@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
+@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
+
+// 165
+@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1
+@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer"
+
+// 169
+@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_SPEC_VERSION 1
+@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3"
+
+// 175
+@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 1
+@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority"
+
+// 179
+@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1
+@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host"
+
 /////////////
 //  Types  //
 /////////////
@@ -436,6 +531,10 @@
 @nonDispatchHandle type u64 VkRenderPass
 @nonDispatchHandle type u64 VkPipelineCache
 
+@vulkan1_1
+@nonDispatchHandle type u64 VkSamplerYcbcrConversion
+@nonDispatchHandle type u64 VkDescriptorUpdateTemplate
+
 // 1
 @extension("VK_KHR_surface")    @nonDispatchHandle type u64 VkSurfaceKHR
 
@@ -456,6 +555,14 @@
 @extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkObjectTableNVX
 @extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkIndirectCommandsLayoutNVX
 
+// 129
+@extension("VK_EXT_debug_utils") @nonDispatchHandle type u64 VkDebugUtilsMessengerEXT
+
+// 157
+@extension("VK_KHR_sampler_ycbcr_conversion") @nonDispatchHandle type u64 VkSamplerYcbcrConversionKHR
+
+// 161
+@extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
 
 /////////////
 //  Enums  //
@@ -472,11 +579,19 @@
     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL                    = 0x00000007,   /// Optimal layout when image is used only as destination of transfer operations
     VK_IMAGE_LAYOUT_PREINITIALIZED                          = 0x00000008,   /// Initial layout used when the data is populated by the CPU
 
+    //@vulkan1_1
+    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
+    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
+
     //@extension("VK_KHR_swapchain") // 2
     VK_IMAGE_LAYOUT_PRESENT_SRC_KHR                         = 1000001002,
 
     //@extension("VK_KHR_shared_presentable_image") // 112
     VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR                      = 1000111000,
+
+    //@extension("VK_KHR_maintenance2") // 118
+    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR  = 1000117000,
+    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR  = 1000117001,
 }
 
 enum VkAttachmentLoadOp {
@@ -951,6 +1066,42 @@
     VK_FORMAT_ASTC_12x12_UNORM_BLOCK                        = 183,
     VK_FORMAT_ASTC_12x12_SRGB_BLOCK                         = 184,
 
+    //@vulkan1_1
+    VK_FORMAT_G8B8G8R8_422_UNORM                            = 1000156000,
+    VK_FORMAT_B8G8R8G8_422_UNORM                            = 1000156001,
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM                     = 1000156002,
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM                      = 1000156003,
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM                     = 1000156004,
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM                      = 1000156005,
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM                     = 1000156006,
+    VK_FORMAT_R10X6_UNORM_PACK16                            = 1000156007,
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16                      = 1000156008,
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16            = 1000156009,
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16        = 1000156010,
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16        = 1000156011,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16    = 1000156012,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16     = 1000156013,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16    = 1000156014,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16     = 1000156015,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16    = 1000156016,
+    VK_FORMAT_R12X4_UNORM_PACK16                            = 1000156017,
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16                      = 1000156018,
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16            = 1000156019,
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16        = 1000156020,
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16        = 1000156021,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16    = 1000156022,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16     = 1000156023,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16    = 1000156024,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16     = 1000156025,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16    = 1000156026,
+    VK_FORMAT_G16B16G16R16_422_UNORM                        = 1000156027,
+    VK_FORMAT_B16G16R16G16_422_UNORM                        = 1000156028,
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM                  = 1000156029,
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM                   = 1000156030,
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM                  = 1000156031,
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM                   = 1000156032,
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM                  = 1000156033,
+
     //@extension("VK_IMG_format_pvrtc") // 28
     VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG                   = 1000054000,
     VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG                   = 1000054001,
@@ -960,6 +1111,42 @@
     VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG                    = 1000054005,
     VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG                    = 1000054006,
     VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG                    = 1000054007,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_FORMAT_G8B8G8R8_422_UNORM_KHR                            = 1000156000,
+    VK_FORMAT_B8G8R8G8_422_UNORM_KHR                            = 1000156001,
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR                     = 1000156002,
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR                      = 1000156003,
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR                     = 1000156004,
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR                      = 1000156005,
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR                     = 1000156006,
+    VK_FORMAT_R10X6_UNORM_PACK16_KHR                            = 1000156007,
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR                      = 1000156008,
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR            = 1000156009,
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR        = 1000156010,
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR        = 1000156011,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR    = 1000156012,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR     = 1000156013,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR    = 1000156014,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR     = 1000156015,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR    = 1000156016,
+    VK_FORMAT_R12X4_UNORM_PACK16_KHR                            = 1000156017,
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR                      = 1000156018,
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR            = 1000156019,
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR        = 1000156020,
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR        = 1000156021,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR    = 1000156022,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR     = 1000156023,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR    = 1000156024,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR     = 1000156025,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR    = 1000156026,
+    VK_FORMAT_G16B16G16R16_422_UNORM_KHR                        = 1000156027,
+    VK_FORMAT_B16G16R16G16_422_UNORM_KHR                        = 1000156028,
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR                  = 1000156029,
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR                   = 1000156030,
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR                  = 1000156031,
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR                   = 1000156032,
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR                  = 1000156033,
 }
 
 /// Structure type enumerant
@@ -1014,9 +1201,83 @@
     VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO               = 47,
     VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO                 = 48,
 
+    //@vulkan1_1
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES       = 1000094000,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO                   = 1000157000,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO                    = 1000157001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES    = 1000083000,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS             = 1000127000,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO            = 1000127001,
+    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO                = 1000060000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO       = 1000060003,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO    = 1000060004,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO                  = 1000060005,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO             = 1000060006,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO      = 1000060013,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO       = 1000060014,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES          = 1000070000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO           = 1000070001,
+    VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2         = 1000146000,
+    VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2          = 1000146001,
+    VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2   = 1000146002,
+    VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2                     = 1000146003,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2        = 1000146004,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2                = 1000059000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2              = 1000059001,
+    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2                       = 1000059002,
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2                 = 1000059003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2       = 1000059004,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2                 = 1000059005,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2       = 1000059006,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2          = 1000059007,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2            = 1000059008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES             = 1000117000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO       = 1000117001,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO                          = 1000117002,
+    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
+    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO                 = 1000053000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES                = 1000053001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES              = 1000053002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES         = 1000120000,
+    VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO                             = 1000145000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES         = 1000145001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES       = 1000145002,
+    VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2                               = 1000145003,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO              = 1000156000,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO                     = 1000156001,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO                      = 1000156002,
+    VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO              = 1000156003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES  = 1000156005,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO            = 1000085000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO        = 1000071000,
+    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES                  = 1000071001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO              = 1000071002,
+    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES                        = 1000071003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES                     = 1000071004,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO                = 1000072000,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO                 = 1000072001,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO                       = 1000072002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO               = 1000112000,
+    VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES                         = 1000112001,
+    VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO                          = 1000113000,
+    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO                      = 1000077000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO           = 1000076000,
+    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES                     = 1000076001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES          = 1000168000,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT                     = 1000168001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES    = 1000063000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR             = 1000060007,
+
     //@extension("VK_KHR_swapchain") // 2
     VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR                 = 1000001000,
     VK_STRUCTURE_TYPE_PRESENT_INFO_KHR                          = 1000001001,
+    // added as interaction from VK_KHR_device_group / VK 1.1
+    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR           = 1000060008,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR      = 1000060009,
+    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR               = 1000060010,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR             = 1000060011,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR    = 1000060012,
 
     //@extension("VK_KHR_display") // 3
     VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR              = 1000002000,
@@ -1067,10 +1328,10 @@
     //@extension("VK_AMD_texture_gather_bias_lod") // 42
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD  = 1000041000,
 
-    //@extension("VK_KHX_multiview") // 54
-    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX     = 1000053000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX    = 1000053001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX  = 1000053002,
+    //@extension("VK_KHR_multiview") // 54
+    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR     = 1000053000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR    = 1000053001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR  = 1000053002,
 
     //@extension("VK_NV_external_memory") // 57
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV      = 1000056000,
@@ -1094,20 +1355,16 @@
     VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR      = 1000059007,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
 
-    //@extension("VK_KHX_device_group") // 61
-    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX            = 1000060000,
-    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX               = 1000060001,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX                = 1000060002,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX   = 1000060003,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX              = 1000060005,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX         = 1000060006,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX     = 1000060007,
-    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX           = 1000060008,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX      = 1000060009,
-    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX               = 1000060010,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX             = 1000060011,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX    = 1000060012,
+    //@extension("VK_KHR_device_group") // 61
+    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR            = 1000060000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR   = 1000060003,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = 1000060004,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR              = 1000060005,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR         = 1000060006,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR     = 1000060007,
+    // tokens 08-12 are listed with VK_KHR_swapchain
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR  = 1000060013,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR   = 1000060014,
 
     //@extension("VK_EXT_validation_flags") // 62
     VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT                      = 1000061000,
@@ -1115,9 +1372,9 @@
     //@extension("VK_NN_vi_surface") // 63
     VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN                 = 1000062000,
 
-    //@extension("VK_KHX_device_group_creation") // 71
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX      = 1000070000,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX       = 1000070001,
+    //@extension("VK_KHR_device_group_creation") // 71
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR      = 1000070000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR       = 1000070001,
 
     //@extension("VK_KHR_external_memory_capabilities") // 72
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR    = 1000071000,
@@ -1183,7 +1440,7 @@
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV  = 1000087000,
 
     //@extension("VK_EXT_display_surface_counter") // 91
-    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT                 = 1000090000,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT                = 1000090000,
 
     //@extension("VK_EXT_display_control") // 92
     VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT                    = 1000091000,
@@ -1204,6 +1461,10 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT  = 1000099000,
     VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT  = 1000099001,
 
+    //@extension("VK_EXT_conservative_rasterization") // 102
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001,
+
     //@extension("VK_EXT_hdr_metadata") // 106
     VK_STRUCTURE_TYPE_HDR_METADATA_EXT                          = 1000105000,
 
@@ -1226,6 +1487,12 @@
     VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR                  = 1000115000,
     VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR                     = 1000115001,
 
+    //@extension("VK_KHR_maintenance2") // 118
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR             = 1000117000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR       = 1000117001,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR                          = 1000117002,
+    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = 1000117003,
+
     //@extension("VK_KHR_get_surface_capabilities2") // 120
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR        = 1000119000,
     VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR                = 1000119001,
@@ -1244,10 +1511,32 @@
     VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR         = 1000127000,
     VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR        = 1000127001,
 
+    //@extension("VK_EXT_debug_utils") // 129
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT          = 1000128000,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT           = 1000128001,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT                     = 1000128002,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT   = 1000128003,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT     = 1000128004,
+
+    //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID             = 1000129000,
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID        = 1000129001,
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002,
+    VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID       = 1000129003,
+    VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID   = 1000129004,
+    VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID                           = 1000129005,
+
     //@extension("VK_EXT_sampler_filter_minmax") // 131
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
     VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
 
+    //@extension("VK_EXT_sample_locations") // 144
+    VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT                         = 1000143000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT       = 1000143001,
+    VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT   = 1000143002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT   = 1000143003,
+    VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT                        = 1000143004,
+
     //@extension("VK_KHR_get_memory_requirements2") // 147
     VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR         = 1000146000,
     VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR          = 1000146001,
@@ -1255,6 +1544,9 @@
     VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR                     = 1000146003,
     VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR        = 1000146004,
 
+    //@extension("VK_KHR_image_format_list") // 148
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR             = 1000147000,
+
     //@extension("VK_EXT_blend_operation_advanced") // 149
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
@@ -1263,8 +1555,36 @@
     //@extension("VK_NV_fragment_coverage_to_color") // 150
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
 
-    //@structure("VK_NV_framebuffer_mixed_samples") // 153
+    //@extension("VK_NV_framebuffer_mixed_samples") // 153
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR              = 1000156000,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR                     = 1000156001,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR                      = 1000156002,
+    VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR              = 1000156003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR  = 1000156005,
+
+    //@extension("VK_KHR_bind_memory2") // 158
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR                       = 1000157000,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR                        = 1000157001,
+
+    //@extension("VK_EXT_validation_cache") // 161
+    VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT                  = 1000160000,
+    VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT    = 1000160001,
+
+    //@extension("VK_KHR_maintenance3") // 169
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR      = 1000168000,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR                 = 1000168001,
+
+    //@extension("VK_EXT_global_priority") // 175
+    VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT      = 1000174000,
+
+    //@extension("VK_EXT_external_memory_host") // 179
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT                   = 1000178000,
+    VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT                    = 1000178001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT   = 1000178002,
 }
 
 enum VkSubpassContents {
@@ -1304,6 +1624,10 @@
     VK_ERROR_FORMAT_NOT_SUPPORTED                           = 0xFFFFFFF5, // -11
     VK_ERROR_FRAGMENTED_POOL                                = 0xFFFFFFF4, // -12
 
+    //@vulkan1_1
+    VK_ERROR_OUT_OF_POOL_MEMORY                             = 0xC4642878, // -1000069000
+    VK_ERROR_INVALID_EXTERNAL_HANDLE                        = 0xC4641CBD, // -1000072003
+
     //@extension("VK_KHR_surface") // 1
     VK_ERROR_SURFACE_LOST_KHR                               = 0xC4653600, // -1000000000
     VK_ERROR_NATIVE_WINDOW_IN_USE_KHR                       = 0xC46535FF, // -1000000001
@@ -1323,6 +1647,9 @@
     //@extension("VK_KHR_maintenance1") // 70
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR                         = 0xC4642878, // -1000069000
 
+    //@extension("VK_EXT_global_priority") // 175
+    VK_ERROR_NOT_PERMITTED_EXT                              = 0xC4628E4F, // -1000174001
+
     //@extension("VK_KHR_external_memory") // 73
     VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR                    = 0xC4641CBD, // -1000072003
 }
@@ -1343,6 +1670,9 @@
 
     //@extension("VK_EXT_discard_rectangles") // 100
     VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT                  = 1000099000,
+
+    //@extension("VK_EXT_sample_locations") // 144
+    VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT                   = 1000143000,
 }
 
 enum VkObjectType {
@@ -1373,6 +1703,10 @@
     VK_OBJECT_TYPE_FRAMEBUFFER                              = 24,
     VK_OBJECT_TYPE_COMMAND_POOL                             = 25,
 
+    //@vulkan1_1
+    VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION                 = 1000156000,
+    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE               = 1000085000,
+
     //@extension("VK_KHR_surface") // 1
     VK_OBJECT_TYPE_SURFACE_KHR                              = 1000000000,
 
@@ -1392,6 +1726,51 @@
     //@extension("VK_NVX_device_generated_commands") // 87
     VK_OBJECT_TYPE_OBJECT_TABLE_NVX                         = 1000086000,
     VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX             = 1000086001,
+
+    //@extension("VK_EXT_debug_utils") // 129
+    VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT                = 1000128000,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR             = 1000156000,
+
+    //@extension("VK_EXT_validation_cache") // 161
+    VK_OBJECT_TYPE_VALIDATION_CACHE_EXT                     = 1000160000,
+}
+
+
+//@vulkan1_1 enums
+
+enum VkPointClippingBehavior {
+    VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES              = 0,
+    VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY        = 1,
+}
+
+enum VkTessellationDomainOrigin {
+    VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT                = 0,
+    VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT                = 1,
+}
+
+enum VkSamplerYcbcrModelConversion {
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY          = 0,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY        = 1,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709             = 2,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601             = 3,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020            = 4,
+}
+
+enum VkSamplerYcbcrRange {
+    VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
+    VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
+}
+
+enum VkChromaLocation {
+    VK_CHROMA_LOCATION_COSITED_EVEN = 0,
+    VK_CHROMA_LOCATION_MIDPOINT = 1,
+}
+
+enum VkDescriptorUpdateTemplateType {
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
 }
 
 @extension("VK_KHR_surface") // 1
@@ -1408,7 +1787,7 @@
 
 @extension("VK_KHR_surface") // 1
 enum VkColorSpaceKHR {
-    VK_COLORSPACE_SRGB_NONLINEAR_KHR                        = 0x00000000,
+    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR                       = 0x00000000,
 
     //@extension("VK_EXT_swapchain_colorspace") // 105
     VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT                 = 1000104001,
@@ -1463,8 +1842,14 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT        = 31,
     VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
 
+    //extension("VK_EXT_validation_cache") // 161
+    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT    = 33,
+
     //extension("VK_KHR_descriptor_update_template") // 86
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
 }
 
 @extension("VK_AMD_rasterization_order") // 19
@@ -1473,6 +1858,13 @@
     VK_RASTERIZATION_ORDER_RELAXED_AMD                      = 1,
 }
 
+@extension("VK_AMD_shader_info") // 43
+enum VkShaderInfoTypeAMD {
+    VK_SHADER_INFO_TYPE_STATISTICS_AMD                      = 0,
+    VK_SHADER_INFO_TYPE_BINARY_AMD                          = 1,
+    VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD                     = 2,
+}
+
 @extension("VK_EXT_validation_flags") // 62
 enum VkValidationCheckEXT {
     VK_VALIDATION_CHECK_ALL_EXT                             = 0,
@@ -1541,6 +1933,25 @@
     VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
 }
 
+@extension("VK_EXT_conservative_rasterization") // 102
+enum VkConservativeRasterizationModeEXT {
+    VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT         = 0,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT     = 1,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT    = 2,
+}
+
+@extension("VK_KHR_maintenance2") // 118
+enum VkPointClippingBehaviorKHR {
+    VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR          = 0,
+    VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR    = 1,
+}
+
+@extension("VK_KHR_maintenance2") // 118
+enum VkTessellationDomainOriginKHR {
+    VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR            = 0,
+    VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR            = 1,
+}
+
 @extension("VK_EXT_sampler_filter_minmax") // 131
 enum VkSamplerReductionModeEXT {
     VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT          = 0,
@@ -1563,6 +1974,40 @@
     VK_COVERAGE_MODULATION_MODE_RGBA_NV                     = 3,
 }
 
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkSamplerYcbcrModelConversionKHR {
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR      = 0,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR    = 1,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR         = 2,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR         = 3,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR        = 4,
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkSamplerYcbcrRangeKHR {
+    VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR                     = 0,
+    VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR                   = 1,
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+enum VkChromaLocationKHR {
+    VK_CHROMA_LOCATION_COSITED_EVEN_KHR                     = 0,
+    VK_CHROMA_LOCATION_MIDPOINT_KHR                         = 1,
+}
+
+@extension("VK_EXT_validation_cache") // 161
+enum VkValidationCacheHeaderVersionEXT {
+    VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT              = 1,
+}
+
+@extension("VK_EXT_global_priority") // 175
+enum VkQueueGlobalPriorityEXT {
+    VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT                        = 128,
+    VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT                     = 256,
+    VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT                       = 512,
+    VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT                   = 1024,
+}
+
 /////////////////
 //  Bitfields  //
 /////////////////
@@ -1574,6 +2019,9 @@
     VK_QUEUE_COMPUTE_BIT                                    = 0x00000002,    /// Queue supports compute operations
     VK_QUEUE_TRANSFER_BIT                                   = 0x00000004,    /// Queue supports transfer operations
     VK_QUEUE_SPARSE_BINDING_BIT                             = 0x00000008,    /// Queue supports sparse resource memory management operations
+
+    //@vulkan1_1
+    VK_QUEUE_PROTECTED_BIT                                  = 0x00000010,
 }
 
 /// Memory properties passed into vkAllocMemory().
@@ -1584,6 +2032,9 @@
     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT                    = 0x00000004,
     VK_MEMORY_PROPERTY_HOST_CACHED_BIT                      = 0x00000008,
     VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT                 = 0x00000010,
+
+    //@vulkan1_1
+    VK_MEMORY_PROPERTY_PROTECTED_BIT                        = 0x00000020,
 }
 
 /// Memory heap flags
@@ -1591,8 +2042,11 @@
 bitfield VkMemoryHeapFlagBits {
     VK_MEMORY_HEAP_DEVICE_LOCAL_BIT                         = 0x00000001,
 
-    //@extension("VK_KHX_device_group_creation") // 71
-    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX                   = 0x00000002,
+    //@vulkan1_1
+    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT                       = 0x00000002,
+
+    //@extension("VK_KHR_device_group_creation") // 71
+    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR                   = 0x00000002,
 }
 
 /// Access flags
@@ -1644,6 +2098,9 @@
     VK_BUFFER_CREATE_SPARSE_BINDING_BIT                     = 0x00000001,    /// Buffer should support sparse backing
     VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT                   = 0x00000002,    /// Buffer should support sparse backing with partial residency
     VK_BUFFER_CREATE_SPARSE_ALIASED_BIT                     = 0x00000004,    /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers
+
+    //@vulkan1_1
+    VK_BUFFER_CREATE_PROTECTED_BIT                          = 0x00000008,
 }
 
 /// Shader stage flags
@@ -1693,11 +2150,33 @@
     VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT                      = 0x00000008,    /// Allows image views to have different format than the base image
     VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT                     = 0x00000010,    /// Allows creating image views with cube type from the created image
 
+    //@vulkan1_1
+    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT                 = 0x00000020,
+    VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT         = 0x00000040,
+    VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT         = 0x00000080,
+    VK_IMAGE_CREATE_EXTENDED_USAGE_BIT                      = 0x00000100,
+    VK_IMAGE_CREATE_DISJOINT_BIT                            = 0x00000200,
+    VK_IMAGE_CREATE_ALIAS_BIT                               = 0x00000400,
+    VK_IMAGE_CREATE_PROTECTED_BIT                           = 0x00000800,
+
     //@extension("VK_KHR_maintenance1") // 70
     VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR             = 0x00000020,
 
-    //@extension("VK_KHX_device_group") // 61
-    VK_IMAGE_CREATE_BIND_SFR_BIT_KHX                        = 0x00000040,
+    //@extension("VK_KHR_device_group") // 61
+    VK_IMAGE_CREATE_BIND_SFR_BIT_KHR                        = 0x00000040,
+
+    //@extension("VK_KHR_maintenance2") // 118
+    VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR     = 0x00000080,
+    VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR                  = 0x00000100,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_IMAGE_CREATE_DISJOINT_BIT_KHR                        = 0x00000200,
+
+    //@extension("VK_KHR_bind_memory2") // 158
+    VK_IMAGE_CREATE_ALIAS_BIT_KHR                           = 0x00000400,
+
+    //@extension("VK_EXT_sample_locations") // 144
+    VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
 }
 
 /// Image view creation flags
@@ -1712,9 +2191,13 @@
     VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT                = 0x00000002,
     VK_PIPELINE_CREATE_DERIVATIVE_BIT                       = 0x00000004,
 
-    //@extension("VK_KHX_device_group") // 61
-    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
-    VK_PIPELINE_CREATE_DISPATCH_BASE_KHX                    = 0x00000010,
+    //@vulkan1_1
+    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT     = 0x00000008,
+    VK_PIPELINE_CREATE_DISPATCH_BASE                        = 0x00000010,
+
+    //@extension("VK_KHR_device_group") // 61
+    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
+    VK_PIPELINE_CREATE_DISPATCH_BASE_KHR                    = 0x00000010,
 }
 
 /// Color component flags
@@ -1754,6 +2237,17 @@
     VK_FORMAT_FEATURE_BLIT_DST_BIT                          = 0x00000800,    /// Format can be used as the destination image of blits with vkCommandBlitImage
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT       = 0x00001000,
 
+    //@vulkan1_1
+    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT                      = 0x00004000,
+    VK_FORMAT_FEATURE_TRANSFER_DST_BIT                      = 0x00008000,
+    VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT                                                   = 0x00020000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT                              = 0x00040000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT             = 0x00080000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT             = 0x00100000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT   = 0x00200000,
+    VK_FORMAT_FEATURE_DISJOINT_BIT                                                                  = 0x00400000,
+    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT                                                    = 0x00800000,
+
     //@extension("VK_IMG_filter_cubic") // 16
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG    = 0x00002000,
 
@@ -1763,6 +2257,15 @@
 
     //@extension("VK_EXT_sampler_filter_minmax") // 131
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT   = 0x00010000,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR                                                   = 0x00020000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR                              = 0x00040000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR             = 0x00080000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR             = 0x00100000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR   = 0x00200000,
+    VK_FORMAT_FEATURE_DISJOINT_BIT_KHR                                                                  = 0x00400000,
+    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR                                                    = 0x00800000,
 }
 
 /// Query control flags
@@ -1826,6 +2329,16 @@
     VK_IMAGE_ASPECT_DEPTH_BIT                               = 0x00000002,
     VK_IMAGE_ASPECT_STENCIL_BIT                             = 0x00000004,
     VK_IMAGE_ASPECT_METADATA_BIT                            = 0x00000008,
+
+    //@vulkan1_1
+    VK_IMAGE_ASPECT_PLANE_0_BIT                             = 0x00000010,
+    VK_IMAGE_ASPECT_PLANE_1_BIT                             = 0x00000020,
+    VK_IMAGE_ASPECT_PLANE_2_BIT                             = 0x00000040,
+
+    //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+    VK_IMAGE_ASPECT_PLANE_0_BIT_KHR                         = 0x00000010,
+    VK_IMAGE_ASPECT_PLANE_1_BIT_KHR                         = 0x00000020,
+    VK_IMAGE_ASPECT_PLANE_2_BIT_KHR                         = 0x00000040,
 }
 
 /// Sparse memory bind flags
@@ -1887,6 +2400,9 @@
 bitfield VkCommandPoolCreateFlagBits {
     VK_COMMAND_POOL_CREATE_TRANSIENT_BIT                    = 0x00000001,  /// Command buffers have a short lifetime
     VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT         = 0x00000002,  /// Command buffers may release their memory individually
+
+    //@vulkan1_1
+    VK_COMMAND_POOL_CREATE_PROTECTED_BIT                    = 0x00000004,
 }
 
 /// Command pool reset flags
@@ -1930,8 +2446,10 @@
 
 /// Device queue creation flags
 type VkFlags VkDeviceQueueCreateFlags
-//bitfield VkDeviceQueueCreateFlagBits {
-//}
+@vulkan1_1
+bitfield VkDeviceQueueCreateFlagBits {
+    VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT                    = 0x00000001,
+}
 
 /// Query pool creation flags
 type VkFlags VkQueryPoolCreateFlags
@@ -2030,11 +2548,15 @@
 bitfield VkDependencyFlagBits {
     VK_DEPENDENCY_BY_REGION_BIT                             = 0x00000001,
 
-    //@extension("VK_KHX_multiview") // 54
-    VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX                        = 0x00000002,
+    //@vulkan1_1
+    VK_DEPENDENCY_DEVICE_GROUP_BIT                          = 0x00000004,
+    VK_DEPENDENCY_VIEW_LOCAL_BIT                            = 0x00000002,
 
-    //@extension("VK_KHX_device_group") // 61
-    VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX                      = 0x00000004,
+    //@extension("VK_KHR_multiview") // 54
+    VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR                        = 0x00000002,
+
+    //@extension("VK_KHR_device_group") // 61
+    VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR                      = 0x00000004,
 }
 
 /// Cull mode flags
@@ -2046,6 +2568,119 @@
     VK_CULL_MODE_FRONT_AND_BACK                             = 0x00000003,
 }
 
+//@vulkan1_1 flags
+
+/// Subgroup feature flags
+type VkFlags VkSubgroupFeatureFlags
+bitfield VkSubgroupFeatureFlagBits {
+    VK_SUBGROUP_FEATURE_BASIC_BIT                           = 0x00000001,
+    VK_SUBGROUP_FEATURE_VOTE_BIT                            = 0x00000002,
+    VK_SUBGROUP_FEATURE_ARITHMETIC_BIT                      = 0x00000004,
+    VK_SUBGROUP_FEATURE_BALLOT_BIT                          = 0x00000008,
+    VK_SUBGROUP_FEATURE_SHUFFLE_BIT                         = 0x00000010,
+    VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT                = 0x00000020,
+    VK_SUBGROUP_FEATURE_CLUSTERED_BIT                       = 0x00000040,
+    VK_SUBGROUP_FEATURE_QUAD_BIT                            = 0x00000080,
+}
+
+/// Peer memory feature flags
+type VkFlags VkPeerMemoryFeatureFlags
+bitfield VkPeerMemoryFeatureFlagBits {
+    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT                     = 0x00000001,
+    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT                     = 0x00000002,
+    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT                  = 0x00000004,
+    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT                  = 0x00000008,
+}
+
+/// Memory allocation flags
+type VkFlags VkMemoryAllocateFlags
+bitfield VkMemoryAllocateFlagBits {
+    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT                      = 0x00000001,
+}
+
+type VkFlags VkCommandPoolTrimFlags
+//bitfield VkCommandPoolTrimFlagBits {
+//}
+
+type VkFlags VkDescriptorUpdateTemplateCreateFlags
+//bitfield VkDescriptorUpdateTemplateCreateFlagBits {
+//}
+
+/// External memory handle type flags
+type VkFlags VkExternalMemoryHandleTypeFlags
+bitfield VkExternalMemoryHandleTypeFlagBits {
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT            = 0x00000001,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT         = 0x00000002,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT     = 0x00000004,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT        = 0x00000008,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT    = 0x00000010,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT           = 0x00000020,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT       = 0x00000040,
+
+    //@extension("VK_EXT_external_memory_host") // 179
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT              = 0x00000080,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT   = 0x00000100,
+
+    //@extension("VK_EXT_external_memory_dma_buf") // 126
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT                      = 0x00000200,
+
+    //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID  = 0x00000400,
+}
+
+/// External memory feature flags
+type VkFlags VkExternalMemoryFeatureFlags
+bitfield VkExternalMemoryFeatureFlagBits {
+    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT           = 0x00000001,
+    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT               = 0x00000002,
+    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT               = 0x00000004,
+}
+
+/// External fence handle type flags
+type VkFlags VkExternalFenceHandleTypeFlags
+bitfield VkExternalFenceHandleTypeFlagBits {
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT             = 0x00000001,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT          = 0x00000002,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT      = 0x00000004,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT               = 0x00000008,
+}
+
+/// External fence feature flags
+type VkFlags VkExternalFenceFeatureFlags
+bitfield VkExternalFenceFeatureFlagBits {
+    VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT                = 0x00000001,
+    VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT                = 0x00000002,
+}
+
+/// Fence import flags
+type VkFlags VkFenceImportFlags
+bitfield VkFenceImportFlagBits {
+    VK_FENCE_IMPORT_TEMPORARY_BIT                           = 0x00000001,
+}
+
+/// Semaphore import flags
+type VkFlags VkSemaphoreImportFlags
+bitfield VkSemaphoreImportFlagBits {
+    VK_SEMAPHORE_IMPORT_TEMPORARY_BIT                       = 0x00000001,
+}
+
+/// External semaphore handle type flags
+type VkFlags VkExternalSemaphoreHandleTypeFlags
+bitfield VkExternalSemaphoreHandleTypeFlagBits {
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT         = 0x00000001,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT      = 0x00000002,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT  = 0x00000004,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT       = 0x00000008,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT           = 0x00000010,
+}
+
+/// External semaphore feature flags
+type VkFlags VkExternalSemaphoreFeatureFlags
+bitfield VkExternalSemaphoreFeatureFlagBits {
+    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT            = 0x00000001,
+    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT            = 0x00000002,
+}
+
 @extension("VK_KHR_surface") // 1
 type VkFlags VkSurfaceTransformFlagsKHR
 @extension("VK_KHR_surface") // 1
@@ -2075,8 +2710,21 @@
 type VkFlags VkSwapchainCreateFlagsKHR
 @extension("VK_KHR_swapchain") // 2
 bitfield VkSwapchainCreateFlagBitsKHR {
-    //@extension("VK_KHX_device_group") // 61
-    VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX                    = 0x00000001,
+    //@vulkan1_1
+    VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001,
+    VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR                   = 0x00000002,
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+type VkFlags VkDeviceGroupPresentModeFlagsKHR
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+bitfield VkDeviceGroupPresentModeFlagBitsKHR {
+    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR              = 0x00000001,
+    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR             = 0x00000002,
+    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR                = 0x00000004,
+    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008,
 }
 
 @extension("VK_KHR_display") // 3
@@ -2174,31 +2822,21 @@
     VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV            = 0x00000004,
 }
 
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkPeerMemoryFeatureFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkPeerMemoryFeatureFlagBitsKHX {
-    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX                 = 0x00000001,
-    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX                 = 0x00000002,
-    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX              = 0x00000004,
-    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX              = 0x00000008,
+@extension("VK_KHR_device_group") // 61
+type VkFlags VkPeerMemoryFeatureFlagsKHR
+@extension("VK_KHR_device_group") // 61
+bitfield VkPeerMemoryFeatureFlagBitsKHR {
+    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR                 = 0x00000001,
+    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR                 = 0x00000002,
+    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR              = 0x00000004,
+    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR              = 0x00000008,
 }
 
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkMemoryAllocateFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkMemoryAllocateFlagBitsKHX {
-    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX                  = 0x00000001,
-}
-
-@extension("VK_KHX_device_group") // 61
-type VkFlags VkDeviceGroupPresentModeFlagsKHX
-@extension("VK_KHX_device_group") // 61
-bitfield VkDeviceGroupPresentModeFlagBitsKHX {
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX              = 0x00000001,
-    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX             = 0x00000002,
-    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX                = 0x00000004,
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
+@extension("VK_KHR_device_group") // 61
+type VkFlags VkMemoryAllocateFlagsKHR
+@extension("VK_KHR_device_group") // 61
+bitfield VkMemoryAllocateFlagBitsKHR {
+    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR                  = 0x00000001,
 }
 
 @extension("VK_NN_vi_surface") // 63
@@ -2304,6 +2942,12 @@
 //bitfield VkPipelineDiscardRectangleStateCreateFlagBitsEXT {
 //}
 
+@extension("VK_EXT_conservative_rasterization") // 102
+type VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT
+//@extension("VK_EXT_conservative_rasterization") // 102
+//bitfield VkPipelineRasterizationConservativeStateCreateFlagBitsEXT {
+//}
+
 @extension("VK_KHR_external_fence_capabilities") // 113
 type VkFlags VkExternalFenceHandleTypeFlagsKHR
 @extension("VK_KHR_external_fence_capabilities") // 113
@@ -2341,6 +2985,37 @@
 //bitfield VkMacOSSurfaceCreateFlagBitsMVK {
 //}
 
+@extension("VK_EXT_debug_utils") // 129
+type VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT
+//@extension("VK_EXT_debug_utils") // 129
+//bitfield VkDebugUtilsMessengerCallbackDataFlagBitsEXT {
+//}
+
+@extension("VK_EXT_debug_utils") // 129
+type VkFlags VkDebugUtilsMessengerCreateFlagsEXT
+//@extension("VK_EXT_debug_utils") // 129
+//bitfield VkDebugUtilsMessengerCreateFlagBitsEXT {
+//}
+
+@extension("VK_EXT_debug_utils") // 129
+type VkFlags VkDebugUtilsMessageSeverityFlagsEXT
+@extension("VK_EXT_debug_utils") // 129
+bitfield VkDebugUtilsMessageSeverityFlagBitsEXT {
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT    = 0x00000010,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT   = 0x00001000,
+}
+
+@extension("VK_EXT_debug_utils") // 129
+type VkFlags VkDebugUtilsMessageTypeFlagsEXT
+@extension("VK_EXT_debug_utils") // 129
+bitfield VkDebugUtilsMessageTypeFlagBitsEXT {
+    VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT     = 0x00000001,
+    VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT  = 0x00000002,
+    VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004,
+}
+
 @extension("VK_NV_fragment_coverage_to_color") // 150
 type VkFlags VkPipelineCoverageToColorStateCreateFlagsNV
 @extension("VK_NV_fragment_coverage_to_color") // 150
@@ -2353,6 +3028,12 @@
 //bitfield VkPipelineCoverageModulationStateCreateFlagBitsNV {
 //}
 
+@extension("VK_EXT_validation_cache") // 161
+type VkFlags VkValidationCacheCreateFlagsEXT
+@extension("VK_EXT_validation_cache") // 161
+//bitfield VkValidationCacheCreateFlagBitsEXT {
+//}
+
 //////////////////
 //  Structures  //
 //////////////////
@@ -3457,6 +4138,493 @@
     u32                                         z
 }
 
+//@vulkan1_1 structures
+
+class VkPhysicalDeviceSubgroupProperties {
+    VkStructureType                             sType
+    void*                                       pNext
+    u32                                         subgroupSize
+    VkShaderStageFlags                          supportedStages
+    VkSubgroupFeatureFlags                      supportedOperations
+    VkBool32                                    quadOperationsInAllStages
+}
+
+class VkBindBufferMemoryInfo {
+    VkStructureType    sType
+    const void*        pNext
+    VkBuffer           buffer
+    VkDeviceMemory     memory
+    VkDeviceSize       memoryOffset
+}
+
+class VkBindImageMemoryInfo {
+    VkStructureType    sType
+    const void*        pNext
+    VkImage            image
+    VkDeviceMemory     memory
+    VkDeviceSize       memoryOffset
+}
+
+class VkPhysicalDevice16BitStorageFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           storageBuffer16BitAccess
+    VkBool32           uniformAndStorageBuffer16BitAccess
+    VkBool32           storagePushConstant16
+    VkBool32           storageInputOutput16
+}
+
+class VkMemoryDedicatedRequirements {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           prefersDedicatedAllocation
+    VkBool32           requiresDedicatedAllocation
+}
+
+class VkMemoryDedicatedAllocateInfo {
+    VkStructureType    sType
+    const void*        pNext
+    VkImage            image
+    VkBuffer           buffer
+}
+
+class VkMemoryAllocateFlagsInfo {
+    VkStructureType          sType
+    const void*              pNext
+    VkMemoryAllocateFlags    flags
+    u32                      deviceMask
+}
+
+class VkDeviceGroupRenderPassBeginInfo {
+    VkStructureType    sType
+    const void*        pNext
+    u32                deviceMask
+    u32                deviceRenderAreaCount
+    const VkRect2D*    pDeviceRenderAreas
+}
+
+class VkDeviceGroupCommandBufferBeginInfo {
+    VkStructureType    sType
+    const void*        pNext
+    u32                deviceMask
+}
+
+class VkDeviceGroupSubmitInfo {
+    VkStructureType             sType
+    const void*                 pNext
+    u32                         waitSemaphoreCount
+    const u32*                  pWaitSemaphoreDeviceIndices
+    u32                         commandBufferCount
+    const u32*                  pCommandBufferDeviceMasks
+    u32                         signalSemaphoreCount
+    const u32*                  pSignalSemaphoreDeviceIndices
+}
+
+class VkDeviceGroupBindSparseInfo {
+    VkStructureType    sType
+    const void*        pNext
+    u32                resourceDeviceIndex
+    u32                memoryDeviceIndex
+}
+
+class VkBindBufferMemoryDeviceGroupInfo {
+    VkStructureType                     sType
+    const void*                         pNext
+    u32                                 deviceIndexCount
+    const u32*                          pDeviceIndices
+}
+
+class VkBindImageMemoryDeviceGroupInfo {
+    VkStructureType                     sType
+    const void*                         pNext
+    u32                                 deviceIndexCount
+    const u32*                          pDeviceIndices
+    u32                                 splitInstanceBindRegionCount
+    const VkRect2D*                     pSplitInstanceBindRegions
+}
+
+class VkPhysicalDeviceGroupProperties {
+    VkStructureType                             sType
+    void*                                       pNext
+    u32                                         physicalDeviceCount
+    VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE]  physicalDevices
+    VkBool32                                    subsetAllocation
+}
+
+class VkDeviceGroupDeviceCreateInfo {
+    VkStructureType            sType
+    const void*                pNext
+    u32                        physicalDeviceCount
+    const VkPhysicalDevice*    pPhysicalDevices
+}
+
+class VkBufferMemoryRequirementsInfo2 {
+    VkStructureType    sType
+    const void*        pNext
+    VkBuffer           buffer
+}
+
+class VkImageMemoryRequirementsInfo2 {
+    VkStructureType    sType
+    const void*        pNext
+    VkImage            image
+}
+
+class VkImageSparseMemoryRequirementsInfo2 {
+    VkStructureType    sType
+    const void*        pNext
+    VkImage            image
+}
+
+class VkMemoryRequirements2 {
+    VkStructureType         sType
+    void*                   pNext
+    VkMemoryRequirements    memoryRequirements
+}
+
+class VkSparseImageMemoryRequirements2 {
+    VkStructureType                    sType
+    void*                              pNext
+    VkSparseImageMemoryRequirements    memoryRequirements
+}
+
+class VkPhysicalDeviceFeatures2 {
+    VkStructureType             sType
+    void*                       pNext
+    VkPhysicalDeviceFeatures    features
+}
+
+class VkPhysicalDeviceProperties2 {
+    VkStructureType               sType
+    void*                         pNext
+    VkPhysicalDeviceProperties    properties
+}
+
+class VkFormatProperties2 {
+    VkStructureType       sType
+    void*                 pNext
+    VkFormatProperties    formatProperties
+}
+
+class VkImageFormatProperties2 {
+    VkStructureType            sType
+    void*                      pNext
+    VkImageFormatProperties    imageFormatProperties
+}
+
+class VkPhysicalDeviceImageFormatInfo2 {
+    VkStructureType       sType
+    const void*           pNext
+    VkFormat              format
+    VkImageType           type
+    VkImageTiling         tiling
+    VkImageUsageFlags     usage
+    VkImageCreateFlags    flags
+}
+
+class VkQueueFamilyProperties2 {
+    VkStructureType            sType
+    void*                      pNext
+    VkQueueFamilyProperties    queueFamilyProperties
+}
+
+class VkPhysicalDeviceMemoryProperties2 {
+    VkStructureType                     sType
+    void*                               pNext
+    VkPhysicalDeviceMemoryProperties    memoryProperties
+}
+
+class VkSparseImageFormatProperties2 {
+    VkStructureType                  sType
+    void*                            pNext
+    VkSparseImageFormatProperties    properties
+}
+
+class VkPhysicalDeviceSparseImageFormatInfo2 {
+    VkStructureType          sType
+    const void*              pNext
+    VkFormat                 format
+    VkImageType              type
+    VkSampleCountFlagBits    samples
+    VkImageUsageFlags        usage
+    VkImageTiling            tiling
+}
+
+class VkPhysicalDevicePointClippingProperties {
+    VkStructureType            sType
+    void*                      pNext
+    VkPointClippingBehavior    pointClippingBehavior
+}
+
+class VkInputAttachmentAspectReference {
+    u32                   subpass
+    u32                   inputAttachmentIndex
+    VkImageAspectFlags    aspectMask
+}
+
+class VkRenderPassInputAttachmentAspectCreateInfo {
+    VkStructureType                            sType
+    const void*                                pNext
+    u32                                        aspectReferenceCount
+    const VkInputAttachmentAspectReference*    pAspectReferences
+}
+
+class VkImageViewUsageCreateInfo {
+    VkStructureType      sType
+    const void*          pNext
+    VkImageUsageFlags    usage
+}
+
+class VkPipelineTessellationDomainOriginStateCreateInfo {
+    VkStructureType               sType
+    const void*                   pNext
+    VkTessellationDomainOrigin    domainOrigin
+}
+
+class VkRenderPassMultiviewCreateInfo {
+    VkStructureType    sType
+    const void*        pNext
+    u32                subpassCount
+    const u32*         pViewMasks
+    u32                dependencyCount
+    const s32*         pViewOffsets
+    u32                correlationMaskCount
+    const u32*         pCorrelationMasks
+}
+
+class VkPhysicalDeviceMultiviewFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           multiview
+    VkBool32           multiviewGeometryShader
+    VkBool32           multiviewTessellationShader
+}
+
+class VkPhysicalDeviceMultiviewProperties {
+    VkStructureType    sType
+    void*              pNext
+    u32                maxMultiviewViewCount
+    u32                maxMultiviewInstanceIndex
+}
+
+class VkPhysicalDeviceVariablePointerFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           variablePointersStorageBuffer
+    VkBool32           variablePointers
+}
+
+class VkPhysicalDeviceProtectedMemoryFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           protectedMemory
+}
+
+class VkPhysicalDeviceProtectedMemoryProperties {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           protectedNoFault
+}
+
+class VkDeviceQueueInfo2 {
+    VkStructureType             sType
+    const void*                 pNext
+    VkDeviceQueueCreateFlags    flags
+    u32                         queueFamilyIndex
+    u32                         queueIndex
+}
+
+class VkProtectedSubmitInfo {
+    VkStructureType    sType
+    const void*        pNext
+    VkBool32           protectedSubmit
+}
+
+class VkSamplerYcbcrConversionCreateInfo {
+    VkStructureType                  sType
+    const void*                      pNext
+    VkFormat                         format
+    VkSamplerYcbcrModelConversion    ycbcrModel
+    VkSamplerYcbcrRange              ycbcrRange
+    VkComponentMapping               components
+    VkChromaLocation                 xChromaOffset
+    VkChromaLocation                 yChromaOffset
+    VkFilter                         chromaFilter
+    VkBool32                         forceExplicitReconstruction
+}
+
+class VkSamplerYcbcrConversionInfo {
+    VkStructureType             sType
+    const void*                 pNext
+    VkSamplerYcbcrConversion    conversion
+}
+
+class VkBindImagePlaneMemoryInfo {
+    VkStructureType          sType
+    const void*              pNext
+    VkImageAspectFlagBits    planeAspect
+}
+
+class VkImagePlaneMemoryRequirementsInfo {
+    VkStructureType          sType
+    const void*              pNext
+    VkImageAspectFlagBits    planeAspect
+}
+
+class VkPhysicalDeviceSamplerYcbcrConversionFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           samplerYcbcrConversion
+}
+
+class VkSamplerYcbcrConversionImageFormatProperties {
+    VkStructureType    sType
+    void*              pNext
+    u32                combinedImageSamplerDescriptorCount
+}
+
+class VkDescriptorUpdateTemplateEntry {
+    u32                                 dstBinding
+    u32                                 dstArrayElement
+    u32                                 descriptorCount
+    VkDescriptorType                    descriptorType
+    platform.size_t                     offset
+    platform.size_t                     stride
+}
+
+class VkDescriptorUpdateTemplateCreateInfo {
+    VkStructureType                           sType
+    void*                                     pNext
+    VkDescriptorUpdateTemplateCreateFlags     flags
+    u32                                       descriptorUpdateEntryCount
+    const VkDescriptorUpdateTemplateEntry*    pDescriptorUpdateEntries
+    VkDescriptorUpdateTemplateType            templateType
+    VkDescriptorSetLayout                     descriptorSetLayout
+    VkPipelineBindPoint                       pipelineBindPoint
+    VkPipelineLayout                          pipelineLayout
+    u32                                       set
+}
+
+class VkExternalMemoryProperties {
+    VkExternalMemoryFeatureFlags       externalMemoryFeatures
+    VkExternalMemoryHandleTypeFlags    exportFromImportedHandleTypes
+    VkExternalMemoryHandleTypeFlags    compatibleHandleTypes
+}
+
+class VkPhysicalDeviceExternalImageFormatInfo {
+    VkStructureType                       sType
+    const void*                           pNext
+    VkExternalMemoryHandleTypeFlagBits    handleType
+}
+
+class VkExternalImageFormatProperties {
+    VkStructureType               sType
+    void*                         pNext
+    VkExternalMemoryProperties    externalMemoryProperties
+}
+
+class VkPhysicalDeviceExternalBufferInfo {
+    VkStructureType                       sType
+    const void*                           pNext
+    VkBufferCreateFlags                   flags
+    VkBufferUsageFlags                    usage
+    VkExternalMemoryHandleTypeFlagBits    handleType
+}
+
+class VkExternalBufferProperties {
+    VkStructureType               sType
+    void*                         pNext
+    VkExternalMemoryProperties    externalMemoryProperties
+}
+
+class VkPhysicalDeviceIDProperties {
+    VkStructureType    sType
+    void*              pNext
+    u8[VK_UUID_SIZE]   deviceUUID
+    u8[VK_UUID_SIZE]   driverUUID
+    u8[VK_LUID_SIZE]   deviceLUID
+    u32                deviceNodeMask
+    VkBool32           deviceLUIDValid
+}
+
+class VkExternalMemoryImageCreateInfo {
+    VkStructureType                    sType
+    const void*                        pNext
+    VkExternalMemoryHandleTypeFlags    handleTypes
+}
+
+class VkExternalMemoryBufferCreateInfo {
+    VkStructureType                    sType
+    const void*                        pNext
+    VkExternalMemoryHandleTypeFlags    handleTypes
+}
+
+class VkExportMemoryAllocateInfo {
+    VkStructureType                    sType
+    const void*                        pNext
+    VkExternalMemoryHandleTypeFlags    handleTypes
+}
+
+class VkPhysicalDeviceExternalFenceInfo {
+    VkStructureType                      sType
+    const void*                          pNext
+    VkExternalFenceHandleTypeFlagBits    handleType
+}
+
+class VkExternalFenceProperties {
+    VkStructureType                   sType
+    void*                             pNext
+    VkExternalFenceHandleTypeFlags    exportFromImportedHandleTypes
+    VkExternalFenceHandleTypeFlags    compatibleHandleTypes
+    VkExternalFenceFeatureFlags       externalFenceFeatures
+}
+
+class VkExportFenceCreateInfo {
+    VkStructureType                   sType
+    const void*                       pNext
+    VkExternalFenceHandleTypeFlags    handleTypes
+}
+
+class VkExportSemaphoreCreateInfo {
+    VkStructureType                       sType
+    const void*                           pNext
+    VkExternalSemaphoreHandleTypeFlags    handleTypes
+}
+
+class VkPhysicalDeviceExternalSemaphoreInfo {
+    VkStructureType                          sType
+    const void*                              pNext
+    VkExternalSemaphoreHandleTypeFlagBits    handleType
+}
+
+class VkExternalSemaphoreProperties {
+    VkStructureType                       sType
+    void*                                 pNext
+    VkExternalSemaphoreHandleTypeFlags    exportFromImportedHandleTypes
+    VkExternalSemaphoreHandleTypeFlags    compatibleHandleTypes
+    VkExternalSemaphoreFeatureFlags       externalSemaphoreFeatures
+}
+
+class VkPhysicalDeviceMaintenance3Properties {
+    VkStructureType    sType
+    void*              pNext
+    u32                maxPerSetDescriptors
+    VkDeviceSize       maxMemoryAllocationSize
+}
+
+class VkDescriptorSetLayoutSupport {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           supported
+}
+
+class VkPhysicalDeviceShaderDrawParameterFeatures {
+    VkStructureType    sType
+    void*              pNext
+    VkBool32           shaderDrawParameters
+}
+
+
 @extension("VK_KHR_surface") // 1
 class VkSurfaceCapabilitiesKHR {
     u32                                         minImageCount
@@ -3511,6 +4679,62 @@
     VkResult*                                   pResults
 }
 
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkImageSwapchainCreateInfoKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkSwapchainKHR                              swapchain
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkBindImageMemorySwapchainInfoKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkSwapchainKHR                              swapchain
+    u32                                         imageIndex
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkAcquireNextImageInfoKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkSwapchainKHR                              swapchain
+    u64                                         timeout
+    VkSemaphore                                 semaphore
+    VkFence                                     fence
+    u32                                         deviceMask
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupPresentCapabilitiesKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    u32[VK_MAX_DEVICE_GROUP_SIZE]               presentMask
+    VkDeviceGroupPresentModeFlagsKHR            modes
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupPresentInfoKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    u32                                         swapchainCount
+    const u32*                                  pDeviceMasks
+    VkDeviceGroupPresentModeFlagBitsKHR         mode
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+class VkDeviceGroupSwapchainCreateInfoKHR {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkDeviceGroupPresentModeFlagsKHR            modes
+}
+
 @extension("VK_KHR_display") // 3
 class VkDisplayPropertiesKHR {
     VkDisplayKHR                                display
@@ -3741,8 +4965,28 @@
     VkBool32                                    supportsTextureGatherLODBiasAMD
 }
 
-@extension("VK_KHX_multiview") // 54
-class VkRenderPassMultiviewCreateInfoKHX {
+@extension("VK_AMD_shader_info") // 43
+class VkShaderResourceUsageAMD {
+    u32                                         numUsedVgprs
+    u32                                         numUsedSgprs
+    u32                                         ldsSizePerLocalWorkGroup
+    platform.size_t                             ldsUsageSizeInBytes
+    platform.size_t                             scratchMemUsageInBytes
+}
+
+@extension("VK_AMD_shader_info") // 43
+class VkShaderStatisticsInfoAMD {
+    VkShaderStageFlags                          shaderStageMask
+    VkShaderResourceUsageAMD                    resourceUsage
+    u32                                         numPhysicalVgprs
+    u32                                         numPhysicalSgprs
+    u32                                         numAvailableVgprs
+    u32                                         numAvailableSgprs
+    u32[3]                                      computeWorkGroupSize
+}
+
+@extension("VK_KHR_multiview") // 54
+class VkRenderPassMultiviewCreateInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         subpassCount
@@ -3753,8 +4997,8 @@
     const u32*                                  pCorrelationMasks
 }
 
-@extension("VK_KHX_multiview") // 54
-class VkPhysicalDeviceMultiviewFeaturesKHX {
+@extension("VK_KHR_multiview") // 54
+class VkPhysicalDeviceMultiviewFeaturesKHR {
     VkStructureType                             sType
     void*                                       pNext
     VkBool32                                    multiview
@@ -3762,8 +5006,8 @@
     VkBool32                                    multiviewTessellationShader
 }
 
-@extension("VK_KHX_multiview") // 54
-class VkPhysicalDeviceMultiviewPropertiesKHX {
+@extension("VK_KHR_multiview") // 54
+class VkPhysicalDeviceMultiviewPropertiesKHR {
     VkStructureType                             sType
     void*                                       pNext
     u32                                         maxMultiviewViewCount
@@ -3892,40 +5136,34 @@
     VkImageTiling                               tiling
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkMemoryAllocateFlagsInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkMemoryAllocateFlagsInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
-    VkMemoryAllocateFlagsKHX                    flags
+    VkMemoryAllocateFlagsKHR                    flags
     u32                                         deviceMask
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkBindBufferMemoryInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkBindBufferMemoryDeviceGroupInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
-    VkBuffer                                    buffer
-    VkDeviceMemory                              memory
-    VkDeviceSize                                memoryOffset
     u32                                         deviceIndexCount
     const u32*                                  pDeviceIndices
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkBindImageMemoryInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkBindImageMemoryDeviceGroupInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
-    VkImage                                     image
-    VkDeviceMemory                              memory
-    VkDeviceSize                                memoryOffset
     u32                                         deviceIndexCount
     const u32*                                  pDeviceIndices
     u32                                         SFRRectCount
     const VkRect2D*                             pSFRRects
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupRenderPassBeginInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupRenderPassBeginInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         deviceMask
@@ -3933,15 +5171,15 @@
     const VkRect2D*                             pDeviceRenderAreas
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupCommandBufferBeginInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupCommandBufferBeginInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         deviceMask
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupSubmitInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupSubmitInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         waitSemaphoreCount
@@ -3952,64 +5190,14 @@
     const u32*                                  pSignalSemaphoreDeviceIndices
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupBindSparseInfoKHX {
+@extension("VK_KHR_device_group") // 61
+class VkDeviceGroupBindSparseInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         resourceDeviceIndex
     u32                                         memoryDeviceIndex
 }
 
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupPresentCapabilitiesKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    u32[VK_MAX_DEVICE_GROUP_SIZE_KHX]           presentMask
-    VkDeviceGroupPresentModeFlagsKHX            modes
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkImageSwapchainCreateInfoKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkSwapchainKHR                              swapchain
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkBindImageMemorySwapchainInfoKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkSwapchainKHR                              swapchain
-    u32                                         imageIndex
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkAcquireNextImageInfoKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkSwapchainKHR                              swapchain
-    u64                                         timeout
-    VkSemaphore                                 semaphore
-    VkFence                                     fence
-    u32                                         deviceMask
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupPresentInfoKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    u32                                         swapchainCount
-    const u32*                                  pDeviceMasks
-    VkDeviceGroupPresentModeFlagBitsKHX         mode
-}
-
-@extension("VK_KHX_device_group") // 61
-class VkDeviceGroupSwapchainCreateInfoKHX {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkDeviceGroupPresentModeFlagsKHX            modes
-}
-
 @extension("VK_EXT_validation_flags") // 62
 class VkValidationFlagsEXT {
     VkStructureType                             sType
@@ -4026,17 +5214,17 @@
     void*                                       window
 }
 
-@extension("VK_KHX_device_group_creation") // 71
-class VkPhysicalDeviceGroupPropertiesKHX {
+@extension("VK_KHR_device_group_creation") // 71
+class VkPhysicalDeviceGroupPropertiesKHR {
     VkStructureType                                 sType
     void*                                           pNext
     u32                                             physicalDeviceCount
-    VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX]  physicalDevices
+    VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE]      physicalDevices
     VkBool32                                        subsetAllocation
 }
 
-@extension("VK_KHX_device_group_creation") // 71
-class VkDeviceGroupDeviceCreateInfoKHX {
+@extension("VK_KHR_device_group_creation") // 71
+class VkDeviceGroupDeviceCreateInfoKHR {
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         physicalDeviceCount
@@ -4086,7 +5274,7 @@
     void*                                       pNext
     u8[VK_UUID_SIZE]                            deviceUUID
     u8[VK_UUID_SIZE]                            driverUUID
-    u8[VK_LUID_SIZE_KHR]                        deviceLUID
+    u8[VK_LUID_SIZE]                            deviceLUID
     u32                                         deviceNodeMask
     VkBool32                                    deviceLUIDValid
 }
@@ -4578,6 +5766,30 @@
     const VkRect2D*                                 pDiscardRectangles
 }
 
+@extension("VK_EXT_conservative_rasterization") // 102
+class VkPhysicalDeviceConservativeRasterizationPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    f32                                             primitiveOverestimationSize
+    f32                                             maxExtraPrimitiveOverestimationSize
+    f32                                             extraPrimitiveOverestimationSizeGranularity
+    VkBool32                                        primitiveUnderestimation
+    VkBool32                                        conservativePointAndLineRasterization
+    VkBool32                                        degenerateTrianglesRasterized
+    VkBool32                                        degenerateLinesRasterized
+    VkBool32                                        fullyCoveredFragmentShaderInputVariable
+    VkBool32                                        conservativeRasterizationPostDepthCoverage
+}
+
+@extension("VK_EXT_conservative_rasterization") // 102
+class VkPipelineRasterizationConservativeStateCreateInfoEXT {
+    VkStructureType                                           sType
+    const void*                                               pNext
+    VkPipelineRasterizationConservativeStateCreateFlagsEXT    flags
+    VkConservativeRasterizationModeEXT                        conservativeRasterizationMode
+    f32                                                       extraPrimitiveOverestimationSize
+}
+
 @extension("VK_EXT_hdr_metadata") // 106
 class VkXYColorEXT {
     f32                                             x
@@ -4674,6 +5886,42 @@
     VkExternalFenceHandleTypeFlagBitsKHR            handleType
 }
 
+@extension("VK_KHR_maintenance2") // 118
+class VkPhysicalDevicePointClippingPropertiesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkPointClippingBehaviorKHR                      pointClippingBehavior
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkInputAttachmentAspectReferenceKHR {
+    u32                                             subpass
+    u32                                             inputAttachmentIndex
+    VkImageAspectFlags                              aspectMask
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkRenderPassInputAttachmentAspectCreateInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             aspectReferenceCount
+    const VkInputAttachmentAspectReferenceKHR*      pAspectReferences
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkImageViewUsageCreateInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImageUsageFlags                               usage
+}
+
+@extension("VK_KHR_maintenance2") // 118
+class VkPipelineTessellationDomainOriginStateCreateInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkTessellationDomainOriginKHR                   domainOrigin
+}
+
 @extension("VK_KHR_get_surface_capabilities2") // 120
 class VkPhysicalDeviceSurfaceInfo2KHR {
     VkStructureType                                 sType
@@ -4735,6 +5983,111 @@
     VkBuffer                                        buffer
 }
 
+@extension("VK_EXT_debug_utils") // 129
+class VkDebugUtilsObjectNameInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkObjectType                                    objectType
+    u64                                             objectHandle
+    const char*                                     pObjectName
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+class VkDebugUtilsObjectTagInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkObjectType                                    objectType
+    u64                                             objectHandle
+    u64                                             tagName
+    platform.size_t                                 tagSize
+    const void*                                     pTag
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+class VkDebugUtilsLabelEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    const char*                                     pLabelName
+    f32[4]                                          color
+}
+
+@extension("VK_EXT_debug_utils") // 129
+class VkDebugUtilsMessengerCallbackDataEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkDebugUtilsMessengerCallbackDataFlagsEXT       flags
+    const char*                                     pMessageIdName
+    s32                                             messageIdNumber
+    const char*                                     pMessage
+    u32                                             queueLabelCount
+    VkDebugUtilsLabelEXT*                           pQueueLabels
+    u32                                             cmdBufLabelCount
+    VkDebugUtilsLabelEXT*                           pCmdBufLabels
+    u32                                             objectCount
+    VkDebugUtilsObjectNameInfoEXT*                  pObjects
+}
+
+@extension("VK_EXT_debug_utils") // 129
+class VkDebugUtilsMessengerCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkDebugUtilsMessengerCreateFlagsEXT             flags
+    VkDebugUtilsMessageSeverityFlagsEXT             messageSeverity
+    VkDebugUtilsMessageTypeFlagsEXT                 messageType
+    PFN_vkDebugUtilsMessengerCallbackEXT            pfnUserCallback
+    void*                                           pUserData
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 131
+class VkAndroidHardwareBufferUsageANDROID {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u64                                             androidHardwareBufferUsage
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+class VkAndroidHardwareBufferPropertiesANDROID {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkDeviceSize                                    allocationSize
+    u32                                             memoryTypeBits
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+class VkAndroidHardwareBufferFormatPropertiesANDROID {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkFormat                                        format
+    u64                                             externalFormat
+    VkFormatFeatureFlags                            formatFeatures
+    VkComponentMapping                              samplerYcbcrConversionComponents
+    VkSamplerYcbcrModelConversion                   suggestedYcbcrModel
+    VkSamplerYcbcrRange                             suggestedYcbcrRange
+    VkChromaLocation                                suggestedXChromaOffset
+    VkChromaLocation                                suggestedYChromaOffset
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+class VkImportAndroidHardwareBufferInfoANDROID {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    platform.AHardwareBuffer*                       buffer
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+class VkMemoryGetAndroidHardwareBufferInfoANDROID {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkDeviceMemory                                  memory
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+class VkExternalFormatANDROID {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u64                                             externalFormat
+}
+
 @extension("VK_EXT_sampler_filter_minmax") // 131
 class VkSamplerReductionModeCreateInfoEXT {
     VkStructureType                                 sType
@@ -4750,6 +6103,70 @@
     VkBool32                                        filterMinmaxImageComponentMapping
 }
 
+@extension("VK_EXT_sample_locations") // 144
+class VkSampleLocationEXT {
+    f32                                             x
+    f32                                             y
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkSampleLocationsInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkSampleCountFlagBits                           sampleLocationsPerPixel
+    VkExtent2D                                      sampleLocationGridSize
+    u32                                             sampleLocationsCount
+    const VkSampleLocationEXT*                      pSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkAttachmentSampleLocationsEXT {
+    u32                                             attachmentIndex
+    VkSampleLocationsInfoEXT                        sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkSubpassSampleLocationsEXT {
+    u32                                             subpassIndex
+    VkSampleLocationsInfoEXT                        sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkRenderPassSampleLocationsBeginInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             attachmentInitialSampleLocationsCount
+    const VkAttachmentSampleLocationsEXT*           pAttachmentInitialSampleLocations
+    u32                                             postSubpassSampleLocationsCount
+    const VkSubpassSampleLocationsEXT*              pPostSubpassSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkPipelineSampleLocationsStateCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkBool32                                        sampleLocationsEnable
+    VkSampleLocationsInfoEXT                        sampleLocationsInfo
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkPhysicalDeviceSampleLocationsPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkSampleCountFlags                              sampleLocationSampleCounts
+    VkExtent2D                                      maxSampleLocationGridSize
+    f32[2]                                          sampleLocationCoordinateRange
+    u32                                             sampleLocationSubPixelBits
+    VkBool32                                        variableSampleLocations
+}
+
+@extension("VK_EXT_sample_locations") // 144
+class VkMultisamplePropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkExtent2D                                      maxSampleLocationGridSize
+}
+
 @extension("VK_KHR_get_memory_requirements2") // 147
 class VkBufferMemoryRequirementsInfo2KHR {
     VkStructureType                                 sType
@@ -4785,6 +6202,14 @@
     VkSparseImageMemoryRequirements                 memoryRequirements
 }
 
+@extension("VK_KHR_image_format_list") // 148
+class VkImageFormatListCreateInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             viewFormatCount
+    const VkFormat*                                 pViewFormats
+}
+
 @extension("VK_EXT_blend_operation_advanced") // 149
 class VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
     VkStructureType                                 sType
@@ -4833,6 +6258,134 @@
     const f32*                                      pCoverageModulationTable
 }
 
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionCreateInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkFormat                                        format
+    VkSamplerYcbcrModelConversionKHR                ycbcrModel
+    VkSamplerYcbcrRangeKHR                          ycbcrRange
+    VkComponentMapping                              components
+    VkChromaLocationKHR                             xChromaOffset
+    VkChromaLocationKHR                             yChromaOffset
+    VkFilter                                        chromaFilter
+    VkBool32                                        forceExplicitReconstruction
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkSamplerYcbcrConversionKHR                     conversion
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkBindImagePlaneMemoryInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImageAspectFlagBits                           planeAspect
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkImagePlaneMemoryRequirementsInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImageAspectFlagBits                           planeAspect
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        samplerYcbcrConversion
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+class VkSamplerYcbcrConversionImageFormatPropertiesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             combinedImageSamplerDescriptorCount
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+class VkBindBufferMemoryInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkBuffer                                        buffer
+    VkDeviceMemory                                  memory
+    VkDeviceSize                                    memoryOffset
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+class VkBindImageMemoryInfoKHR {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImage                                         image
+    VkDeviceMemory                                  memory
+    VkDeviceSize                                    memoryOffset
+}
+
+@extension("VK_EXT_validation_cache") // 161
+class VkValidationCacheCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkValidationCacheCreateFlagsEXT                 flags
+    platform.size_t                                 initialDataSize
+    const void*                                     pInitialData
+}
+
+@extension("VK_EXT_validation_cache") // 161
+class VkShaderModuleValidationCacheCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkValidationCacheEXT                            validationCache
+}
+
+@extension("VK_KHR_maintenance3") // 169
+class VkPhysicalDeviceMaintenance3PropertiesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             maxPerSetDescriptors
+    VkDeviceSize                                    maxMemoryAllocationSize
+}
+
+@extension("VK_KHR_maintenance3") // 169
+class VkDescriptorSetLayoutSupportKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        supported
+}
+
+@extension("VK_EXT_global_priority") // 175
+class VkDeviceQueueGlobalPriorityCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkQueueGlobalPriorityEXT                        globalPriority
+}
+
+@extension("VK_EXT_external_memory_host") // 179
+class VkImportMemoryHostPointerInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkExternalMemoryHandleTypeFlagBits              handleType
+    void*                                           pHostPointer
+}
+
+@extension("VK_EXT_external_memory_host") // 179
+class VkMemoryHostPointerPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             memoryTypeBits
+}
+
+@extension("VK_EXT_external_memory_host") // 179
+class VkPhysicalDeviceExternalMemoryHostPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkDeviceSize                                    minImportedHostPointerAlignment
+}
+
+
 ////////////////
 //  Commands  //
 ////////////////
@@ -7028,6 +8581,241 @@
     }
 }
 
+//@vulkan1_1 functions
+
+@vulkan1_1
+cmd VkResult vkEnumerateInstanceVersion(
+        u32*                                            pApiVersion) {
+    return ?
+}
+
+@vulkan1_1
+cmd VkResult vkBindBufferMemory2(
+        VkDevice                                        device,
+        u32                                             bindInfoCount,
+        const VkBindBufferMemoryInfo*                   pBindInfos) {
+    return ?
+}
+
+@vulkan1_1
+cmd VkResult vkBindImageMemory2(
+        VkDevice                                        device,
+        u32                                             bindInfoCount,
+        const VkBindImageMemoryInfo*                    pBindInfos) {
+    return ?
+}
+
+@vulkan1_1
+cmd void vkGetDeviceGroupPeerMemoryFeatures(
+        VkDevice                                    device,
+        u32                                         heapIndex,
+        u32                                         localDeviceIndex,
+        u32                                         remoteDeviceIndex,
+        VkPeerMemoryFeatureFlags*                   pPeerMemoryFeatures) {
+}
+
+@vulkan1_1
+cmd void vkCmdSetDeviceMask(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         deviceMask) {
+}
+
+@vulkan1_1
+cmd void vkCmdDispatchBase(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         baseGroupX,
+        u32                                         baseGroupY,
+        u32                                         baseGroupZ,
+        u32                                         groupCountX,
+        u32                                         groupCountY,
+        u32                                         groupCountZ) {
+}
+
+@threadSafety("system")
+@vulkan1_1
+cmd VkResult vkEnumeratePhysicalDeviceGroups(
+        VkInstance                                  instance,
+        u32*                                        pPhysicalDeviceGroupCount,
+        VkPhysicalDeviceGroupProperties*            pPhysicalDeviceGroupProperties) {
+    instanceObject := GetInstance(instance)
+
+    physicalDeviceGroupCount := as!u32(?)
+    pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
+    physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
+
+    for i in (0 .. physicalDeviceGroupCount) {
+        physicalDevice := ?
+        physicalDevices[i] = physicalDevice
+        if !(physicalDevice in State.PhysicalDevices) {
+            State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
+        }
+    }
+
+    return ?
+}
+
+@vulkan1_1
+cmd void vkGetImageMemoryRequirements2(
+        VkDevice                                    device,
+        const VkImageMemoryRequirementsInfo2*       pInfo,
+        VkMemoryRequirements2*                      pMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetBufferMemoryRequirements2(
+        VkDevice                                    device,
+        const VkBufferMemoryRequirementsInfo2*      pInfo,
+        VkMemoryRequirements2*                      pMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetImageSparseMemoryRequirements2(
+        VkDevice                                        device,
+        const VkImageSparseMemoryRequirementsInfo2*     pInfo,
+        u32*                                            pSparseMemoryRequirementCount,
+        VkSparseImageMemoryRequirements2*               pSparseMemoryRequirements) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceFeatures2(
+        VkPhysicalDevice                            physicalDevice,
+        VkPhysicalDeviceFeatures2*                  pFeatures) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceProperties2(
+        VkPhysicalDevice                            physicalDevice,
+        VkPhysicalDeviceProperties2*                pProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceFormatProperties2(
+        VkPhysicalDevice                            physicalDevice,
+        VkFormat                                    format,
+        VkFormatProperties2*                        pFormatProperties) {
+}
+
+@vulkan1_1
+cmd VkResult vkGetPhysicalDeviceImageFormatProperties2(
+        VkPhysicalDevice                            physicalDevice,
+        const VkPhysicalDeviceImageFormatInfo2*     pImageFormatInfo,
+        VkImageFormatProperties2*                   pImageFormatProperties) {
+    return ?
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceQueueFamilyProperties2(
+        VkPhysicalDevice                            physicalDevice,
+        u32*                                        pQueueFamilyPropertyCount,
+        VkQueueFamilyProperties2*                   pQueueFamilyProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceMemoryProperties2(
+        VkPhysicalDevice                            physicalDevice,
+        VkPhysicalDeviceMemoryProperties2*          pMemoryProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceSparseImageFormatProperties2(
+        VkPhysicalDevice                                    physicalDevice,
+        const VkPhysicalDeviceSparseImageFormatInfo2*       pFormatInfo,
+        u32*                                                pPropertyCount,
+        VkSparseImageFormatProperties2*                     pProperties) {
+}
+
+@vulkan1_1
+cmd void vkTrimCommandPool(
+        VkDevice                                    device,
+        VkCommandPool                               commandPool,
+        VkCommandPoolTrimFlags                      flags) {
+}
+
+
+@vulkan1_1
+cmd void vkGetDeviceQueue2(
+        VkDevice                                    device,
+        const VkDeviceQueueInfo2*                   pQueueInfo,
+        VkQueue*                                    pQueue) {
+    deviceObject := GetDevice(device)
+
+    queue := ?
+    pQueue[0] = queue
+
+    if !(queue in State.Queues) {
+        State.Queues[queue] = new!QueueObject(device: device)
+    }
+}
+
+@vulkan1_1
+cmd VkResult vkCreateSamplerYcbcrConversion(
+        VkDevice                                        device,
+        const VkSamplerYcbcrConversionCreateInfo*       pCreateInfo,
+        const VkAllocationCallbacks*                    pAllocator,
+        VkSamplerYcbcrConversion*                       pYcbcrConversion) {
+    return ?
+}
+
+@vulkan1_1
+cmd void vkDestroySamplerYcbcrConversion(
+        VkDevice                                        device,
+        VkSamplerYcbcrConversion                        ycbcrConversion,
+        const VkAllocationCallbacks*                    pAllocator) {
+}
+
+@vulkan1_1
+cmd VkResult vkCreateDescriptorUpdateTemplate(
+        VkDevice                                    device,
+        const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+        const VkAllocationCallbacks*                pAllocator,
+        VkDescriptorUpdateTemplate*                 pDescriptorUpdateTemplate) {
+    return ?
+}
+
+@vulkan1_1
+cmd void vkDestroyDescriptorUpdateTemplate(
+        VkDevice                                    device,
+        VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+        const VkAllocationCallbacks*                pAllocator) {
+}
+
+@vulkan1_1
+cmd void vkUpdateDescriptorSetWithTemplate(
+        VkDevice                                    device,
+        VkDescriptorSet                             descriptorSet,
+        VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+        const void*                                 pData) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalBufferProperties(
+        VkPhysicalDevice                                physicalDevice,
+        const VkPhysicalDeviceExternalBufferInfo*       pExternalBufferInfo,
+        VkExternalBufferProperties*                     pExternalBufferProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalFenceProperties(
+        VkPhysicalDevice                            physicalDevice,
+        const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
+        VkExternalFenceProperties*                  pExternalFenceProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetPhysicalDeviceExternalSemaphoreProperties(
+        VkPhysicalDevice                                physicalDevice,
+        const VkPhysicalDeviceExternalSemaphoreInfo*    pExternalSemaphoreInfo,
+        VkExternalSemaphoreProperties*                  pExternalSemaphoreProperties) {
+}
+
+@vulkan1_1
+cmd void vkGetDescriptorSetLayoutSupport(
+        VkDevice                                    device,
+        const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+        VkDescriptorSetLayoutSupport*               pSupport) {
+}
+
+
 @extension("VK_KHR_surface") // 1
 cmd void vkDestroySurfaceKHR(
         VkInstance                                  instance,
@@ -7182,6 +8970,42 @@
     return ?
 }
 
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHR(
+        VkDevice                                    device,
+        VkDeviceGroupPresentCapabilitiesKHR*        pDeviceGroupPresentCapabilities) {
+    return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetDeviceGroupSurfacePresentModesKHR(
+        VkDevice                                    device,
+        VkSurfaceKHR                                surface,
+        VkDeviceGroupPresentModeFlagsKHR*           pModes) {
+    return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkGetPhysicalDevicePresentRectanglesKHR(
+        VkPhysicalDevice                            physicalDevice,
+        VkSurfaceKHR                                surface,
+        u32*                                        pRectCount,
+        VkRect2D*                                   pRects) {
+    return ?
+}
+
+@vulkan1_1
+@extension("VK_KHR_swapchain") // 2
+cmd VkResult vkAcquireNextImage2KHR(
+        VkDevice                                    device,
+        const VkAcquireNextImageInfoKHR*            pAcquireInfo,
+        u32*                                        pImageIndex) {
+    return ?
+}
+
 @extension("VK_KHR_display") // 3
 cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR(
         VkPhysicalDevice                        physicalDevice,
@@ -7454,21 +9278,21 @@
 @extension("VK_EXT_debug_marker") // 23
 cmd VkResult vkDebugMarkerSetObjectTagEXT(
         VkDevice                                    device,
-        VkDebugMarkerObjectTagInfoEXT*              pTagInfo) {
+        const VkDebugMarkerObjectTagInfoEXT*        pTagInfo) {
     return ?
 }
 
 @extension("VK_EXT_debug_marker") // 23
 cmd VkResult vkDebugMarkerSetObjectNameEXT(
         VkDevice                                    device,
-        VkDebugMarkerObjectNameInfoEXT*             pNameInfo) {
+        const VkDebugMarkerObjectNameInfoEXT*       pNameInfo) {
     return ?
 }
 
 @extension("VK_EXT_debug_marker") // 23
 cmd void vkCmdDebugMarkerBeginEXT(
         VkCommandBuffer                             commandBuffer,
-        VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo) {
+        const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo) {
 }
 
 @extension("VK_EXT_debug_marker") // 23
@@ -7479,7 +9303,7 @@
 @extension("VK_EXT_debug_marker") // 23
 cmd void vkCmdDebugMarkerInsertEXT(
         VkCommandBuffer                             commandBuffer,
-        VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo) {
+        const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo) {
 }
 
 @extension("VK_AMD_draw_indirect_count") // 34
@@ -7504,6 +9328,17 @@
         u32                                         stride) {
 }
 
+@extension("VK_AMD_shader_info") // 43
+cmd VkResult vkGetShaderInfoAMD(
+        VkDevice                                    device,
+        VkPipeline                                  pipeline,
+        VkShaderStageFlagBits                       shaderStage,
+        VkShaderInfoTypeAMD                         infoType,
+        platform.size_t*                            pInfoSize,
+        void*                                       pInfo) {
+    return ?
+}
+
 @extension("VK_NV_external_memory_capabilities") // 56
 cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
         VkPhysicalDevice                            physicalDevice,
@@ -7574,62 +9409,24 @@
         VkSparseImageFormatProperties2KHR*                  pProperties) {
 }
 
-@extension("VK_KHX_device_group") // 61
-cmd void vkGetDeviceGroupPeerMemoryFeaturesKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkGetDeviceGroupPeerMemoryFeaturesKHR(
         VkDevice                                    device,
         u32                                         heapIndex,
         u32                                         localDeviceIndex,
         u32                                         remoteDeviceIndex,
-        VkPeerMemoryFeatureFlagsKHX*                pPeerMemoryFeatures) {
+        VkPeerMemoryFeatureFlagsKHR*                pPeerMemoryFeatures) {
 }
 
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkBindBufferMemory2KHX(
-        VkDevice                                    device,
-        u32                                         bindInfoCount,
-        const VkBindBufferMemoryInfoKHX*            pBindInfos) {
-    return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkBindImageMemory2KHX(
-        VkDevice                                    device,
-        u32                                         bindInfoCount,
-        const VkBindImageMemoryInfoKHX*             pBindInfos) {
-    return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd void vkCmdSetDeviceMaskKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkCmdSetDeviceMaskKHR(
         VkCommandBuffer                             commandBuffer,
         u32                                         deviceMask) {
 }
 
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHX(
-        VkDevice                                    device,
-        VkDeviceGroupPresentCapabilitiesKHX*        pDeviceGroupPresentCapabilities) {
-    return ?
-}
 
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetDeviceGroupSurfacePresentModesKHX(
-        VkDevice                                    device,
-        VkSurfaceKHR                                surface,
-        VkDeviceGroupPresentModeFlagsKHX*           pModes) {
-    return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkAcquireNextImage2KHX(
-        VkDevice                                    device,
-        const VkAcquireNextImageInfoKHX*            pAcquireInfo,
-        u32*                                        pImageIndex) {
-    return ?
-}
-
-@extension("VK_KHX_device_group") // 61
-cmd void vkCmdDispatchBaseKHX(
+@extension("VK_KHR_device_group") // 61
+cmd void vkCmdDispatchBaseKHR(
         VkCommandBuffer                             commandBuffer,
         u32                                         baseGroupX,
         u32                                         baseGroupY,
@@ -7639,15 +9436,6 @@
         u32                                         groupCountZ) {
 }
 
-@extension("VK_KHX_device_group") // 61
-cmd VkResult vkGetPhysicalDevicePresentRectanglesKHX(
-        VkPhysicalDevice                            physicalDevice,
-        VkSurfaceKHR                                surface,
-        u32*                                        pRectCount,
-        VkRect2D*                                   pRects) {
-    return ?
-}
-
 @extension("VK_NN_vi_surface") // 63
 cmd VkResult vkCreateViSurfaceNN(
         VkInstance                                  instance,
@@ -7664,11 +9452,26 @@
         VkCommandPoolTrimFlagsKHR                   flags) {
 }
 
-@extension("VK_KHX_device_group_creation") // 71
-cmd VkResult vkEnumeratePhysicalDeviceGroupsKHX(
+@extension("VK_KHR_device_group_creation") // 71
+@threadSafety("system")
+cmd VkResult vkEnumeratePhysicalDeviceGroupsKHR(
         VkInstance                                  instance,
         u32*                                        pPhysicalDeviceGroupCount,
-        VkPhysicalDeviceGroupPropertiesKHX*         pPhysicalDeviceGroupProperties) {
+        VkPhysicalDeviceGroupPropertiesKHR*         pPhysicalDeviceGroupProperties) {
+    instanceObject := GetInstance(instance)
+
+    physicalDeviceGroupCount := as!u32(?)
+    pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
+    physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
+
+    for i in (0 .. physicalDeviceGroupCount) {
+        physicalDevice := ?
+        physicalDevices[i] = physicalDevice
+        if !(physicalDevice in State.PhysicalDevices) {
+            State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
+        }
+    }
+
     return ?
 }
 
@@ -8058,6 +9861,118 @@
     return ?
 }
 
+@extension("VK_EXT_debug_utils") // 129
+@external type void* PFN_vkDebugUtilsMessengerCallbackEXT
+@extension("VK_EXT_debug_utils") // 129
+@pfn cmd VkBool32 vkDebugUtilsMessengerCallbackEXT(
+        VkDebugUtilsMessageSeverityFlagBitsEXT      messageSeverity,
+        VkDebugUtilsMessageTypeFlagsEXT             messageType,
+        const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
+        void*                                       pUserData) {
+    return ?
+}
+
+@extension("VK_EXT_debug_utils") // 129
+cmd VkResult vkSetDebugUtilsObjectNameEXT(
+        VkDevice                                    device,
+        const VkDebugUtilsObjectNameInfoEXT*        pNameInfo) {
+    return ?
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd VkResult vkSetDebugUtilsObjectTagEXT(
+        VkDevice                                    device,
+        const VkDebugUtilsObjectTagInfoEXT*         pTagInfo) {
+    return ?
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkQueueBeginDebugUtilsLabelEXT(
+        VkQueue                                     queue,
+        const VkDebugUtilsLabelEXT*                 pLabelInfo) {
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkQueueEndDebugUtilsLabelEXT(VkQueue       queue) {
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkQueueInsertDebugUtilsLabelEXT(
+        VkQueue                                     queue,
+        const VkDebugUtilsLabelEXT*                 pLabelInfo) {
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkCmdBeginDebugUtilsLabelEXT(
+        VkCommandBuffer                             commandBuffer,
+        const VkDebugUtilsLabelEXT*                 pLabelInfo) {
+}
+ 
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
+}
+
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkCmdInsertDebugUtilsLabelEXT(
+        VkCommandBuffer                             commandBuffer,
+        const VkDebugUtilsLabelEXT*                 pLabelInfo) {
+}
+
+@extension("VK_EXT_debug_utils") // 129
+cmd VkResult vkCreateDebugUtilsMessengerEXT(
+        VkInstance                                  instance,
+        const VkDebugUtilsMessengerCreateInfoEXT*   pCreateInfo,
+        const VkAllocationCallbacks*                pAllocator,
+        VkDebugUtilsMessengerEXT*                   pMessenger) {
+    return ?
+}
+
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkDestroyDebugUtilsMessengerEXT(
+        VkInstance                                  instance,
+        VkDebugUtilsMessengerEXT                    messenger,
+        const VkAllocationCallbacks*                pAllocator) {
+}
+
+@extension("VK_EXT_debug_utils") // 129
+cmd void vkSubmitDebugUtilsMessageEXT(
+        VkInstance                                  instance,
+        VkDebugUtilsMessageSeverityFlagBitsEXT      messageSeverity,
+        VkDebugUtilsMessageTypeFlagsEXT             messageTypes,
+        const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData) {
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does
+cmd VkResult vkGetAndroidHardwareBufferPropertiesANDROID(
+        VkDevice                                    device,
+        const platform.AHardwareBuffer*             buffer,
+        VkAndroidHardwareBufferPropertiesANDROID*   pProperties) {
+    return ?
+}
+
+@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
+@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does
+cmd VkResult vkGetMemoryAndroidHardwareBufferANDROID(
+        VkDevice                                            device,
+        const VkMemoryGetAndroidHardwareBufferInfoANDROID*  pInfo,
+        platform.AHardwareBuffer**                          pBuffer) {
+    return ?
+}
+
+@extension("VK_EXT_sample_locations") // 144
+cmd void vkCmdSetSampleLocationsEXT(
+        VkCommandBuffer                             commandBuffer,
+        const VkSampleLocationsInfoEXT*             pSampleLocationsInfo) {
+}
+
+@extension("VK_EXT_sample_locations") // 144
+cmd void vkGetPhysicalDeviceMultisamplePropertiesEXT(
+        VkPhysicalDevice                            physicalDevice,
+        VkSampleCountFlagBits                       samples,
+        VkMultisamplePropertiesEXT*                 pMultisampleProperties) {
+}
+
 @extension("VK_KHR_get_memory_requirements2") // 147
 cmd void vkGetImageMemoryRequirements2KHR(
         VkDevice                                    device,
@@ -8080,6 +9995,88 @@
         VkSparseImageMemoryRequirements2KHR*            pSparseMemoryRequirements) {
 }
 
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+cmd VkResult vkCreateSamplerYcbcrConversionKHR(
+        VkDevice                                        device,
+        const VkSamplerYcbcrConversionCreateInfoKHR*    pCreateInfo,
+        const VkAllocationCallbacks*                    pAllocator,
+        VkSamplerYcbcrConversionKHR*                    pYcbcrConversion) {
+    return ?
+}
+
+@extension("VK_KHR_sampler_ycbcr_conversion") // 157
+cmd void vkDestroySamplerYcbcrConversionKHR(
+        VkDevice                                        device,
+        VkSamplerYcbcrConversionKHR                     ycbcrConversion,
+        const VkAllocationCallbacks*                    pAllocator) {
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+cmd VkResult vkBindBufferMemory2KHR(
+        VkDevice                                        device,
+        u32                                             bindInfoCount,
+        const VkBindBufferMemoryInfoKHR*                pBindInfos) {
+    return ?
+}
+
+@extension("VK_KHR_bind_memory2") // 158
+cmd VkResult vkBindImageMemory2KHR(
+        VkDevice                                        device,
+        u32                                             bindInfoCount,
+        const VkBindImageMemoryInfoKHR*                 pBindInfos) {
+    return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkCreateValidationCacheEXT(
+        VkDevice                                    device,
+        const VkValidationCacheCreateInfoEXT*       pCreateInfo,
+        const VkAllocationCallbacks*                pAllocator,
+        VkValidationCacheEXT*                       pValidationCache) {
+    return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd void vkDestroyValidationCacheEXT(
+        VkDevice                                    device,
+        VkValidationCacheEXT                        validationCache,
+        const VkAllocationCallbacks*                pAllocator) {
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkMergeValidationCachesEXT(
+        VkDevice                                    device,
+        VkValidationCacheEXT                        dstCache,
+        u32                                         srcCacheCount,
+        const VkValidationCacheEXT*                 pSrcCaches) {
+    return ?
+}
+
+@extension("VK_EXT_validation_cache") // 161
+cmd VkResult vkGetValidationCacheDataEXT(
+        VkDevice                                    device,
+        VkValidationCacheEXT                        validationCache,
+        platform.size_t*                            pDataSize,
+        void*                                       pData) {
+    return ?
+}
+
+@extension("VK_KHR_maintenance3") // 169
+cmd void vkGetDescriptorSetLayoutSupportKHR(
+        VkDevice                                    device,
+        const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+        VkDescriptorSetLayoutSupportKHR*            pSupport) {
+}
+
+@extension("VK_EXT_external_memory_host") // 179
+cmd VkResult vkGetMemoryHostPointerPropertiesEXT(
+        VkDevice                                    device,
+        VkExternalMemoryHandleTypeFlagBits          handleType,
+        const void*                                 pHostPointer,
+        VkMemoryHostPointerPropertiesEXT*           pMemoryHostPointerProperties) {
+    return ?
+}
+
 ////////////////
 // Validation //
 ////////////////
diff --git a/vulkan/include/vulkan/vk_platform.h b/vulkan/include/vulkan/vk_platform.h
index 6dc5eb5..7289299 100644
--- a/vulkan/include/vulkan/vk_platform.h
+++ b/vulkan/include/vulkan/vk_platform.h
@@ -89,32 +89,4 @@
 } // extern "C"
 #endif // __cplusplus
 
-// Platform-specific headers required by platform window system extensions.
-// These are enabled prior to #including "vulkan.h". The same enable then
-// controls inclusion of the extension interfaces in vulkan.h.
-
-#ifdef VK_USE_PLATFORM_ANDROID_KHR
-struct ANativeWindow;
-#endif
-
-#ifdef VK_USE_PLATFORM_MIR_KHR
-#include <mir_toolkit/client_types.h>
-#endif
-
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
-#include <wayland-client.h>
-#endif
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#include <windows.h>
-#endif
-
-#ifdef VK_USE_PLATFORM_XLIB_KHR
-#include <X11/Xlib.h>
-#endif
-
-#ifdef VK_USE_PLATFORM_XCB_KHR
-#include <xcb/xcb.h>
-#endif
-
 #endif
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 0271d38..d05c849 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -1,12 +1,8 @@
 #ifndef VULKAN_H_
 #define VULKAN_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
-** Copyright (c) 2015-2017 The Khronos Group Inc.
+** Copyright (c) 2015-2018 The Khronos Group Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -21,6408 +17,63 @@
 ** limitations under the License.
 */
 
-/*
-** This header is generated from the Khronos Vulkan XML API Registry.
-**
-*/
-
-
-#define VK_VERSION_1_0 1
 #include "vk_platform.h"
-
-#define VK_MAKE_VERSION(major, minor, patch) \
-    (((major) << 22) | ((minor) << 12) | (patch))
-
-// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.
-//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0)
-
-// Vulkan 1.0 version number
-#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
-
-#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
-#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 54
-
-
-#define VK_NULL_HANDLE 0
-        
-
-
-#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
-
-
-#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)
-#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
-        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
-#else
-        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
-#endif
-#endif
-        
-
-
-typedef uint32_t VkFlags;
-typedef uint32_t VkBool32;
-typedef uint64_t VkDeviceSize;
-typedef uint32_t VkSampleMask;
-
-VK_DEFINE_HANDLE(VkInstance)
-VK_DEFINE_HANDLE(VkPhysicalDevice)
-VK_DEFINE_HANDLE(VkDevice)
-VK_DEFINE_HANDLE(VkQueue)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)
-VK_DEFINE_HANDLE(VkCommandBuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool)
-
-#define VK_LOD_CLAMP_NONE                 1000.0f
-#define VK_REMAINING_MIP_LEVELS           (~0U)
-#define VK_REMAINING_ARRAY_LAYERS         (~0U)
-#define VK_WHOLE_SIZE                     (~0ULL)
-#define VK_ATTACHMENT_UNUSED              (~0U)
-#define VK_TRUE                           1
-#define VK_FALSE                          0
-#define VK_QUEUE_FAMILY_IGNORED           (~0U)
-#define VK_SUBPASS_EXTERNAL               (~0U)
-#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE  256
-#define VK_UUID_SIZE                      16
-#define VK_MAX_MEMORY_TYPES               32
-#define VK_MAX_MEMORY_HEAPS               16
-#define VK_MAX_EXTENSION_NAME_SIZE        256
-#define VK_MAX_DESCRIPTION_SIZE           256
-
-
-typedef enum VkPipelineCacheHeaderVersion {
-    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
-    VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,
-    VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,
-    VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1),
-    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCacheHeaderVersion;
-
-typedef enum VkResult {
-    VK_SUCCESS = 0,
-    VK_NOT_READY = 1,
-    VK_TIMEOUT = 2,
-    VK_EVENT_SET = 3,
-    VK_EVENT_RESET = 4,
-    VK_INCOMPLETE = 5,
-    VK_ERROR_OUT_OF_HOST_MEMORY = -1,
-    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
-    VK_ERROR_INITIALIZATION_FAILED = -3,
-    VK_ERROR_DEVICE_LOST = -4,
-    VK_ERROR_MEMORY_MAP_FAILED = -5,
-    VK_ERROR_LAYER_NOT_PRESENT = -6,
-    VK_ERROR_EXTENSION_NOT_PRESENT = -7,
-    VK_ERROR_FEATURE_NOT_PRESENT = -8,
-    VK_ERROR_INCOMPATIBLE_DRIVER = -9,
-    VK_ERROR_TOO_MANY_OBJECTS = -10,
-    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
-    VK_ERROR_FRAGMENTED_POOL = -12,
-    VK_ERROR_SURFACE_LOST_KHR = -1000000000,
-    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
-    VK_SUBOPTIMAL_KHR = 1000001003,
-    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
-    VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
-    VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
-    VK_ERROR_INVALID_SHADER_NV = -1000012000,
-    VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000,
-    VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = -1000072003,
-    VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
-    VK_RESULT_END_RANGE = VK_INCOMPLETE,
-    VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
-    VK_RESULT_MAX_ENUM = 0x7FFFFFFF
-} VkResult;
-
-typedef enum VkStructureType {
-    VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
-    VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
-    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
-    VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
-    VK_STRUCTURE_TYPE_SUBMIT_INFO = 4,
-    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5,
-    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6,
-    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7,
-    VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8,
-    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9,
-    VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10,
-    VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11,
-    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12,
-    VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13,
-    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14,
-    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15,
-    VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16,
-    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17,
-    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18,
-    VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19,
-    VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,
-    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21,
-    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22,
-    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23,
-    VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24,
-    VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25,
-    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26,
-    VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27,
-    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28,
-    VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29,
-    VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30,
-    VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34,
-    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35,
-    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36,
-    VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37,
-    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38,
-    VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41,
-    VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42,
-    VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43,
-    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44,
-    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45,
-    VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,
-    VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
-    VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
-    VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
-    VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
-    VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
-    VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,
-    VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000,
-    VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
-    VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
-    VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
-    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
-    VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
-    VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
-    VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
-    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,
-    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
-    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
-    VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
-    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
-    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
-    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
-    VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
-    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,
-    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
-    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
-    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
-    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
-    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
-    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
-    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
-    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
-    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
-    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,
-    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,
-    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,
-    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,
-    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,
-    VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
-    VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,
-    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000,
-    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = 1000071001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = 1000071002,
-    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = 1000071003,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = 1000071004,
-    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = 1000072000,
-    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = 1000072001,
-    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = 1000072002,
-    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
-    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
-    VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
-    VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003,
-    VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000,
-    VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001,
-    VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002,
-    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = 1000076000,
-    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = 1000076001,
-    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = 1000077000,
-    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000,
-    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001,
-    VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002,
-    VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003,
-    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000,
-    VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000,
-    VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
-    VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
-    VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
-    VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
-    VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
-    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
-    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
-    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
-    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
-    VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
-    VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
-    VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
-    VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
-    VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,
-    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
-    VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
-    VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
-    VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = 1000112000,
-    VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = 1000112001,
-    VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = 1000113000,
-    VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000,
-    VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001,
-    VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002,
-    VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000,
-    VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
-    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
-    VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = 1000120000,
-    VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
-    VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
-    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = 1000127000,
-    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = 1000127001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
-    VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
-    VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146000,
-    VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146001,
-    VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146002,
-    VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = 1000146003,
-    VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = 1000146004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
-    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
-    VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
-    VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
-    VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
-    VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
-    VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
-    VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkStructureType;
-
-typedef enum VkSystemAllocationScope {
-    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0,
-    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1,
-    VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2,
-    VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3,
-    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4,
-    VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND,
-    VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE,
-    VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1),
-    VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF
-} VkSystemAllocationScope;
-
-typedef enum VkInternalAllocationType {
-    VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,
-    VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,
-    VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,
-    VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1),
-    VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkInternalAllocationType;
-
-typedef enum VkFormat {
-    VK_FORMAT_UNDEFINED = 0,
-    VK_FORMAT_R4G4_UNORM_PACK8 = 1,
-    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
-    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
-    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
-    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
-    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
-    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
-    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
-    VK_FORMAT_R8_UNORM = 9,
-    VK_FORMAT_R8_SNORM = 10,
-    VK_FORMAT_R8_USCALED = 11,
-    VK_FORMAT_R8_SSCALED = 12,
-    VK_FORMAT_R8_UINT = 13,
-    VK_FORMAT_R8_SINT = 14,
-    VK_FORMAT_R8_SRGB = 15,
-    VK_FORMAT_R8G8_UNORM = 16,
-    VK_FORMAT_R8G8_SNORM = 17,
-    VK_FORMAT_R8G8_USCALED = 18,
-    VK_FORMAT_R8G8_SSCALED = 19,
-    VK_FORMAT_R8G8_UINT = 20,
-    VK_FORMAT_R8G8_SINT = 21,
-    VK_FORMAT_R8G8_SRGB = 22,
-    VK_FORMAT_R8G8B8_UNORM = 23,
-    VK_FORMAT_R8G8B8_SNORM = 24,
-    VK_FORMAT_R8G8B8_USCALED = 25,
-    VK_FORMAT_R8G8B8_SSCALED = 26,
-    VK_FORMAT_R8G8B8_UINT = 27,
-    VK_FORMAT_R8G8B8_SINT = 28,
-    VK_FORMAT_R8G8B8_SRGB = 29,
-    VK_FORMAT_B8G8R8_UNORM = 30,
-    VK_FORMAT_B8G8R8_SNORM = 31,
-    VK_FORMAT_B8G8R8_USCALED = 32,
-    VK_FORMAT_B8G8R8_SSCALED = 33,
-    VK_FORMAT_B8G8R8_UINT = 34,
-    VK_FORMAT_B8G8R8_SINT = 35,
-    VK_FORMAT_B8G8R8_SRGB = 36,
-    VK_FORMAT_R8G8B8A8_UNORM = 37,
-    VK_FORMAT_R8G8B8A8_SNORM = 38,
-    VK_FORMAT_R8G8B8A8_USCALED = 39,
-    VK_FORMAT_R8G8B8A8_SSCALED = 40,
-    VK_FORMAT_R8G8B8A8_UINT = 41,
-    VK_FORMAT_R8G8B8A8_SINT = 42,
-    VK_FORMAT_R8G8B8A8_SRGB = 43,
-    VK_FORMAT_B8G8R8A8_UNORM = 44,
-    VK_FORMAT_B8G8R8A8_SNORM = 45,
-    VK_FORMAT_B8G8R8A8_USCALED = 46,
-    VK_FORMAT_B8G8R8A8_SSCALED = 47,
-    VK_FORMAT_B8G8R8A8_UINT = 48,
-    VK_FORMAT_B8G8R8A8_SINT = 49,
-    VK_FORMAT_B8G8R8A8_SRGB = 50,
-    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
-    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
-    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
-    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
-    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
-    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
-    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
-    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
-    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
-    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
-    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
-    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
-    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
-    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
-    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
-    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
-    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
-    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
-    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
-    VK_FORMAT_R16_UNORM = 70,
-    VK_FORMAT_R16_SNORM = 71,
-    VK_FORMAT_R16_USCALED = 72,
-    VK_FORMAT_R16_SSCALED = 73,
-    VK_FORMAT_R16_UINT = 74,
-    VK_FORMAT_R16_SINT = 75,
-    VK_FORMAT_R16_SFLOAT = 76,
-    VK_FORMAT_R16G16_UNORM = 77,
-    VK_FORMAT_R16G16_SNORM = 78,
-    VK_FORMAT_R16G16_USCALED = 79,
-    VK_FORMAT_R16G16_SSCALED = 80,
-    VK_FORMAT_R16G16_UINT = 81,
-    VK_FORMAT_R16G16_SINT = 82,
-    VK_FORMAT_R16G16_SFLOAT = 83,
-    VK_FORMAT_R16G16B16_UNORM = 84,
-    VK_FORMAT_R16G16B16_SNORM = 85,
-    VK_FORMAT_R16G16B16_USCALED = 86,
-    VK_FORMAT_R16G16B16_SSCALED = 87,
-    VK_FORMAT_R16G16B16_UINT = 88,
-    VK_FORMAT_R16G16B16_SINT = 89,
-    VK_FORMAT_R16G16B16_SFLOAT = 90,
-    VK_FORMAT_R16G16B16A16_UNORM = 91,
-    VK_FORMAT_R16G16B16A16_SNORM = 92,
-    VK_FORMAT_R16G16B16A16_USCALED = 93,
-    VK_FORMAT_R16G16B16A16_SSCALED = 94,
-    VK_FORMAT_R16G16B16A16_UINT = 95,
-    VK_FORMAT_R16G16B16A16_SINT = 96,
-    VK_FORMAT_R16G16B16A16_SFLOAT = 97,
-    VK_FORMAT_R32_UINT = 98,
-    VK_FORMAT_R32_SINT = 99,
-    VK_FORMAT_R32_SFLOAT = 100,
-    VK_FORMAT_R32G32_UINT = 101,
-    VK_FORMAT_R32G32_SINT = 102,
-    VK_FORMAT_R32G32_SFLOAT = 103,
-    VK_FORMAT_R32G32B32_UINT = 104,
-    VK_FORMAT_R32G32B32_SINT = 105,
-    VK_FORMAT_R32G32B32_SFLOAT = 106,
-    VK_FORMAT_R32G32B32A32_UINT = 107,
-    VK_FORMAT_R32G32B32A32_SINT = 108,
-    VK_FORMAT_R32G32B32A32_SFLOAT = 109,
-    VK_FORMAT_R64_UINT = 110,
-    VK_FORMAT_R64_SINT = 111,
-    VK_FORMAT_R64_SFLOAT = 112,
-    VK_FORMAT_R64G64_UINT = 113,
-    VK_FORMAT_R64G64_SINT = 114,
-    VK_FORMAT_R64G64_SFLOAT = 115,
-    VK_FORMAT_R64G64B64_UINT = 116,
-    VK_FORMAT_R64G64B64_SINT = 117,
-    VK_FORMAT_R64G64B64_SFLOAT = 118,
-    VK_FORMAT_R64G64B64A64_UINT = 119,
-    VK_FORMAT_R64G64B64A64_SINT = 120,
-    VK_FORMAT_R64G64B64A64_SFLOAT = 121,
-    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
-    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
-    VK_FORMAT_D16_UNORM = 124,
-    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
-    VK_FORMAT_D32_SFLOAT = 126,
-    VK_FORMAT_S8_UINT = 127,
-    VK_FORMAT_D16_UNORM_S8_UINT = 128,
-    VK_FORMAT_D24_UNORM_S8_UINT = 129,
-    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
-    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
-    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
-    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
-    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
-    VK_FORMAT_BC2_UNORM_BLOCK = 135,
-    VK_FORMAT_BC2_SRGB_BLOCK = 136,
-    VK_FORMAT_BC3_UNORM_BLOCK = 137,
-    VK_FORMAT_BC3_SRGB_BLOCK = 138,
-    VK_FORMAT_BC4_UNORM_BLOCK = 139,
-    VK_FORMAT_BC4_SNORM_BLOCK = 140,
-    VK_FORMAT_BC5_UNORM_BLOCK = 141,
-    VK_FORMAT_BC5_SNORM_BLOCK = 142,
-    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
-    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
-    VK_FORMAT_BC7_UNORM_BLOCK = 145,
-    VK_FORMAT_BC7_SRGB_BLOCK = 146,
-    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
-    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
-    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
-    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
-    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
-    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
-    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
-    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
-    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
-    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
-    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
-    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
-    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
-    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
-    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
-    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
-    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
-    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
-    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
-    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
-    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
-    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
-    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
-    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
-    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
-    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
-    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
-    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
-    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
-    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
-    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
-    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
-    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
-    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
-    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
-    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
-    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
-    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
-    VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
-    VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
-    VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
-    VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
-    VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
-    VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
-    VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
-    VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
-    VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED,
-    VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
-    VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1),
-    VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
-} VkFormat;
-
-typedef enum VkImageType {
-    VK_IMAGE_TYPE_1D = 0,
-    VK_IMAGE_TYPE_2D = 1,
-    VK_IMAGE_TYPE_3D = 2,
-    VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D,
-    VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D,
-    VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1),
-    VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkImageType;
-
-typedef enum VkImageTiling {
-    VK_IMAGE_TILING_OPTIMAL = 0,
-    VK_IMAGE_TILING_LINEAR = 1,
-    VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,
-    VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,
-    VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),
-    VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF
-} VkImageTiling;
-
-typedef enum VkPhysicalDeviceType {
-    VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
-    VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
-    VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
-    VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
-    VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
-    VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER,
-    VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU,
-    VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1),
-    VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkPhysicalDeviceType;
-
-typedef enum VkQueryType {
-    VK_QUERY_TYPE_OCCLUSION = 0,
-    VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
-    VK_QUERY_TYPE_TIMESTAMP = 2,
-    VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
-    VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,
-    VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),
-    VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkQueryType;
-
-typedef enum VkSharingMode {
-    VK_SHARING_MODE_EXCLUSIVE = 0,
-    VK_SHARING_MODE_CONCURRENT = 1,
-    VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE,
-    VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT,
-    VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1),
-    VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSharingMode;
-
-typedef enum VkImageLayout {
-    VK_IMAGE_LAYOUT_UNDEFINED = 0,
-    VK_IMAGE_LAYOUT_GENERAL = 1,
-    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2,
-    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3,
-    VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4,
-    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5,
-    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,
-    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,
-    VK_IMAGE_LAYOUT_PREINITIALIZED = 8,
-    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
-    VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
-    VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED,
-    VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED,
-    VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1),
-    VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF
-} VkImageLayout;
-
-typedef enum VkImageViewType {
-    VK_IMAGE_VIEW_TYPE_1D = 0,
-    VK_IMAGE_VIEW_TYPE_2D = 1,
-    VK_IMAGE_VIEW_TYPE_3D = 2,
-    VK_IMAGE_VIEW_TYPE_CUBE = 3,
-    VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4,
-    VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5,
-    VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6,
-    VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D,
-    VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
-    VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1),
-    VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkImageViewType;
-
-typedef enum VkComponentSwizzle {
-    VK_COMPONENT_SWIZZLE_IDENTITY = 0,
-    VK_COMPONENT_SWIZZLE_ZERO = 1,
-    VK_COMPONENT_SWIZZLE_ONE = 2,
-    VK_COMPONENT_SWIZZLE_R = 3,
-    VK_COMPONENT_SWIZZLE_G = 4,
-    VK_COMPONENT_SWIZZLE_B = 5,
-    VK_COMPONENT_SWIZZLE_A = 6,
-    VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY,
-    VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A,
-    VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1),
-    VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF
-} VkComponentSwizzle;
-
-typedef enum VkVertexInputRate {
-    VK_VERTEX_INPUT_RATE_VERTEX = 0,
-    VK_VERTEX_INPUT_RATE_INSTANCE = 1,
-    VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX,
-    VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE,
-    VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1),
-    VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF
-} VkVertexInputRate;
-
-typedef enum VkPrimitiveTopology {
-    VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,
-    VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,
-    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,
-    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,
-    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,
-    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,
-    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,
-    VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
-    VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
-    VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1),
-    VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF
-} VkPrimitiveTopology;
-
-typedef enum VkPolygonMode {
-    VK_POLYGON_MODE_FILL = 0,
-    VK_POLYGON_MODE_LINE = 1,
-    VK_POLYGON_MODE_POINT = 2,
-    VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
-    VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL,
-    VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT,
-    VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1),
-    VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkPolygonMode;
-
-typedef enum VkFrontFace {
-    VK_FRONT_FACE_COUNTER_CLOCKWISE = 0,
-    VK_FRONT_FACE_CLOCKWISE = 1,
-    VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE,
-    VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE,
-    VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1),
-    VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF
-} VkFrontFace;
-
-typedef enum VkCompareOp {
-    VK_COMPARE_OP_NEVER = 0,
-    VK_COMPARE_OP_LESS = 1,
-    VK_COMPARE_OP_EQUAL = 2,
-    VK_COMPARE_OP_LESS_OR_EQUAL = 3,
-    VK_COMPARE_OP_GREATER = 4,
-    VK_COMPARE_OP_NOT_EQUAL = 5,
-    VK_COMPARE_OP_GREATER_OR_EQUAL = 6,
-    VK_COMPARE_OP_ALWAYS = 7,
-    VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER,
-    VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS,
-    VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1),
-    VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF
-} VkCompareOp;
-
-typedef enum VkStencilOp {
-    VK_STENCIL_OP_KEEP = 0,
-    VK_STENCIL_OP_ZERO = 1,
-    VK_STENCIL_OP_REPLACE = 2,
-    VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3,
-    VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4,
-    VK_STENCIL_OP_INVERT = 5,
-    VK_STENCIL_OP_INCREMENT_AND_WRAP = 6,
-    VK_STENCIL_OP_DECREMENT_AND_WRAP = 7,
-    VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP,
-    VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP,
-    VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1),
-    VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF
-} VkStencilOp;
-
-typedef enum VkLogicOp {
-    VK_LOGIC_OP_CLEAR = 0,
-    VK_LOGIC_OP_AND = 1,
-    VK_LOGIC_OP_AND_REVERSE = 2,
-    VK_LOGIC_OP_COPY = 3,
-    VK_LOGIC_OP_AND_INVERTED = 4,
-    VK_LOGIC_OP_NO_OP = 5,
-    VK_LOGIC_OP_XOR = 6,
-    VK_LOGIC_OP_OR = 7,
-    VK_LOGIC_OP_NOR = 8,
-    VK_LOGIC_OP_EQUIVALENT = 9,
-    VK_LOGIC_OP_INVERT = 10,
-    VK_LOGIC_OP_OR_REVERSE = 11,
-    VK_LOGIC_OP_COPY_INVERTED = 12,
-    VK_LOGIC_OP_OR_INVERTED = 13,
-    VK_LOGIC_OP_NAND = 14,
-    VK_LOGIC_OP_SET = 15,
-    VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR,
-    VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET,
-    VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1),
-    VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF
-} VkLogicOp;
-
-typedef enum VkBlendFactor {
-    VK_BLEND_FACTOR_ZERO = 0,
-    VK_BLEND_FACTOR_ONE = 1,
-    VK_BLEND_FACTOR_SRC_COLOR = 2,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
-    VK_BLEND_FACTOR_DST_COLOR = 4,
-    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
-    VK_BLEND_FACTOR_SRC_ALPHA = 6,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
-    VK_BLEND_FACTOR_DST_ALPHA = 8,
-    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
-    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
-    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
-    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
-    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
-    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
-    VK_BLEND_FACTOR_SRC1_COLOR = 15,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
-    VK_BLEND_FACTOR_SRC1_ALPHA = 17,
-    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
-    VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO,
-    VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
-    VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1),
-    VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF
-} VkBlendFactor;
-
-typedef enum VkBlendOp {
-    VK_BLEND_OP_ADD = 0,
-    VK_BLEND_OP_SUBTRACT = 1,
-    VK_BLEND_OP_REVERSE_SUBTRACT = 2,
-    VK_BLEND_OP_MIN = 3,
-    VK_BLEND_OP_MAX = 4,
-    VK_BLEND_OP_ZERO_EXT = 1000148000,
-    VK_BLEND_OP_SRC_EXT = 1000148001,
-    VK_BLEND_OP_DST_EXT = 1000148002,
-    VK_BLEND_OP_SRC_OVER_EXT = 1000148003,
-    VK_BLEND_OP_DST_OVER_EXT = 1000148004,
-    VK_BLEND_OP_SRC_IN_EXT = 1000148005,
-    VK_BLEND_OP_DST_IN_EXT = 1000148006,
-    VK_BLEND_OP_SRC_OUT_EXT = 1000148007,
-    VK_BLEND_OP_DST_OUT_EXT = 1000148008,
-    VK_BLEND_OP_SRC_ATOP_EXT = 1000148009,
-    VK_BLEND_OP_DST_ATOP_EXT = 1000148010,
-    VK_BLEND_OP_XOR_EXT = 1000148011,
-    VK_BLEND_OP_MULTIPLY_EXT = 1000148012,
-    VK_BLEND_OP_SCREEN_EXT = 1000148013,
-    VK_BLEND_OP_OVERLAY_EXT = 1000148014,
-    VK_BLEND_OP_DARKEN_EXT = 1000148015,
-    VK_BLEND_OP_LIGHTEN_EXT = 1000148016,
-    VK_BLEND_OP_COLORDODGE_EXT = 1000148017,
-    VK_BLEND_OP_COLORBURN_EXT = 1000148018,
-    VK_BLEND_OP_HARDLIGHT_EXT = 1000148019,
-    VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020,
-    VK_BLEND_OP_DIFFERENCE_EXT = 1000148021,
-    VK_BLEND_OP_EXCLUSION_EXT = 1000148022,
-    VK_BLEND_OP_INVERT_EXT = 1000148023,
-    VK_BLEND_OP_INVERT_RGB_EXT = 1000148024,
-    VK_BLEND_OP_LINEARDODGE_EXT = 1000148025,
-    VK_BLEND_OP_LINEARBURN_EXT = 1000148026,
-    VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027,
-    VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028,
-    VK_BLEND_OP_PINLIGHT_EXT = 1000148029,
-    VK_BLEND_OP_HARDMIX_EXT = 1000148030,
-    VK_BLEND_OP_HSL_HUE_EXT = 1000148031,
-    VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032,
-    VK_BLEND_OP_HSL_COLOR_EXT = 1000148033,
-    VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034,
-    VK_BLEND_OP_PLUS_EXT = 1000148035,
-    VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036,
-    VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037,
-    VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038,
-    VK_BLEND_OP_MINUS_EXT = 1000148039,
-    VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040,
-    VK_BLEND_OP_CONTRAST_EXT = 1000148041,
-    VK_BLEND_OP_INVERT_OVG_EXT = 1000148042,
-    VK_BLEND_OP_RED_EXT = 1000148043,
-    VK_BLEND_OP_GREEN_EXT = 1000148044,
-    VK_BLEND_OP_BLUE_EXT = 1000148045,
-    VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD,
-    VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX,
-    VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1),
-    VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF
-} VkBlendOp;
-
-typedef enum VkDynamicState {
-    VK_DYNAMIC_STATE_VIEWPORT = 0,
-    VK_DYNAMIC_STATE_SCISSOR = 1,
-    VK_DYNAMIC_STATE_LINE_WIDTH = 2,
-    VK_DYNAMIC_STATE_DEPTH_BIAS = 3,
-    VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,
-    VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5,
-    VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,
-    VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,
-    VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
-    VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
-    VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
-    VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT,
-    VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE,
-    VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1),
-    VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF
-} VkDynamicState;
-
-typedef enum VkFilter {
-    VK_FILTER_NEAREST = 0,
-    VK_FILTER_LINEAR = 1,
-    VK_FILTER_CUBIC_IMG = 1000015000,
-    VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST,
-    VK_FILTER_END_RANGE = VK_FILTER_LINEAR,
-    VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1),
-    VK_FILTER_MAX_ENUM = 0x7FFFFFFF
-} VkFilter;
-
-typedef enum VkSamplerMipmapMode {
-    VK_SAMPLER_MIPMAP_MODE_NEAREST = 0,
-    VK_SAMPLER_MIPMAP_MODE_LINEAR = 1,
-    VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST,
-    VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR,
-    VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1),
-    VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerMipmapMode;
-
-typedef enum VkSamplerAddressMode {
-    VK_SAMPLER_ADDRESS_MODE_REPEAT = 0,
-    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1,
-    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2,
-    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3,
-    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4,
-    VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT,
-    VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
-    VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1),
-    VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF
-} VkSamplerAddressMode;
-
-typedef enum VkBorderColor {
-    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,
-    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,
-    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,
-    VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3,
-    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,
-    VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5,
-    VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
-    VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE,
-    VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1),
-    VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF
-} VkBorderColor;
-
-typedef enum VkDescriptorType {
-    VK_DESCRIPTOR_TYPE_SAMPLER = 0,
-    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1,
-    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2,
-    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3,
-    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4,
-    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5,
-    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6,
-    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7,
-    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
-    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
-    VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
-    VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
-    VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
-    VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
-    VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorType;
-
-typedef enum VkAttachmentLoadOp {
-    VK_ATTACHMENT_LOAD_OP_LOAD = 0,
-    VK_ATTACHMENT_LOAD_OP_CLEAR = 1,
-    VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2,
-    VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD,
-    VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
-    VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1),
-    VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentLoadOp;
-
-typedef enum VkAttachmentStoreOp {
-    VK_ATTACHMENT_STORE_OP_STORE = 0,
-    VK_ATTACHMENT_STORE_OP_DONT_CARE = 1,
-    VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE,
-    VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE,
-    VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1),
-    VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentStoreOp;
-
-typedef enum VkPipelineBindPoint {
-    VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
-    VK_PIPELINE_BIND_POINT_COMPUTE = 1,
-    VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,
-    VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,
-    VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),
-    VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineBindPoint;
-
-typedef enum VkCommandBufferLevel {
-    VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0,
-    VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1,
-    VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-    VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY,
-    VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1),
-    VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferLevel;
-
-typedef enum VkIndexType {
-    VK_INDEX_TYPE_UINT16 = 0,
-    VK_INDEX_TYPE_UINT32 = 1,
-    VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,
-    VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,
-    VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),
-    VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkIndexType;
-
-typedef enum VkSubpassContents {
-    VK_SUBPASS_CONTENTS_INLINE = 0,
-    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1,
-    VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE,
-    VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS,
-    VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1),
-    VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
-} VkSubpassContents;
-
-typedef enum VkObjectType {
-    VK_OBJECT_TYPE_UNKNOWN = 0,
-    VK_OBJECT_TYPE_INSTANCE = 1,
-    VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
-    VK_OBJECT_TYPE_DEVICE = 3,
-    VK_OBJECT_TYPE_QUEUE = 4,
-    VK_OBJECT_TYPE_SEMAPHORE = 5,
-    VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
-    VK_OBJECT_TYPE_FENCE = 7,
-    VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
-    VK_OBJECT_TYPE_BUFFER = 9,
-    VK_OBJECT_TYPE_IMAGE = 10,
-    VK_OBJECT_TYPE_EVENT = 11,
-    VK_OBJECT_TYPE_QUERY_POOL = 12,
-    VK_OBJECT_TYPE_BUFFER_VIEW = 13,
-    VK_OBJECT_TYPE_IMAGE_VIEW = 14,
-    VK_OBJECT_TYPE_SHADER_MODULE = 15,
-    VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
-    VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
-    VK_OBJECT_TYPE_RENDER_PASS = 18,
-    VK_OBJECT_TYPE_PIPELINE = 19,
-    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
-    VK_OBJECT_TYPE_SAMPLER = 21,
-    VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
-    VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
-    VK_OBJECT_TYPE_FRAMEBUFFER = 24,
-    VK_OBJECT_TYPE_COMMAND_POOL = 25,
-    VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
-    VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
-    VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
-    VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
-    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
-    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
-    VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
-    VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
-    VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
-    VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,
-    VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),
-    VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
-} VkObjectType;
-
-typedef VkFlags VkInstanceCreateFlags;
-
-typedef enum VkFormatFeatureFlagBits {
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001,
-    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002,
-    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004,
-    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008,
-    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010,
-    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020,
-    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040,
-    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080,
-    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100,
-    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200,
-    VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400,
-    VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
-    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
-    VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000,
-    VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFormatFeatureFlagBits;
-typedef VkFlags VkFormatFeatureFlags;
-
-typedef enum VkImageUsageFlagBits {
-    VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001,
-    VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002,
-    VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004,
-    VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008,
-    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010,
-    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020,
-    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040,
-    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080,
-    VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageUsageFlagBits;
-typedef VkFlags VkImageUsageFlags;
-
-typedef enum VkImageCreateFlagBits {
-    VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001,
-    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
-    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
-    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,
-    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,
-    VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,
-    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
-    VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageCreateFlagBits;
-typedef VkFlags VkImageCreateFlags;
-
-typedef enum VkSampleCountFlagBits {
-    VK_SAMPLE_COUNT_1_BIT = 0x00000001,
-    VK_SAMPLE_COUNT_2_BIT = 0x00000002,
-    VK_SAMPLE_COUNT_4_BIT = 0x00000004,
-    VK_SAMPLE_COUNT_8_BIT = 0x00000008,
-    VK_SAMPLE_COUNT_16_BIT = 0x00000010,
-    VK_SAMPLE_COUNT_32_BIT = 0x00000020,
-    VK_SAMPLE_COUNT_64_BIT = 0x00000040,
-    VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSampleCountFlagBits;
-typedef VkFlags VkSampleCountFlags;
-
-typedef enum VkQueueFlagBits {
-    VK_QUEUE_GRAPHICS_BIT = 0x00000001,
-    VK_QUEUE_COMPUTE_BIT = 0x00000002,
-    VK_QUEUE_TRANSFER_BIT = 0x00000004,
-    VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,
-    VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueueFlagBits;
-typedef VkFlags VkQueueFlags;
-
-typedef enum VkMemoryPropertyFlagBits {
-    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,
-    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,
-    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
-    VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
-    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
-    VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkMemoryPropertyFlagBits;
-typedef VkFlags VkMemoryPropertyFlags;
-
-typedef enum VkMemoryHeapFlagBits {
-    VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
-    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,
-    VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkMemoryHeapFlagBits;
-typedef VkFlags VkMemoryHeapFlags;
-typedef VkFlags VkDeviceCreateFlags;
-typedef VkFlags VkDeviceQueueCreateFlags;
-
-typedef enum VkPipelineStageFlagBits {
-    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001,
-    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002,
-    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004,
-    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008,
-    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010,
-    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020,
-    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040,
-    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080,
-    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100,
-    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200,
-    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400,
-    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800,
-    VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000,
-    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000,
-    VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
-    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
-    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
-    VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
-    VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineStageFlagBits;
-typedef VkFlags VkPipelineStageFlags;
-typedef VkFlags VkMemoryMapFlags;
-
-typedef enum VkImageAspectFlagBits {
-    VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001,
-    VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,
-    VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,
-    VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,
-    VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkImageAspectFlagBits;
-typedef VkFlags VkImageAspectFlags;
-
-typedef enum VkSparseImageFormatFlagBits {
-    VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001,
-    VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002,
-    VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004,
-    VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSparseImageFormatFlagBits;
-typedef VkFlags VkSparseImageFormatFlags;
-
-typedef enum VkSparseMemoryBindFlagBits {
-    VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001,
-    VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSparseMemoryBindFlagBits;
-typedef VkFlags VkSparseMemoryBindFlags;
-
-typedef enum VkFenceCreateFlagBits {
-    VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001,
-    VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkFenceCreateFlagBits;
-typedef VkFlags VkFenceCreateFlags;
-typedef VkFlags VkSemaphoreCreateFlags;
-typedef VkFlags VkEventCreateFlags;
-typedef VkFlags VkQueryPoolCreateFlags;
-
-typedef enum VkQueryPipelineStatisticFlagBits {
-    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001,
-    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002,
-    VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004,
-    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008,
-    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010,
-    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020,
-    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040,
-    VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080,
-    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100,
-    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200,
-    VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400,
-    VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryPipelineStatisticFlagBits;
-typedef VkFlags VkQueryPipelineStatisticFlags;
-
-typedef enum VkQueryResultFlagBits {
-    VK_QUERY_RESULT_64_BIT = 0x00000001,
-    VK_QUERY_RESULT_WAIT_BIT = 0x00000002,
-    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004,
-    VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008,
-    VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryResultFlagBits;
-typedef VkFlags VkQueryResultFlags;
-
-typedef enum VkBufferCreateFlagBits {
-    VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001,
-    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
-    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
-    VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkBufferCreateFlagBits;
-typedef VkFlags VkBufferCreateFlags;
-
-typedef enum VkBufferUsageFlagBits {
-    VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001,
-    VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002,
-    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004,
-    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008,
-    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010,
-    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020,
-    VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
-    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
-    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
-    VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkBufferUsageFlagBits;
-typedef VkFlags VkBufferUsageFlags;
-typedef VkFlags VkBufferViewCreateFlags;
-typedef VkFlags VkImageViewCreateFlags;
-typedef VkFlags VkShaderModuleCreateFlags;
-typedef VkFlags VkPipelineCacheCreateFlags;
-
-typedef enum VkPipelineCreateFlagBits {
-    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
-    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
-    VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
-    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
-    VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,
-    VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCreateFlagBits;
-typedef VkFlags VkPipelineCreateFlags;
-typedef VkFlags VkPipelineShaderStageCreateFlags;
-
-typedef enum VkShaderStageFlagBits {
-    VK_SHADER_STAGE_VERTEX_BIT = 0x00000001,
-    VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002,
-    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004,
-    VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008,
-    VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010,
-    VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
-    VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
-    VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
-    VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkShaderStageFlagBits;
-typedef VkFlags VkPipelineVertexInputStateCreateFlags;
-typedef VkFlags VkPipelineInputAssemblyStateCreateFlags;
-typedef VkFlags VkPipelineTessellationStateCreateFlags;
-typedef VkFlags VkPipelineViewportStateCreateFlags;
-typedef VkFlags VkPipelineRasterizationStateCreateFlags;
-
-typedef enum VkCullModeFlagBits {
-    VK_CULL_MODE_NONE = 0,
-    VK_CULL_MODE_FRONT_BIT = 0x00000001,
-    VK_CULL_MODE_BACK_BIT = 0x00000002,
-    VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
-    VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCullModeFlagBits;
-typedef VkFlags VkCullModeFlags;
-typedef VkFlags VkPipelineMultisampleStateCreateFlags;
-typedef VkFlags VkPipelineDepthStencilStateCreateFlags;
-typedef VkFlags VkPipelineColorBlendStateCreateFlags;
-
-typedef enum VkColorComponentFlagBits {
-    VK_COLOR_COMPONENT_R_BIT = 0x00000001,
-    VK_COLOR_COMPONENT_G_BIT = 0x00000002,
-    VK_COLOR_COMPONENT_B_BIT = 0x00000004,
-    VK_COLOR_COMPONENT_A_BIT = 0x00000008,
-    VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkColorComponentFlagBits;
-typedef VkFlags VkColorComponentFlags;
-typedef VkFlags VkPipelineDynamicStateCreateFlags;
-typedef VkFlags VkPipelineLayoutCreateFlags;
-typedef VkFlags VkShaderStageFlags;
-typedef VkFlags VkSamplerCreateFlags;
-
-typedef enum VkDescriptorSetLayoutCreateFlagBits {
-    VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
-    VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorSetLayoutCreateFlagBits;
-typedef VkFlags VkDescriptorSetLayoutCreateFlags;
-
-typedef enum VkDescriptorPoolCreateFlagBits {
-    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,
-    VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDescriptorPoolCreateFlagBits;
-typedef VkFlags VkDescriptorPoolCreateFlags;
-typedef VkFlags VkDescriptorPoolResetFlags;
-typedef VkFlags VkFramebufferCreateFlags;
-typedef VkFlags VkRenderPassCreateFlags;
-
-typedef enum VkAttachmentDescriptionFlagBits {
-    VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001,
-    VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkAttachmentDescriptionFlagBits;
-typedef VkFlags VkAttachmentDescriptionFlags;
-
-typedef enum VkSubpassDescriptionFlagBits {
-    VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,
-    VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
-    VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkSubpassDescriptionFlagBits;
-typedef VkFlags VkSubpassDescriptionFlags;
-
-typedef enum VkAccessFlagBits {
-    VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,
-    VK_ACCESS_INDEX_READ_BIT = 0x00000002,
-    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,
-    VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,
-    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,
-    VK_ACCESS_SHADER_READ_BIT = 0x00000020,
-    VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,
-    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,
-    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,
-    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,
-    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,
-    VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,
-    VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,
-    VK_ACCESS_HOST_READ_BIT = 0x00002000,
-    VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
-    VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
-    VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
-    VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
-    VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
-    VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
-    VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkAccessFlagBits;
-typedef VkFlags VkAccessFlags;
-
-typedef enum VkDependencyFlagBits {
-    VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
-    VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,
-    VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,
-    VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkDependencyFlagBits;
-typedef VkFlags VkDependencyFlags;
-
-typedef enum VkCommandPoolCreateFlagBits {
-    VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001,
-    VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,
-    VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandPoolCreateFlagBits;
-typedef VkFlags VkCommandPoolCreateFlags;
-
-typedef enum VkCommandPoolResetFlagBits {
-    VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
-    VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandPoolResetFlagBits;
-typedef VkFlags VkCommandPoolResetFlags;
-
-typedef enum VkCommandBufferUsageFlagBits {
-    VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001,
-    VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002,
-    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004,
-    VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferUsageFlagBits;
-typedef VkFlags VkCommandBufferUsageFlags;
-
-typedef enum VkQueryControlFlagBits {
-    VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001,
-    VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkQueryControlFlagBits;
-typedef VkFlags VkQueryControlFlags;
-
-typedef enum VkCommandBufferResetFlagBits {
-    VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
-    VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkCommandBufferResetFlagBits;
-typedef VkFlags VkCommandBufferResetFlags;
-
-typedef enum VkStencilFaceFlagBits {
-    VK_STENCIL_FACE_FRONT_BIT = 0x00000001,
-    VK_STENCIL_FACE_BACK_BIT = 0x00000002,
-    VK_STENCIL_FRONT_AND_BACK = 0x00000003,
-    VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkStencilFaceFlagBits;
-typedef VkFlags VkStencilFaceFlags;
-
-typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(
-    void*                                       pUserData,
-    size_t                                      size,
-    size_t                                      alignment,
-    VkSystemAllocationScope                     allocationScope);
-
-typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)(
-    void*                                       pUserData,
-    void*                                       pOriginal,
-    size_t                                      size,
-    size_t                                      alignment,
-    VkSystemAllocationScope                     allocationScope);
-
-typedef void (VKAPI_PTR *PFN_vkFreeFunction)(
-    void*                                       pUserData,
-    void*                                       pMemory);
-
-typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(
-    void*                                       pUserData,
-    size_t                                      size,
-    VkInternalAllocationType                    allocationType,
-    VkSystemAllocationScope                     allocationScope);
-
-typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(
-    void*                                       pUserData,
-    size_t                                      size,
-    VkInternalAllocationType                    allocationType,
-    VkSystemAllocationScope                     allocationScope);
-
-typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
-
-typedef struct VkApplicationInfo {
-    VkStructureType    sType;
-    const void*        pNext;
-    const char*        pApplicationName;
-    uint32_t           applicationVersion;
-    const char*        pEngineName;
-    uint32_t           engineVersion;
-    uint32_t           apiVersion;
-} VkApplicationInfo;
-
-typedef struct VkInstanceCreateInfo {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkInstanceCreateFlags       flags;
-    const VkApplicationInfo*    pApplicationInfo;
-    uint32_t                    enabledLayerCount;
-    const char* const*          ppEnabledLayerNames;
-    uint32_t                    enabledExtensionCount;
-    const char* const*          ppEnabledExtensionNames;
-} VkInstanceCreateInfo;
-
-typedef struct VkAllocationCallbacks {
-    void*                                   pUserData;
-    PFN_vkAllocationFunction                pfnAllocation;
-    PFN_vkReallocationFunction              pfnReallocation;
-    PFN_vkFreeFunction                      pfnFree;
-    PFN_vkInternalAllocationNotification    pfnInternalAllocation;
-    PFN_vkInternalFreeNotification          pfnInternalFree;
-} VkAllocationCallbacks;
-
-typedef struct VkPhysicalDeviceFeatures {
-    VkBool32    robustBufferAccess;
-    VkBool32    fullDrawIndexUint32;
-    VkBool32    imageCubeArray;
-    VkBool32    independentBlend;
-    VkBool32    geometryShader;
-    VkBool32    tessellationShader;
-    VkBool32    sampleRateShading;
-    VkBool32    dualSrcBlend;
-    VkBool32    logicOp;
-    VkBool32    multiDrawIndirect;
-    VkBool32    drawIndirectFirstInstance;
-    VkBool32    depthClamp;
-    VkBool32    depthBiasClamp;
-    VkBool32    fillModeNonSolid;
-    VkBool32    depthBounds;
-    VkBool32    wideLines;
-    VkBool32    largePoints;
-    VkBool32    alphaToOne;
-    VkBool32    multiViewport;
-    VkBool32    samplerAnisotropy;
-    VkBool32    textureCompressionETC2;
-    VkBool32    textureCompressionASTC_LDR;
-    VkBool32    textureCompressionBC;
-    VkBool32    occlusionQueryPrecise;
-    VkBool32    pipelineStatisticsQuery;
-    VkBool32    vertexPipelineStoresAndAtomics;
-    VkBool32    fragmentStoresAndAtomics;
-    VkBool32    shaderTessellationAndGeometryPointSize;
-    VkBool32    shaderImageGatherExtended;
-    VkBool32    shaderStorageImageExtendedFormats;
-    VkBool32    shaderStorageImageMultisample;
-    VkBool32    shaderStorageImageReadWithoutFormat;
-    VkBool32    shaderStorageImageWriteWithoutFormat;
-    VkBool32    shaderUniformBufferArrayDynamicIndexing;
-    VkBool32    shaderSampledImageArrayDynamicIndexing;
-    VkBool32    shaderStorageBufferArrayDynamicIndexing;
-    VkBool32    shaderStorageImageArrayDynamicIndexing;
-    VkBool32    shaderClipDistance;
-    VkBool32    shaderCullDistance;
-    VkBool32    shaderFloat64;
-    VkBool32    shaderInt64;
-    VkBool32    shaderInt16;
-    VkBool32    shaderResourceResidency;
-    VkBool32    shaderResourceMinLod;
-    VkBool32    sparseBinding;
-    VkBool32    sparseResidencyBuffer;
-    VkBool32    sparseResidencyImage2D;
-    VkBool32    sparseResidencyImage3D;
-    VkBool32    sparseResidency2Samples;
-    VkBool32    sparseResidency4Samples;
-    VkBool32    sparseResidency8Samples;
-    VkBool32    sparseResidency16Samples;
-    VkBool32    sparseResidencyAliased;
-    VkBool32    variableMultisampleRate;
-    VkBool32    inheritedQueries;
-} VkPhysicalDeviceFeatures;
-
-typedef struct VkFormatProperties {
-    VkFormatFeatureFlags    linearTilingFeatures;
-    VkFormatFeatureFlags    optimalTilingFeatures;
-    VkFormatFeatureFlags    bufferFeatures;
-} VkFormatProperties;
-
-typedef struct VkExtent3D {
-    uint32_t    width;
-    uint32_t    height;
-    uint32_t    depth;
-} VkExtent3D;
-
-typedef struct VkImageFormatProperties {
-    VkExtent3D            maxExtent;
-    uint32_t              maxMipLevels;
-    uint32_t              maxArrayLayers;
-    VkSampleCountFlags    sampleCounts;
-    VkDeviceSize          maxResourceSize;
-} VkImageFormatProperties;
-
-typedef struct VkPhysicalDeviceLimits {
-    uint32_t              maxImageDimension1D;
-    uint32_t              maxImageDimension2D;
-    uint32_t              maxImageDimension3D;
-    uint32_t              maxImageDimensionCube;
-    uint32_t              maxImageArrayLayers;
-    uint32_t              maxTexelBufferElements;
-    uint32_t              maxUniformBufferRange;
-    uint32_t              maxStorageBufferRange;
-    uint32_t              maxPushConstantsSize;
-    uint32_t              maxMemoryAllocationCount;
-    uint32_t              maxSamplerAllocationCount;
-    VkDeviceSize          bufferImageGranularity;
-    VkDeviceSize          sparseAddressSpaceSize;
-    uint32_t              maxBoundDescriptorSets;
-    uint32_t              maxPerStageDescriptorSamplers;
-    uint32_t              maxPerStageDescriptorUniformBuffers;
-    uint32_t              maxPerStageDescriptorStorageBuffers;
-    uint32_t              maxPerStageDescriptorSampledImages;
-    uint32_t              maxPerStageDescriptorStorageImages;
-    uint32_t              maxPerStageDescriptorInputAttachments;
-    uint32_t              maxPerStageResources;
-    uint32_t              maxDescriptorSetSamplers;
-    uint32_t              maxDescriptorSetUniformBuffers;
-    uint32_t              maxDescriptorSetUniformBuffersDynamic;
-    uint32_t              maxDescriptorSetStorageBuffers;
-    uint32_t              maxDescriptorSetStorageBuffersDynamic;
-    uint32_t              maxDescriptorSetSampledImages;
-    uint32_t              maxDescriptorSetStorageImages;
-    uint32_t              maxDescriptorSetInputAttachments;
-    uint32_t              maxVertexInputAttributes;
-    uint32_t              maxVertexInputBindings;
-    uint32_t              maxVertexInputAttributeOffset;
-    uint32_t              maxVertexInputBindingStride;
-    uint32_t              maxVertexOutputComponents;
-    uint32_t              maxTessellationGenerationLevel;
-    uint32_t              maxTessellationPatchSize;
-    uint32_t              maxTessellationControlPerVertexInputComponents;
-    uint32_t              maxTessellationControlPerVertexOutputComponents;
-    uint32_t              maxTessellationControlPerPatchOutputComponents;
-    uint32_t              maxTessellationControlTotalOutputComponents;
-    uint32_t              maxTessellationEvaluationInputComponents;
-    uint32_t              maxTessellationEvaluationOutputComponents;
-    uint32_t              maxGeometryShaderInvocations;
-    uint32_t              maxGeometryInputComponents;
-    uint32_t              maxGeometryOutputComponents;
-    uint32_t              maxGeometryOutputVertices;
-    uint32_t              maxGeometryTotalOutputComponents;
-    uint32_t              maxFragmentInputComponents;
-    uint32_t              maxFragmentOutputAttachments;
-    uint32_t              maxFragmentDualSrcAttachments;
-    uint32_t              maxFragmentCombinedOutputResources;
-    uint32_t              maxComputeSharedMemorySize;
-    uint32_t              maxComputeWorkGroupCount[3];
-    uint32_t              maxComputeWorkGroupInvocations;
-    uint32_t              maxComputeWorkGroupSize[3];
-    uint32_t              subPixelPrecisionBits;
-    uint32_t              subTexelPrecisionBits;
-    uint32_t              mipmapPrecisionBits;
-    uint32_t              maxDrawIndexedIndexValue;
-    uint32_t              maxDrawIndirectCount;
-    float                 maxSamplerLodBias;
-    float                 maxSamplerAnisotropy;
-    uint32_t              maxViewports;
-    uint32_t              maxViewportDimensions[2];
-    float                 viewportBoundsRange[2];
-    uint32_t              viewportSubPixelBits;
-    size_t                minMemoryMapAlignment;
-    VkDeviceSize          minTexelBufferOffsetAlignment;
-    VkDeviceSize          minUniformBufferOffsetAlignment;
-    VkDeviceSize          minStorageBufferOffsetAlignment;
-    int32_t               minTexelOffset;
-    uint32_t              maxTexelOffset;
-    int32_t               minTexelGatherOffset;
-    uint32_t              maxTexelGatherOffset;
-    float                 minInterpolationOffset;
-    float                 maxInterpolationOffset;
-    uint32_t              subPixelInterpolationOffsetBits;
-    uint32_t              maxFramebufferWidth;
-    uint32_t              maxFramebufferHeight;
-    uint32_t              maxFramebufferLayers;
-    VkSampleCountFlags    framebufferColorSampleCounts;
-    VkSampleCountFlags    framebufferDepthSampleCounts;
-    VkSampleCountFlags    framebufferStencilSampleCounts;
-    VkSampleCountFlags    framebufferNoAttachmentsSampleCounts;
-    uint32_t              maxColorAttachments;
-    VkSampleCountFlags    sampledImageColorSampleCounts;
-    VkSampleCountFlags    sampledImageIntegerSampleCounts;
-    VkSampleCountFlags    sampledImageDepthSampleCounts;
-    VkSampleCountFlags    sampledImageStencilSampleCounts;
-    VkSampleCountFlags    storageImageSampleCounts;
-    uint32_t              maxSampleMaskWords;
-    VkBool32              timestampComputeAndGraphics;
-    float                 timestampPeriod;
-    uint32_t              maxClipDistances;
-    uint32_t              maxCullDistances;
-    uint32_t              maxCombinedClipAndCullDistances;
-    uint32_t              discreteQueuePriorities;
-    float                 pointSizeRange[2];
-    float                 lineWidthRange[2];
-    float                 pointSizeGranularity;
-    float                 lineWidthGranularity;
-    VkBool32              strictLines;
-    VkBool32              standardSampleLocations;
-    VkDeviceSize          optimalBufferCopyOffsetAlignment;
-    VkDeviceSize          optimalBufferCopyRowPitchAlignment;
-    VkDeviceSize          nonCoherentAtomSize;
-} VkPhysicalDeviceLimits;
-
-typedef struct VkPhysicalDeviceSparseProperties {
-    VkBool32    residencyStandard2DBlockShape;
-    VkBool32    residencyStandard2DMultisampleBlockShape;
-    VkBool32    residencyStandard3DBlockShape;
-    VkBool32    residencyAlignedMipSize;
-    VkBool32    residencyNonResidentStrict;
-} VkPhysicalDeviceSparseProperties;
-
-typedef struct VkPhysicalDeviceProperties {
-    uint32_t                            apiVersion;
-    uint32_t                            driverVersion;
-    uint32_t                            vendorID;
-    uint32_t                            deviceID;
-    VkPhysicalDeviceType                deviceType;
-    char                                deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
-    uint8_t                             pipelineCacheUUID[VK_UUID_SIZE];
-    VkPhysicalDeviceLimits              limits;
-    VkPhysicalDeviceSparseProperties    sparseProperties;
-} VkPhysicalDeviceProperties;
-
-typedef struct VkQueueFamilyProperties {
-    VkQueueFlags    queueFlags;
-    uint32_t        queueCount;
-    uint32_t        timestampValidBits;
-    VkExtent3D      minImageTransferGranularity;
-} VkQueueFamilyProperties;
-
-typedef struct VkMemoryType {
-    VkMemoryPropertyFlags    propertyFlags;
-    uint32_t                 heapIndex;
-} VkMemoryType;
-
-typedef struct VkMemoryHeap {
-    VkDeviceSize         size;
-    VkMemoryHeapFlags    flags;
-} VkMemoryHeap;
-
-typedef struct VkPhysicalDeviceMemoryProperties {
-    uint32_t        memoryTypeCount;
-    VkMemoryType    memoryTypes[VK_MAX_MEMORY_TYPES];
-    uint32_t        memoryHeapCount;
-    VkMemoryHeap    memoryHeaps[VK_MAX_MEMORY_HEAPS];
-} VkPhysicalDeviceMemoryProperties;
-
-typedef struct VkDeviceQueueCreateInfo {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkDeviceQueueCreateFlags    flags;
-    uint32_t                    queueFamilyIndex;
-    uint32_t                    queueCount;
-    const float*                pQueuePriorities;
-} VkDeviceQueueCreateInfo;
-
-typedef struct VkDeviceCreateInfo {
-    VkStructureType                    sType;
-    const void*                        pNext;
-    VkDeviceCreateFlags                flags;
-    uint32_t                           queueCreateInfoCount;
-    const VkDeviceQueueCreateInfo*     pQueueCreateInfos;
-    uint32_t                           enabledLayerCount;
-    const char* const*                 ppEnabledLayerNames;
-    uint32_t                           enabledExtensionCount;
-    const char* const*                 ppEnabledExtensionNames;
-    const VkPhysicalDeviceFeatures*    pEnabledFeatures;
-} VkDeviceCreateInfo;
-
-typedef struct VkExtensionProperties {
-    char        extensionName[VK_MAX_EXTENSION_NAME_SIZE];
-    uint32_t    specVersion;
-} VkExtensionProperties;
-
-typedef struct VkLayerProperties {
-    char        layerName[VK_MAX_EXTENSION_NAME_SIZE];
-    uint32_t    specVersion;
-    uint32_t    implementationVersion;
-    char        description[VK_MAX_DESCRIPTION_SIZE];
-} VkLayerProperties;
-
-typedef struct VkSubmitInfo {
-    VkStructureType                sType;
-    const void*                    pNext;
-    uint32_t                       waitSemaphoreCount;
-    const VkSemaphore*             pWaitSemaphores;
-    const VkPipelineStageFlags*    pWaitDstStageMask;
-    uint32_t                       commandBufferCount;
-    const VkCommandBuffer*         pCommandBuffers;
-    uint32_t                       signalSemaphoreCount;
-    const VkSemaphore*             pSignalSemaphores;
-} VkSubmitInfo;
-
-typedef struct VkMemoryAllocateInfo {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkDeviceSize       allocationSize;
-    uint32_t           memoryTypeIndex;
-} VkMemoryAllocateInfo;
-
-typedef struct VkMappedMemoryRange {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkDeviceMemory     memory;
-    VkDeviceSize       offset;
-    VkDeviceSize       size;
-} VkMappedMemoryRange;
-
-typedef struct VkMemoryRequirements {
-    VkDeviceSize    size;
-    VkDeviceSize    alignment;
-    uint32_t        memoryTypeBits;
-} VkMemoryRequirements;
-
-typedef struct VkSparseImageFormatProperties {
-    VkImageAspectFlags          aspectMask;
-    VkExtent3D                  imageGranularity;
-    VkSparseImageFormatFlags    flags;
-} VkSparseImageFormatProperties;
-
-typedef struct VkSparseImageMemoryRequirements {
-    VkSparseImageFormatProperties    formatProperties;
-    uint32_t                         imageMipTailFirstLod;
-    VkDeviceSize                     imageMipTailSize;
-    VkDeviceSize                     imageMipTailOffset;
-    VkDeviceSize                     imageMipTailStride;
-} VkSparseImageMemoryRequirements;
-
-typedef struct VkSparseMemoryBind {
-    VkDeviceSize               resourceOffset;
-    VkDeviceSize               size;
-    VkDeviceMemory             memory;
-    VkDeviceSize               memoryOffset;
-    VkSparseMemoryBindFlags    flags;
-} VkSparseMemoryBind;
-
-typedef struct VkSparseBufferMemoryBindInfo {
-    VkBuffer                     buffer;
-    uint32_t                     bindCount;
-    const VkSparseMemoryBind*    pBinds;
-} VkSparseBufferMemoryBindInfo;
-
-typedef struct VkSparseImageOpaqueMemoryBindInfo {
-    VkImage                      image;
-    uint32_t                     bindCount;
-    const VkSparseMemoryBind*    pBinds;
-} VkSparseImageOpaqueMemoryBindInfo;
-
-typedef struct VkImageSubresource {
-    VkImageAspectFlags    aspectMask;
-    uint32_t              mipLevel;
-    uint32_t              arrayLayer;
-} VkImageSubresource;
-
-typedef struct VkOffset3D {
-    int32_t    x;
-    int32_t    y;
-    int32_t    z;
-} VkOffset3D;
-
-typedef struct VkSparseImageMemoryBind {
-    VkImageSubresource         subresource;
-    VkOffset3D                 offset;
-    VkExtent3D                 extent;
-    VkDeviceMemory             memory;
-    VkDeviceSize               memoryOffset;
-    VkSparseMemoryBindFlags    flags;
-} VkSparseImageMemoryBind;
-
-typedef struct VkSparseImageMemoryBindInfo {
-    VkImage                           image;
-    uint32_t                          bindCount;
-    const VkSparseImageMemoryBind*    pBinds;
-} VkSparseImageMemoryBindInfo;
-
-typedef struct VkBindSparseInfo {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    uint32_t                                    waitSemaphoreCount;
-    const VkSemaphore*                          pWaitSemaphores;
-    uint32_t                                    bufferBindCount;
-    const VkSparseBufferMemoryBindInfo*         pBufferBinds;
-    uint32_t                                    imageOpaqueBindCount;
-    const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds;
-    uint32_t                                    imageBindCount;
-    const VkSparseImageMemoryBindInfo*          pImageBinds;
-    uint32_t                                    signalSemaphoreCount;
-    const VkSemaphore*                          pSignalSemaphores;
-} VkBindSparseInfo;
-
-typedef struct VkFenceCreateInfo {
-    VkStructureType       sType;
-    const void*           pNext;
-    VkFenceCreateFlags    flags;
-} VkFenceCreateInfo;
-
-typedef struct VkSemaphoreCreateInfo {
-    VkStructureType           sType;
-    const void*               pNext;
-    VkSemaphoreCreateFlags    flags;
-} VkSemaphoreCreateInfo;
-
-typedef struct VkEventCreateInfo {
-    VkStructureType       sType;
-    const void*           pNext;
-    VkEventCreateFlags    flags;
-} VkEventCreateInfo;
-
-typedef struct VkQueryPoolCreateInfo {
-    VkStructureType                  sType;
-    const void*                      pNext;
-    VkQueryPoolCreateFlags           flags;
-    VkQueryType                      queryType;
-    uint32_t                         queryCount;
-    VkQueryPipelineStatisticFlags    pipelineStatistics;
-} VkQueryPoolCreateInfo;
-
-typedef struct VkBufferCreateInfo {
-    VkStructureType        sType;
-    const void*            pNext;
-    VkBufferCreateFlags    flags;
-    VkDeviceSize           size;
-    VkBufferUsageFlags     usage;
-    VkSharingMode          sharingMode;
-    uint32_t               queueFamilyIndexCount;
-    const uint32_t*        pQueueFamilyIndices;
-} VkBufferCreateInfo;
-
-typedef struct VkBufferViewCreateInfo {
-    VkStructureType            sType;
-    const void*                pNext;
-    VkBufferViewCreateFlags    flags;
-    VkBuffer                   buffer;
-    VkFormat                   format;
-    VkDeviceSize               offset;
-    VkDeviceSize               range;
-} VkBufferViewCreateInfo;
-
-typedef struct VkImageCreateInfo {
-    VkStructureType          sType;
-    const void*              pNext;
-    VkImageCreateFlags       flags;
-    VkImageType              imageType;
-    VkFormat                 format;
-    VkExtent3D               extent;
-    uint32_t                 mipLevels;
-    uint32_t                 arrayLayers;
-    VkSampleCountFlagBits    samples;
-    VkImageTiling            tiling;
-    VkImageUsageFlags        usage;
-    VkSharingMode            sharingMode;
-    uint32_t                 queueFamilyIndexCount;
-    const uint32_t*          pQueueFamilyIndices;
-    VkImageLayout            initialLayout;
-} VkImageCreateInfo;
-
-typedef struct VkSubresourceLayout {
-    VkDeviceSize    offset;
-    VkDeviceSize    size;
-    VkDeviceSize    rowPitch;
-    VkDeviceSize    arrayPitch;
-    VkDeviceSize    depthPitch;
-} VkSubresourceLayout;
-
-typedef struct VkComponentMapping {
-    VkComponentSwizzle    r;
-    VkComponentSwizzle    g;
-    VkComponentSwizzle    b;
-    VkComponentSwizzle    a;
-} VkComponentMapping;
-
-typedef struct VkImageSubresourceRange {
-    VkImageAspectFlags    aspectMask;
-    uint32_t              baseMipLevel;
-    uint32_t              levelCount;
-    uint32_t              baseArrayLayer;
-    uint32_t              layerCount;
-} VkImageSubresourceRange;
-
-typedef struct VkImageViewCreateInfo {
-    VkStructureType            sType;
-    const void*                pNext;
-    VkImageViewCreateFlags     flags;
-    VkImage                    image;
-    VkImageViewType            viewType;
-    VkFormat                   format;
-    VkComponentMapping         components;
-    VkImageSubresourceRange    subresourceRange;
-} VkImageViewCreateInfo;
-
-typedef struct VkShaderModuleCreateInfo {
-    VkStructureType              sType;
-    const void*                  pNext;
-    VkShaderModuleCreateFlags    flags;
-    size_t                       codeSize;
-    const uint32_t*              pCode;
-} VkShaderModuleCreateInfo;
-
-typedef struct VkPipelineCacheCreateInfo {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkPipelineCacheCreateFlags    flags;
-    size_t                        initialDataSize;
-    const void*                   pInitialData;
-} VkPipelineCacheCreateInfo;
-
-typedef struct VkSpecializationMapEntry {
-    uint32_t    constantID;
-    uint32_t    offset;
-    size_t      size;
-} VkSpecializationMapEntry;
-
-typedef struct VkSpecializationInfo {
-    uint32_t                           mapEntryCount;
-    const VkSpecializationMapEntry*    pMapEntries;
-    size_t                             dataSize;
-    const void*                        pData;
-} VkSpecializationInfo;
-
-typedef struct VkPipelineShaderStageCreateInfo {
-    VkStructureType                     sType;
-    const void*                         pNext;
-    VkPipelineShaderStageCreateFlags    flags;
-    VkShaderStageFlagBits               stage;
-    VkShaderModule                      module;
-    const char*                         pName;
-    const VkSpecializationInfo*         pSpecializationInfo;
-} VkPipelineShaderStageCreateInfo;
-
-typedef struct VkVertexInputBindingDescription {
-    uint32_t             binding;
-    uint32_t             stride;
-    VkVertexInputRate    inputRate;
-} VkVertexInputBindingDescription;
-
-typedef struct VkVertexInputAttributeDescription {
-    uint32_t    location;
-    uint32_t    binding;
-    VkFormat    format;
-    uint32_t    offset;
-} VkVertexInputAttributeDescription;
-
-typedef struct VkPipelineVertexInputStateCreateInfo {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkPipelineVertexInputStateCreateFlags       flags;
-    uint32_t                                    vertexBindingDescriptionCount;
-    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
-    uint32_t                                    vertexAttributeDescriptionCount;
-    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
-} VkPipelineVertexInputStateCreateInfo;
-
-typedef struct VkPipelineInputAssemblyStateCreateInfo {
-    VkStructureType                            sType;
-    const void*                                pNext;
-    VkPipelineInputAssemblyStateCreateFlags    flags;
-    VkPrimitiveTopology                        topology;
-    VkBool32                                   primitiveRestartEnable;
-} VkPipelineInputAssemblyStateCreateInfo;
-
-typedef struct VkPipelineTessellationStateCreateInfo {
-    VkStructureType                           sType;
-    const void*                               pNext;
-    VkPipelineTessellationStateCreateFlags    flags;
-    uint32_t                                  patchControlPoints;
-} VkPipelineTessellationStateCreateInfo;
-
-typedef struct VkViewport {
-    float    x;
-    float    y;
-    float    width;
-    float    height;
-    float    minDepth;
-    float    maxDepth;
-} VkViewport;
-
-typedef struct VkOffset2D {
-    int32_t    x;
-    int32_t    y;
-} VkOffset2D;
-
-typedef struct VkExtent2D {
-    uint32_t    width;
-    uint32_t    height;
-} VkExtent2D;
-
-typedef struct VkRect2D {
-    VkOffset2D    offset;
-    VkExtent2D    extent;
-} VkRect2D;
-
-typedef struct VkPipelineViewportStateCreateInfo {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkPipelineViewportStateCreateFlags    flags;
-    uint32_t                              viewportCount;
-    const VkViewport*                     pViewports;
-    uint32_t                              scissorCount;
-    const VkRect2D*                       pScissors;
-} VkPipelineViewportStateCreateInfo;
-
-typedef struct VkPipelineRasterizationStateCreateInfo {
-    VkStructureType                            sType;
-    const void*                                pNext;
-    VkPipelineRasterizationStateCreateFlags    flags;
-    VkBool32                                   depthClampEnable;
-    VkBool32                                   rasterizerDiscardEnable;
-    VkPolygonMode                              polygonMode;
-    VkCullModeFlags                            cullMode;
-    VkFrontFace                                frontFace;
-    VkBool32                                   depthBiasEnable;
-    float                                      depthBiasConstantFactor;
-    float                                      depthBiasClamp;
-    float                                      depthBiasSlopeFactor;
-    float                                      lineWidth;
-} VkPipelineRasterizationStateCreateInfo;
-
-typedef struct VkPipelineMultisampleStateCreateInfo {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkPipelineMultisampleStateCreateFlags    flags;
-    VkSampleCountFlagBits                    rasterizationSamples;
-    VkBool32                                 sampleShadingEnable;
-    float                                    minSampleShading;
-    const VkSampleMask*                      pSampleMask;
-    VkBool32                                 alphaToCoverageEnable;
-    VkBool32                                 alphaToOneEnable;
-} VkPipelineMultisampleStateCreateInfo;
-
-typedef struct VkStencilOpState {
-    VkStencilOp    failOp;
-    VkStencilOp    passOp;
-    VkStencilOp    depthFailOp;
-    VkCompareOp    compareOp;
-    uint32_t       compareMask;
-    uint32_t       writeMask;
-    uint32_t       reference;
-} VkStencilOpState;
-
-typedef struct VkPipelineDepthStencilStateCreateInfo {
-    VkStructureType                           sType;
-    const void*                               pNext;
-    VkPipelineDepthStencilStateCreateFlags    flags;
-    VkBool32                                  depthTestEnable;
-    VkBool32                                  depthWriteEnable;
-    VkCompareOp                               depthCompareOp;
-    VkBool32                                  depthBoundsTestEnable;
-    VkBool32                                  stencilTestEnable;
-    VkStencilOpState                          front;
-    VkStencilOpState                          back;
-    float                                     minDepthBounds;
-    float                                     maxDepthBounds;
-} VkPipelineDepthStencilStateCreateInfo;
-
-typedef struct VkPipelineColorBlendAttachmentState {
-    VkBool32                 blendEnable;
-    VkBlendFactor            srcColorBlendFactor;
-    VkBlendFactor            dstColorBlendFactor;
-    VkBlendOp                colorBlendOp;
-    VkBlendFactor            srcAlphaBlendFactor;
-    VkBlendFactor            dstAlphaBlendFactor;
-    VkBlendOp                alphaBlendOp;
-    VkColorComponentFlags    colorWriteMask;
-} VkPipelineColorBlendAttachmentState;
-
-typedef struct VkPipelineColorBlendStateCreateInfo {
-    VkStructureType                               sType;
-    const void*                                   pNext;
-    VkPipelineColorBlendStateCreateFlags          flags;
-    VkBool32                                      logicOpEnable;
-    VkLogicOp                                     logicOp;
-    uint32_t                                      attachmentCount;
-    const VkPipelineColorBlendAttachmentState*    pAttachments;
-    float                                         blendConstants[4];
-} VkPipelineColorBlendStateCreateInfo;
-
-typedef struct VkPipelineDynamicStateCreateInfo {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkPipelineDynamicStateCreateFlags    flags;
-    uint32_t                             dynamicStateCount;
-    const VkDynamicState*                pDynamicStates;
-} VkPipelineDynamicStateCreateInfo;
-
-typedef struct VkGraphicsPipelineCreateInfo {
-    VkStructureType                                  sType;
-    const void*                                      pNext;
-    VkPipelineCreateFlags                            flags;
-    uint32_t                                         stageCount;
-    const VkPipelineShaderStageCreateInfo*           pStages;
-    const VkPipelineVertexInputStateCreateInfo*      pVertexInputState;
-    const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState;
-    const VkPipelineTessellationStateCreateInfo*     pTessellationState;
-    const VkPipelineViewportStateCreateInfo*         pViewportState;
-    const VkPipelineRasterizationStateCreateInfo*    pRasterizationState;
-    const VkPipelineMultisampleStateCreateInfo*      pMultisampleState;
-    const VkPipelineDepthStencilStateCreateInfo*     pDepthStencilState;
-    const VkPipelineColorBlendStateCreateInfo*       pColorBlendState;
-    const VkPipelineDynamicStateCreateInfo*          pDynamicState;
-    VkPipelineLayout                                 layout;
-    VkRenderPass                                     renderPass;
-    uint32_t                                         subpass;
-    VkPipeline                                       basePipelineHandle;
-    int32_t                                          basePipelineIndex;
-} VkGraphicsPipelineCreateInfo;
-
-typedef struct VkComputePipelineCreateInfo {
-    VkStructureType                    sType;
-    const void*                        pNext;
-    VkPipelineCreateFlags              flags;
-    VkPipelineShaderStageCreateInfo    stage;
-    VkPipelineLayout                   layout;
-    VkPipeline                         basePipelineHandle;
-    int32_t                            basePipelineIndex;
-} VkComputePipelineCreateInfo;
-
-typedef struct VkPushConstantRange {
-    VkShaderStageFlags    stageFlags;
-    uint32_t              offset;
-    uint32_t              size;
-} VkPushConstantRange;
-
-typedef struct VkPipelineLayoutCreateInfo {
-    VkStructureType                 sType;
-    const void*                     pNext;
-    VkPipelineLayoutCreateFlags     flags;
-    uint32_t                        setLayoutCount;
-    const VkDescriptorSetLayout*    pSetLayouts;
-    uint32_t                        pushConstantRangeCount;
-    const VkPushConstantRange*      pPushConstantRanges;
-} VkPipelineLayoutCreateInfo;
-
-typedef struct VkSamplerCreateInfo {
-    VkStructureType         sType;
-    const void*             pNext;
-    VkSamplerCreateFlags    flags;
-    VkFilter                magFilter;
-    VkFilter                minFilter;
-    VkSamplerMipmapMode     mipmapMode;
-    VkSamplerAddressMode    addressModeU;
-    VkSamplerAddressMode    addressModeV;
-    VkSamplerAddressMode    addressModeW;
-    float                   mipLodBias;
-    VkBool32                anisotropyEnable;
-    float                   maxAnisotropy;
-    VkBool32                compareEnable;
-    VkCompareOp             compareOp;
-    float                   minLod;
-    float                   maxLod;
-    VkBorderColor           borderColor;
-    VkBool32                unnormalizedCoordinates;
-} VkSamplerCreateInfo;
-
-typedef struct VkDescriptorSetLayoutBinding {
-    uint32_t              binding;
-    VkDescriptorType      descriptorType;
-    uint32_t              descriptorCount;
-    VkShaderStageFlags    stageFlags;
-    const VkSampler*      pImmutableSamplers;
-} VkDescriptorSetLayoutBinding;
-
-typedef struct VkDescriptorSetLayoutCreateInfo {
-    VkStructureType                        sType;
-    const void*                            pNext;
-    VkDescriptorSetLayoutCreateFlags       flags;
-    uint32_t                               bindingCount;
-    const VkDescriptorSetLayoutBinding*    pBindings;
-} VkDescriptorSetLayoutCreateInfo;
-
-typedef struct VkDescriptorPoolSize {
-    VkDescriptorType    type;
-    uint32_t            descriptorCount;
-} VkDescriptorPoolSize;
-
-typedef struct VkDescriptorPoolCreateInfo {
-    VkStructureType                sType;
-    const void*                    pNext;
-    VkDescriptorPoolCreateFlags    flags;
-    uint32_t                       maxSets;
-    uint32_t                       poolSizeCount;
-    const VkDescriptorPoolSize*    pPoolSizes;
-} VkDescriptorPoolCreateInfo;
-
-typedef struct VkDescriptorSetAllocateInfo {
-    VkStructureType                 sType;
-    const void*                     pNext;
-    VkDescriptorPool                descriptorPool;
-    uint32_t                        descriptorSetCount;
-    const VkDescriptorSetLayout*    pSetLayouts;
-} VkDescriptorSetAllocateInfo;
-
-typedef struct VkDescriptorImageInfo {
-    VkSampler        sampler;
-    VkImageView      imageView;
-    VkImageLayout    imageLayout;
-} VkDescriptorImageInfo;
-
-typedef struct VkDescriptorBufferInfo {
-    VkBuffer        buffer;
-    VkDeviceSize    offset;
-    VkDeviceSize    range;
-} VkDescriptorBufferInfo;
-
-typedef struct VkWriteDescriptorSet {
-    VkStructureType                  sType;
-    const void*                      pNext;
-    VkDescriptorSet                  dstSet;
-    uint32_t                         dstBinding;
-    uint32_t                         dstArrayElement;
-    uint32_t                         descriptorCount;
-    VkDescriptorType                 descriptorType;
-    const VkDescriptorImageInfo*     pImageInfo;
-    const VkDescriptorBufferInfo*    pBufferInfo;
-    const VkBufferView*              pTexelBufferView;
-} VkWriteDescriptorSet;
-
-typedef struct VkCopyDescriptorSet {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkDescriptorSet    srcSet;
-    uint32_t           srcBinding;
-    uint32_t           srcArrayElement;
-    VkDescriptorSet    dstSet;
-    uint32_t           dstBinding;
-    uint32_t           dstArrayElement;
-    uint32_t           descriptorCount;
-} VkCopyDescriptorSet;
-
-typedef struct VkFramebufferCreateInfo {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkFramebufferCreateFlags    flags;
-    VkRenderPass                renderPass;
-    uint32_t                    attachmentCount;
-    const VkImageView*          pAttachments;
-    uint32_t                    width;
-    uint32_t                    height;
-    uint32_t                    layers;
-} VkFramebufferCreateInfo;
-
-typedef struct VkAttachmentDescription {
-    VkAttachmentDescriptionFlags    flags;
-    VkFormat                        format;
-    VkSampleCountFlagBits           samples;
-    VkAttachmentLoadOp              loadOp;
-    VkAttachmentStoreOp             storeOp;
-    VkAttachmentLoadOp              stencilLoadOp;
-    VkAttachmentStoreOp             stencilStoreOp;
-    VkImageLayout                   initialLayout;
-    VkImageLayout                   finalLayout;
-} VkAttachmentDescription;
-
-typedef struct VkAttachmentReference {
-    uint32_t         attachment;
-    VkImageLayout    layout;
-} VkAttachmentReference;
-
-typedef struct VkSubpassDescription {
-    VkSubpassDescriptionFlags       flags;
-    VkPipelineBindPoint             pipelineBindPoint;
-    uint32_t                        inputAttachmentCount;
-    const VkAttachmentReference*    pInputAttachments;
-    uint32_t                        colorAttachmentCount;
-    const VkAttachmentReference*    pColorAttachments;
-    const VkAttachmentReference*    pResolveAttachments;
-    const VkAttachmentReference*    pDepthStencilAttachment;
-    uint32_t                        preserveAttachmentCount;
-    const uint32_t*                 pPreserveAttachments;
-} VkSubpassDescription;
-
-typedef struct VkSubpassDependency {
-    uint32_t                srcSubpass;
-    uint32_t                dstSubpass;
-    VkPipelineStageFlags    srcStageMask;
-    VkPipelineStageFlags    dstStageMask;
-    VkAccessFlags           srcAccessMask;
-    VkAccessFlags           dstAccessMask;
-    VkDependencyFlags       dependencyFlags;
-} VkSubpassDependency;
-
-typedef struct VkRenderPassCreateInfo {
-    VkStructureType                   sType;
-    const void*                       pNext;
-    VkRenderPassCreateFlags           flags;
-    uint32_t                          attachmentCount;
-    const VkAttachmentDescription*    pAttachments;
-    uint32_t                          subpassCount;
-    const VkSubpassDescription*       pSubpasses;
-    uint32_t                          dependencyCount;
-    const VkSubpassDependency*        pDependencies;
-} VkRenderPassCreateInfo;
-
-typedef struct VkCommandPoolCreateInfo {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkCommandPoolCreateFlags    flags;
-    uint32_t                    queueFamilyIndex;
-} VkCommandPoolCreateInfo;
-
-typedef struct VkCommandBufferAllocateInfo {
-    VkStructureType         sType;
-    const void*             pNext;
-    VkCommandPool           commandPool;
-    VkCommandBufferLevel    level;
-    uint32_t                commandBufferCount;
-} VkCommandBufferAllocateInfo;
-
-typedef struct VkCommandBufferInheritanceInfo {
-    VkStructureType                  sType;
-    const void*                      pNext;
-    VkRenderPass                     renderPass;
-    uint32_t                         subpass;
-    VkFramebuffer                    framebuffer;
-    VkBool32                         occlusionQueryEnable;
-    VkQueryControlFlags              queryFlags;
-    VkQueryPipelineStatisticFlags    pipelineStatistics;
-} VkCommandBufferInheritanceInfo;
-
-typedef struct VkCommandBufferBeginInfo {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkCommandBufferUsageFlags                flags;
-    const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
-} VkCommandBufferBeginInfo;
-
-typedef struct VkBufferCopy {
-    VkDeviceSize    srcOffset;
-    VkDeviceSize    dstOffset;
-    VkDeviceSize    size;
-} VkBufferCopy;
-
-typedef struct VkImageSubresourceLayers {
-    VkImageAspectFlags    aspectMask;
-    uint32_t              mipLevel;
-    uint32_t              baseArrayLayer;
-    uint32_t              layerCount;
-} VkImageSubresourceLayers;
-
-typedef struct VkImageCopy {
-    VkImageSubresourceLayers    srcSubresource;
-    VkOffset3D                  srcOffset;
-    VkImageSubresourceLayers    dstSubresource;
-    VkOffset3D                  dstOffset;
-    VkExtent3D                  extent;
-} VkImageCopy;
-
-typedef struct VkImageBlit {
-    VkImageSubresourceLayers    srcSubresource;
-    VkOffset3D                  srcOffsets[2];
-    VkImageSubresourceLayers    dstSubresource;
-    VkOffset3D                  dstOffsets[2];
-} VkImageBlit;
-
-typedef struct VkBufferImageCopy {
-    VkDeviceSize                bufferOffset;
-    uint32_t                    bufferRowLength;
-    uint32_t                    bufferImageHeight;
-    VkImageSubresourceLayers    imageSubresource;
-    VkOffset3D                  imageOffset;
-    VkExtent3D                  imageExtent;
-} VkBufferImageCopy;
-
-typedef union VkClearColorValue {
-    float       float32[4];
-    int32_t     int32[4];
-    uint32_t    uint32[4];
-} VkClearColorValue;
-
-typedef struct VkClearDepthStencilValue {
-    float       depth;
-    uint32_t    stencil;
-} VkClearDepthStencilValue;
-
-typedef union VkClearValue {
-    VkClearColorValue           color;
-    VkClearDepthStencilValue    depthStencil;
-} VkClearValue;
-
-typedef struct VkClearAttachment {
-    VkImageAspectFlags    aspectMask;
-    uint32_t              colorAttachment;
-    VkClearValue          clearValue;
-} VkClearAttachment;
-
-typedef struct VkClearRect {
-    VkRect2D    rect;
-    uint32_t    baseArrayLayer;
-    uint32_t    layerCount;
-} VkClearRect;
-
-typedef struct VkImageResolve {
-    VkImageSubresourceLayers    srcSubresource;
-    VkOffset3D                  srcOffset;
-    VkImageSubresourceLayers    dstSubresource;
-    VkOffset3D                  dstOffset;
-    VkExtent3D                  extent;
-} VkImageResolve;
-
-typedef struct VkMemoryBarrier {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkAccessFlags      srcAccessMask;
-    VkAccessFlags      dstAccessMask;
-} VkMemoryBarrier;
-
-typedef struct VkBufferMemoryBarrier {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkAccessFlags      srcAccessMask;
-    VkAccessFlags      dstAccessMask;
-    uint32_t           srcQueueFamilyIndex;
-    uint32_t           dstQueueFamilyIndex;
-    VkBuffer           buffer;
-    VkDeviceSize       offset;
-    VkDeviceSize       size;
-} VkBufferMemoryBarrier;
-
-typedef struct VkImageMemoryBarrier {
-    VkStructureType            sType;
-    const void*                pNext;
-    VkAccessFlags              srcAccessMask;
-    VkAccessFlags              dstAccessMask;
-    VkImageLayout              oldLayout;
-    VkImageLayout              newLayout;
-    uint32_t                   srcQueueFamilyIndex;
-    uint32_t                   dstQueueFamilyIndex;
-    VkImage                    image;
-    VkImageSubresourceRange    subresourceRange;
-} VkImageMemoryBarrier;
-
-typedef struct VkRenderPassBeginInfo {
-    VkStructureType        sType;
-    const void*            pNext;
-    VkRenderPass           renderPass;
-    VkFramebuffer          framebuffer;
-    VkRect2D               renderArea;
-    uint32_t               clearValueCount;
-    const VkClearValue*    pClearValues;
-} VkRenderPassBeginInfo;
-
-typedef struct VkDispatchIndirectCommand {
-    uint32_t    x;
-    uint32_t    y;
-    uint32_t    z;
-} VkDispatchIndirectCommand;
-
-typedef struct VkDrawIndexedIndirectCommand {
-    uint32_t    indexCount;
-    uint32_t    instanceCount;
-    uint32_t    firstIndex;
-    int32_t     vertexOffset;
-    uint32_t    firstInstance;
-} VkDrawIndexedIndirectCommand;
-
-typedef struct VkDrawIndirectCommand {
-    uint32_t    vertexCount;
-    uint32_t    instanceCount;
-    uint32_t    firstVertex;
-    uint32_t    firstInstance;
-} VkDrawIndirectCommand;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
-typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
-typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName);
-typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
-typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);
-typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
-typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
-typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue);
-typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device);
-typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory);
-typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData);
-typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory);
-typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);
-typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);
-typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes);
-typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset);
-typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset);
-typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
-typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences);
-typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence);
-typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore);
-typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent);
-typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event);
-typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event);
-typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
-typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
-typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
-typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage);
-typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView);
-typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule);
-typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache);
-typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData);
-typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
-typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout);
-typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler);
-typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout);
-typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool);
-typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);
-typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets);
-typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets);
-typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer);
-typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
-typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool);
-typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);
-typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
-typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
-typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer);
-typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);
-typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
-typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports);
-typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors);
-typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth);
-typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor);
-typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]);
-typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);
-typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);
-typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);
-typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);
-typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets);
-typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType);
-typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);
-typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
-typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
-typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
-typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
-typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
-typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects);
-typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
-typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
-typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
-typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
-typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags);
-typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query);
-typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags);
-typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues);
-typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);
-typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents);
-typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer);
-typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
-    const VkInstanceCreateInfo*                 pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkInstance*                                 pInstance);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(
-    VkInstance                                  instance,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
-    VkInstance                                  instance,
-    uint32_t*                                   pPhysicalDeviceCount,
-    VkPhysicalDevice*                           pPhysicalDevices);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceFeatures*                   pFeatures);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkFormatProperties*                         pFormatProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkImageType                                 type,
-    VkImageTiling                               tiling,
-    VkImageUsageFlags                           usage,
-    VkImageCreateFlags                          flags,
-    VkImageFormatProperties*                    pImageFormatProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceProperties*                 pProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pQueueFamilyPropertyCount,
-    VkQueueFamilyProperties*                    pQueueFamilyProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceMemoryProperties*           pMemoryProperties);
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(
-    VkInstance                                  instance,
-    const char*                                 pName);
-
-VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(
-    VkDevice                                    device,
-    const char*                                 pName);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(
-    VkPhysicalDevice                            physicalDevice,
-    const VkDeviceCreateInfo*                   pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDevice*                                   pDevice);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(
-    VkDevice                                    device,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(
-    const char*                                 pLayerName,
-    uint32_t*                                   pPropertyCount,
-    VkExtensionProperties*                      pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(
-    VkPhysicalDevice                            physicalDevice,
-    const char*                                 pLayerName,
-    uint32_t*                                   pPropertyCount,
-    VkExtensionProperties*                      pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(
-    uint32_t*                                   pPropertyCount,
-    VkLayerProperties*                          pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pPropertyCount,
-    VkLayerProperties*                          pProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
-    VkDevice                                    device,
-    uint32_t                                    queueFamilyIndex,
-    uint32_t                                    queueIndex,
-    VkQueue*                                    pQueue);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(
-    VkQueue                                     queue,
-    uint32_t                                    submitCount,
-    const VkSubmitInfo*                         pSubmits,
-    VkFence                                     fence);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(
-    VkQueue                                     queue);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(
-    VkDevice                                    device);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(
-    VkDevice                                    device,
-    const VkMemoryAllocateInfo*                 pAllocateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDeviceMemory*                             pMemory);
-
-VKAPI_ATTR void VKAPI_CALL vkFreeMemory(
-    VkDevice                                    device,
-    VkDeviceMemory                              memory,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(
-    VkDevice                                    device,
-    VkDeviceMemory                              memory,
-    VkDeviceSize                                offset,
-    VkDeviceSize                                size,
-    VkMemoryMapFlags                            flags,
-    void**                                      ppData);
-
-VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(
-    VkDevice                                    device,
-    VkDeviceMemory                              memory);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(
-    VkDevice                                    device,
-    uint32_t                                    memoryRangeCount,
-    const VkMappedMemoryRange*                  pMemoryRanges);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(
-    VkDevice                                    device,
-    uint32_t                                    memoryRangeCount,
-    const VkMappedMemoryRange*                  pMemoryRanges);
-
-VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment(
-    VkDevice                                    device,
-    VkDeviceMemory                              memory,
-    VkDeviceSize*                               pCommittedMemoryInBytes);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(
-    VkDevice                                    device,
-    VkBuffer                                    buffer,
-    VkDeviceMemory                              memory,
-    VkDeviceSize                                memoryOffset);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(
-    VkDevice                                    device,
-    VkImage                                     image,
-    VkDeviceMemory                              memory,
-    VkDeviceSize                                memoryOffset);
-
-VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(
-    VkDevice                                    device,
-    VkBuffer                                    buffer,
-    VkMemoryRequirements*                       pMemoryRequirements);
-
-VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements(
-    VkDevice                                    device,
-    VkImage                                     image,
-    VkMemoryRequirements*                       pMemoryRequirements);
-
-VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements(
-    VkDevice                                    device,
-    VkImage                                     image,
-    uint32_t*                                   pSparseMemoryRequirementCount,
-    VkSparseImageMemoryRequirements*            pSparseMemoryRequirements);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkImageType                                 type,
-    VkSampleCountFlagBits                       samples,
-    VkImageUsageFlags                           usage,
-    VkImageTiling                               tiling,
-    uint32_t*                                   pPropertyCount,
-    VkSparseImageFormatProperties*              pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse(
-    VkQueue                                     queue,
-    uint32_t                                    bindInfoCount,
-    const VkBindSparseInfo*                     pBindInfo,
-    VkFence                                     fence);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence(
-    VkDevice                                    device,
-    const VkFenceCreateInfo*                    pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkFence*                                    pFence);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyFence(
-    VkDevice                                    device,
-    VkFence                                     fence,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(
-    VkDevice                                    device,
-    uint32_t                                    fenceCount,
-    const VkFence*                              pFences);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(
-    VkDevice                                    device,
-    VkFence                                     fence);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(
-    VkDevice                                    device,
-    uint32_t                                    fenceCount,
-    const VkFence*                              pFences,
-    VkBool32                                    waitAll,
-    uint64_t                                    timeout);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(
-    VkDevice                                    device,
-    const VkSemaphoreCreateInfo*                pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSemaphore*                                pSemaphore);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(
-    VkDevice                                    device,
-    VkSemaphore                                 semaphore,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent(
-    VkDevice                                    device,
-    const VkEventCreateInfo*                    pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkEvent*                                    pEvent);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(
-    VkDevice                                    device,
-    VkEvent                                     event,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus(
-    VkDevice                                    device,
-    VkEvent                                     event);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(
-    VkDevice                                    device,
-    VkEvent                                     event);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent(
-    VkDevice                                    device,
-    VkEvent                                     event);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(
-    VkDevice                                    device,
-    const VkQueryPoolCreateInfo*                pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkQueryPool*                                pQueryPool);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool(
-    VkDevice                                    device,
-    VkQueryPool                                 queryPool,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(
-    VkDevice                                    device,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    firstQuery,
-    uint32_t                                    queryCount,
-    size_t                                      dataSize,
-    void*                                       pData,
-    VkDeviceSize                                stride,
-    VkQueryResultFlags                          flags);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(
-    VkDevice                                    device,
-    const VkBufferCreateInfo*                   pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkBuffer*                                   pBuffer);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(
-    VkDevice                                    device,
-    VkBuffer                                    buffer,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(
-    VkDevice                                    device,
-    const VkBufferViewCreateInfo*               pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkBufferView*                               pView);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(
-    VkDevice                                    device,
-    VkBufferView                                bufferView,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(
-    VkDevice                                    device,
-    const VkImageCreateInfo*                    pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkImage*                                    pImage);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyImage(
-    VkDevice                                    device,
-    VkImage                                     image,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout(
-    VkDevice                                    device,
-    VkImage                                     image,
-    const VkImageSubresource*                   pSubresource,
-    VkSubresourceLayout*                        pLayout);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(
-    VkDevice                                    device,
-    const VkImageViewCreateInfo*                pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkImageView*                                pView);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyImageView(
-    VkDevice                                    device,
-    VkImageView                                 imageView,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(
-    VkDevice                                    device,
-    const VkShaderModuleCreateInfo*             pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkShaderModule*                             pShaderModule);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule(
-    VkDevice                                    device,
-    VkShaderModule                              shaderModule,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(
-    VkDevice                                    device,
-    const VkPipelineCacheCreateInfo*            pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkPipelineCache*                            pPipelineCache);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache(
-    VkDevice                                    device,
-    VkPipelineCache                             pipelineCache,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData(
-    VkDevice                                    device,
-    VkPipelineCache                             pipelineCache,
-    size_t*                                     pDataSize,
-    void*                                       pData);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches(
-    VkDevice                                    device,
-    VkPipelineCache                             dstCache,
-    uint32_t                                    srcCacheCount,
-    const VkPipelineCache*                      pSrcCaches);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines(
-    VkDevice                                    device,
-    VkPipelineCache                             pipelineCache,
-    uint32_t                                    createInfoCount,
-    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
-    const VkAllocationCallbacks*                pAllocator,
-    VkPipeline*                                 pPipelines);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines(
-    VkDevice                                    device,
-    VkPipelineCache                             pipelineCache,
-    uint32_t                                    createInfoCount,
-    const VkComputePipelineCreateInfo*          pCreateInfos,
-    const VkAllocationCallbacks*                pAllocator,
-    VkPipeline*                                 pPipelines);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(
-    VkDevice                                    device,
-    VkPipeline                                  pipeline,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(
-    VkDevice                                    device,
-    const VkPipelineLayoutCreateInfo*           pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkPipelineLayout*                           pPipelineLayout);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout(
-    VkDevice                                    device,
-    VkPipelineLayout                            pipelineLayout,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(
-    VkDevice                                    device,
-    const VkSamplerCreateInfo*                  pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSampler*                                  pSampler);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroySampler(
-    VkDevice                                    device,
-    VkSampler                                   sampler,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(
-    VkDevice                                    device,
-    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDescriptorSetLayout*                      pSetLayout);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout(
-    VkDevice                                    device,
-    VkDescriptorSetLayout                       descriptorSetLayout,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool(
-    VkDevice                                    device,
-    const VkDescriptorPoolCreateInfo*           pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDescriptorPool*                           pDescriptorPool);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool(
-    VkDevice                                    device,
-    VkDescriptorPool                            descriptorPool,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool(
-    VkDevice                                    device,
-    VkDescriptorPool                            descriptorPool,
-    VkDescriptorPoolResetFlags                  flags);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets(
-    VkDevice                                    device,
-    const VkDescriptorSetAllocateInfo*          pAllocateInfo,
-    VkDescriptorSet*                            pDescriptorSets);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets(
-    VkDevice                                    device,
-    VkDescriptorPool                            descriptorPool,
-    uint32_t                                    descriptorSetCount,
-    const VkDescriptorSet*                      pDescriptorSets);
-
-VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets(
-    VkDevice                                    device,
-    uint32_t                                    descriptorWriteCount,
-    const VkWriteDescriptorSet*                 pDescriptorWrites,
-    uint32_t                                    descriptorCopyCount,
-    const VkCopyDescriptorSet*                  pDescriptorCopies);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(
-    VkDevice                                    device,
-    const VkFramebufferCreateInfo*              pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkFramebuffer*                              pFramebuffer);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer(
-    VkDevice                                    device,
-    VkFramebuffer                               framebuffer,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(
-    VkDevice                                    device,
-    const VkRenderPassCreateInfo*               pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkRenderPass*                               pRenderPass);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass(
-    VkDevice                                    device,
-    VkRenderPass                                renderPass,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity(
-    VkDevice                                    device,
-    VkRenderPass                                renderPass,
-    VkExtent2D*                                 pGranularity);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(
-    VkDevice                                    device,
-    const VkCommandPoolCreateInfo*              pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkCommandPool*                              pCommandPool);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(
-    VkDevice                                    device,
-    VkCommandPool                               commandPool,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(
-    VkDevice                                    device,
-    VkCommandPool                               commandPool,
-    VkCommandPoolResetFlags                     flags);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(
-    VkDevice                                    device,
-    const VkCommandBufferAllocateInfo*          pAllocateInfo,
-    VkCommandBuffer*                            pCommandBuffers);
-
-VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(
-    VkDevice                                    device,
-    VkCommandPool                               commandPool,
-    uint32_t                                    commandBufferCount,
-    const VkCommandBuffer*                      pCommandBuffers);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(
-    VkCommandBuffer                             commandBuffer,
-    const VkCommandBufferBeginInfo*             pBeginInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(
-    VkCommandBuffer                             commandBuffer);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkCommandBufferResetFlags                   flags);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineBindPoint                         pipelineBindPoint,
-    VkPipeline                                  pipeline);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    firstViewport,
-    uint32_t                                    viewportCount,
-    const VkViewport*                           pViewports);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    firstScissor,
-    uint32_t                                    scissorCount,
-    const VkRect2D*                             pScissors);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(
-    VkCommandBuffer                             commandBuffer,
-    float                                       lineWidth);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias(
-    VkCommandBuffer                             commandBuffer,
-    float                                       depthBiasConstantFactor,
-    float                                       depthBiasClamp,
-    float                                       depthBiasSlopeFactor);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(
-    VkCommandBuffer                             commandBuffer,
-    const float                                 blendConstants[4]);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds(
-    VkCommandBuffer                             commandBuffer,
-    float                                       minDepthBounds,
-    float                                       maxDepthBounds);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask(
-    VkCommandBuffer                             commandBuffer,
-    VkStencilFaceFlags                          faceMask,
-    uint32_t                                    compareMask);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask(
-    VkCommandBuffer                             commandBuffer,
-    VkStencilFaceFlags                          faceMask,
-    uint32_t                                    writeMask);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference(
-    VkCommandBuffer                             commandBuffer,
-    VkStencilFaceFlags                          faceMask,
-    uint32_t                                    reference);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineBindPoint                         pipelineBindPoint,
-    VkPipelineLayout                            layout,
-    uint32_t                                    firstSet,
-    uint32_t                                    descriptorSetCount,
-    const VkDescriptorSet*                      pDescriptorSets,
-    uint32_t                                    dynamicOffsetCount,
-    const uint32_t*                             pDynamicOffsets);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset,
-    VkIndexType                                 indexType);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    firstBinding,
-    uint32_t                                    bindingCount,
-    const VkBuffer*                             pBuffers,
-    const VkDeviceSize*                         pOffsets);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDraw(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    vertexCount,
-    uint32_t                                    instanceCount,
-    uint32_t                                    firstVertex,
-    uint32_t                                    firstInstance);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    indexCount,
-    uint32_t                                    instanceCount,
-    uint32_t                                    firstIndex,
-    int32_t                                     vertexOffset,
-    uint32_t                                    firstInstance);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset,
-    uint32_t                                    drawCount,
-    uint32_t                                    stride);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset,
-    uint32_t                                    drawCount,
-    uint32_t                                    stride);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    groupCountX,
-    uint32_t                                    groupCountY,
-    uint32_t                                    groupCountZ);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    srcBuffer,
-    VkBuffer                                    dstBuffer,
-    uint32_t                                    regionCount,
-    const VkBufferCopy*                         pRegions);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     srcImage,
-    VkImageLayout                               srcImageLayout,
-    VkImage                                     dstImage,
-    VkImageLayout                               dstImageLayout,
-    uint32_t                                    regionCount,
-    const VkImageCopy*                          pRegions);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     srcImage,
-    VkImageLayout                               srcImageLayout,
-    VkImage                                     dstImage,
-    VkImageLayout                               dstImageLayout,
-    uint32_t                                    regionCount,
-    const VkImageBlit*                          pRegions,
-    VkFilter                                    filter);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    srcBuffer,
-    VkImage                                     dstImage,
-    VkImageLayout                               dstImageLayout,
-    uint32_t                                    regionCount,
-    const VkBufferImageCopy*                    pRegions);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     srcImage,
-    VkImageLayout                               srcImageLayout,
-    VkBuffer                                    dstBuffer,
-    uint32_t                                    regionCount,
-    const VkBufferImageCopy*                    pRegions);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    dstBuffer,
-    VkDeviceSize                                dstOffset,
-    VkDeviceSize                                dataSize,
-    const void*                                 pData);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    dstBuffer,
-    VkDeviceSize                                dstOffset,
-    VkDeviceSize                                size,
-    uint32_t                                    data);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     image,
-    VkImageLayout                               imageLayout,
-    const VkClearColorValue*                    pColor,
-    uint32_t                                    rangeCount,
-    const VkImageSubresourceRange*              pRanges);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     image,
-    VkImageLayout                               imageLayout,
-    const VkClearDepthStencilValue*             pDepthStencil,
-    uint32_t                                    rangeCount,
-    const VkImageSubresourceRange*              pRanges);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    attachmentCount,
-    const VkClearAttachment*                    pAttachments,
-    uint32_t                                    rectCount,
-    const VkClearRect*                          pRects);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage(
-    VkCommandBuffer                             commandBuffer,
-    VkImage                                     srcImage,
-    VkImageLayout                               srcImageLayout,
-    VkImage                                     dstImage,
-    VkImageLayout                               dstImageLayout,
-    uint32_t                                    regionCount,
-    const VkImageResolve*                       pRegions);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent(
-    VkCommandBuffer                             commandBuffer,
-    VkEvent                                     event,
-    VkPipelineStageFlags                        stageMask);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent(
-    VkCommandBuffer                             commandBuffer,
-    VkEvent                                     event,
-    VkPipelineStageFlags                        stageMask);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    eventCount,
-    const VkEvent*                              pEvents,
-    VkPipelineStageFlags                        srcStageMask,
-    VkPipelineStageFlags                        dstStageMask,
-    uint32_t                                    memoryBarrierCount,
-    const VkMemoryBarrier*                      pMemoryBarriers,
-    uint32_t                                    bufferMemoryBarrierCount,
-    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
-    uint32_t                                    imageMemoryBarrierCount,
-    const VkImageMemoryBarrier*                 pImageMemoryBarriers);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineStageFlags                        srcStageMask,
-    VkPipelineStageFlags                        dstStageMask,
-    VkDependencyFlags                           dependencyFlags,
-    uint32_t                                    memoryBarrierCount,
-    const VkMemoryBarrier*                      pMemoryBarriers,
-    uint32_t                                    bufferMemoryBarrierCount,
-    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
-    uint32_t                                    imageMemoryBarrierCount,
-    const VkImageMemoryBarrier*                 pImageMemoryBarriers);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery(
-    VkCommandBuffer                             commandBuffer,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    query,
-    VkQueryControlFlags                         flags);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(
-    VkCommandBuffer                             commandBuffer,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    query);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool(
-    VkCommandBuffer                             commandBuffer,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    firstQuery,
-    uint32_t                                    queryCount);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineStageFlagBits                     pipelineStage,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    query);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults(
-    VkCommandBuffer                             commandBuffer,
-    VkQueryPool                                 queryPool,
-    uint32_t                                    firstQuery,
-    uint32_t                                    queryCount,
-    VkBuffer                                    dstBuffer,
-    VkDeviceSize                                dstOffset,
-    VkDeviceSize                                stride,
-    VkQueryResultFlags                          flags);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineLayout                            layout,
-    VkShaderStageFlags                          stageFlags,
-    uint32_t                                    offset,
-    uint32_t                                    size,
-    const void*                                 pValues);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass(
-    VkCommandBuffer                             commandBuffer,
-    const VkRenderPassBeginInfo*                pRenderPassBegin,
-    VkSubpassContents                           contents);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(
-    VkCommandBuffer                             commandBuffer,
-    VkSubpassContents                           contents);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(
-    VkCommandBuffer                             commandBuffer);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    commandBufferCount,
-    const VkCommandBuffer*                      pCommandBuffers);
-#endif
-
-#define VK_KHR_surface 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
-
-#define VK_KHR_SURFACE_SPEC_VERSION       25
-#define VK_KHR_SURFACE_EXTENSION_NAME     "VK_KHR_surface"
-#define VK_COLORSPACE_SRGB_NONLINEAR_KHR  VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
-
-
-typedef enum VkColorSpaceKHR {
-    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
-    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
-    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
-    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,
-    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,
-    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,
-    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,
-    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,
-    VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,
-    VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,
-    VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,
-    VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
-    VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
-    VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
-    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
-    VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
-    VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
-    VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
-    VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkColorSpaceKHR;
-
-typedef enum VkPresentModeKHR {
-    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,
-    VK_PRESENT_MODE_MAILBOX_KHR = 1,
-    VK_PRESENT_MODE_FIFO_KHR = 2,
-    VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,
-    VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,
-    VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,
-    VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR,
-    VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR,
-    VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1),
-    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkPresentModeKHR;
-
-
-typedef enum VkSurfaceTransformFlagBitsKHR {
-    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,
-    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002,
-    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004,
-    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040,
-    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080,
-    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,
-    VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkSurfaceTransformFlagBitsKHR;
-typedef VkFlags VkSurfaceTransformFlagsKHR;
-
-typedef enum VkCompositeAlphaFlagBitsKHR {
-    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
-    VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002,
-    VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004,
-    VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008,
-    VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkCompositeAlphaFlagBitsKHR;
-typedef VkFlags VkCompositeAlphaFlagsKHR;
-
-typedef struct VkSurfaceCapabilitiesKHR {
-    uint32_t                         minImageCount;
-    uint32_t                         maxImageCount;
-    VkExtent2D                       currentExtent;
-    VkExtent2D                       minImageExtent;
-    VkExtent2D                       maxImageExtent;
-    uint32_t                         maxImageArrayLayers;
-    VkSurfaceTransformFlagsKHR       supportedTransforms;
-    VkSurfaceTransformFlagBitsKHR    currentTransform;
-    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;
-    VkImageUsageFlags                supportedUsageFlags;
-} VkSurfaceCapabilitiesKHR;
-
-typedef struct VkSurfaceFormatKHR {
-    VkFormat           format;
-    VkColorSpaceKHR    colorSpace;
-} VkSurfaceFormatKHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(
-    VkInstance                                  instance,
-    VkSurfaceKHR                                surface,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex,
-    VkSurfaceKHR                                surface,
-    VkBool32*                                   pSupported);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkSurfaceKHR                                surface,
-    VkSurfaceCapabilitiesKHR*                   pSurfaceCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkSurfaceKHR                                surface,
-    uint32_t*                                   pSurfaceFormatCount,
-    VkSurfaceFormatKHR*                         pSurfaceFormats);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkSurfaceKHR                                surface,
-    uint32_t*                                   pPresentModeCount,
-    VkPresentModeKHR*                           pPresentModes);
-#endif
-
-#define VK_KHR_swapchain 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR)
-
-#define VK_KHR_SWAPCHAIN_SPEC_VERSION     68
-#define VK_KHR_SWAPCHAIN_EXTENSION_NAME   "VK_KHR_swapchain"
-
-
-typedef enum VkSwapchainCreateFlagBitsKHR {
-    VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,
-    VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkSwapchainCreateFlagBitsKHR;
-typedef VkFlags VkSwapchainCreateFlagsKHR;
-
-typedef struct VkSwapchainCreateInfoKHR {
-    VkStructureType                  sType;
-    const void*                      pNext;
-    VkSwapchainCreateFlagsKHR        flags;
-    VkSurfaceKHR                     surface;
-    uint32_t                         minImageCount;
-    VkFormat                         imageFormat;
-    VkColorSpaceKHR                  imageColorSpace;
-    VkExtent2D                       imageExtent;
-    uint32_t                         imageArrayLayers;
-    VkImageUsageFlags                imageUsage;
-    VkSharingMode                    imageSharingMode;
-    uint32_t                         queueFamilyIndexCount;
-    const uint32_t*                  pQueueFamilyIndices;
-    VkSurfaceTransformFlagBitsKHR    preTransform;
-    VkCompositeAlphaFlagBitsKHR      compositeAlpha;
-    VkPresentModeKHR                 presentMode;
-    VkBool32                         clipped;
-    VkSwapchainKHR                   oldSwapchain;
-} VkSwapchainCreateInfoKHR;
-
-typedef struct VkPresentInfoKHR {
-    VkStructureType          sType;
-    const void*              pNext;
-    uint32_t                 waitSemaphoreCount;
-    const VkSemaphore*       pWaitSemaphores;
-    uint32_t                 swapchainCount;
-    const VkSwapchainKHR*    pSwapchains;
-    const uint32_t*          pImageIndices;
-    VkResult*                pResults;
-} VkPresentInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain);
-typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
-typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
-typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(
-    VkDevice                                    device,
-    const VkSwapchainCreateInfoKHR*             pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSwapchainKHR*                             pSwapchain);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    uint32_t*                                   pSwapchainImageCount,
-    VkImage*                                    pSwapchainImages);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    uint64_t                                    timeout,
-    VkSemaphore                                 semaphore,
-    VkFence                                     fence,
-    uint32_t*                                   pImageIndex);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
-    VkQueue                                     queue,
-    const VkPresentInfoKHR*                     pPresentInfo);
-#endif
-
-#define VK_KHR_display 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR)
-
-#define VK_KHR_DISPLAY_SPEC_VERSION       21
-#define VK_KHR_DISPLAY_EXTENSION_NAME     "VK_KHR_display"
-
-
-typedef enum VkDisplayPlaneAlphaFlagBitsKHR {
-    VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
-    VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002,
-    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004,
-    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008,
-    VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkDisplayPlaneAlphaFlagBitsKHR;
-typedef VkFlags VkDisplayPlaneAlphaFlagsKHR;
-typedef VkFlags VkDisplayModeCreateFlagsKHR;
-typedef VkFlags VkDisplaySurfaceCreateFlagsKHR;
-
-typedef struct VkDisplayPropertiesKHR {
-    VkDisplayKHR                  display;
-    const char*                   displayName;
-    VkExtent2D                    physicalDimensions;
-    VkExtent2D                    physicalResolution;
-    VkSurfaceTransformFlagsKHR    supportedTransforms;
-    VkBool32                      planeReorderPossible;
-    VkBool32                      persistentContent;
-} VkDisplayPropertiesKHR;
-
-typedef struct VkDisplayModeParametersKHR {
-    VkExtent2D    visibleRegion;
-    uint32_t      refreshRate;
-} VkDisplayModeParametersKHR;
-
-typedef struct VkDisplayModePropertiesKHR {
-    VkDisplayModeKHR              displayMode;
-    VkDisplayModeParametersKHR    parameters;
-} VkDisplayModePropertiesKHR;
-
-typedef struct VkDisplayModeCreateInfoKHR {
-    VkStructureType                sType;
-    const void*                    pNext;
-    VkDisplayModeCreateFlagsKHR    flags;
-    VkDisplayModeParametersKHR     parameters;
-} VkDisplayModeCreateInfoKHR;
-
-typedef struct VkDisplayPlaneCapabilitiesKHR {
-    VkDisplayPlaneAlphaFlagsKHR    supportedAlpha;
-    VkOffset2D                     minSrcPosition;
-    VkOffset2D                     maxSrcPosition;
-    VkExtent2D                     minSrcExtent;
-    VkExtent2D                     maxSrcExtent;
-    VkOffset2D                     minDstPosition;
-    VkOffset2D                     maxDstPosition;
-    VkExtent2D                     minDstExtent;
-    VkExtent2D                     maxDstExtent;
-} VkDisplayPlaneCapabilitiesKHR;
-
-typedef struct VkDisplayPlanePropertiesKHR {
-    VkDisplayKHR    currentDisplay;
-    uint32_t        currentStackIndex;
-} VkDisplayPlanePropertiesKHR;
-
-typedef struct VkDisplaySurfaceCreateInfoKHR {
-    VkStructureType                   sType;
-    const void*                       pNext;
-    VkDisplaySurfaceCreateFlagsKHR    flags;
-    VkDisplayModeKHR                  displayMode;
-    uint32_t                          planeIndex;
-    uint32_t                          planeStackIndex;
-    VkSurfaceTransformFlagBitsKHR     transform;
-    float                             globalAlpha;
-    VkDisplayPlaneAlphaFlagBitsKHR    alphaMode;
-    VkExtent2D                        imageExtent;
-} VkDisplaySurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pPropertyCount,
-    VkDisplayPropertiesKHR*                     pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pPropertyCount,
-    VkDisplayPlanePropertiesKHR*                pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    planeIndex,
-    uint32_t*                                   pDisplayCount,
-    VkDisplayKHR*                               pDisplays);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkDisplayKHR                                display,
-    uint32_t*                                   pPropertyCount,
-    VkDisplayModePropertiesKHR*                 pProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkDisplayKHR                                display,
-    const VkDisplayModeCreateInfoKHR*           pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDisplayModeKHR*                           pMode);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkDisplayModeKHR                            mode,
-    uint32_t                                    planeIndex,
-    VkDisplayPlaneCapabilitiesKHR*              pCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR(
-    VkInstance                                  instance,
-    const VkDisplaySurfaceCreateInfoKHR*        pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-#endif
-
-#define VK_KHR_display_swapchain 1
-#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9
-#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain"
-
-typedef struct VkDisplayPresentInfoKHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkRect2D           srcRect;
-    VkRect2D           dstRect;
-    VkBool32           persistent;
-} VkDisplayPresentInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR(
-    VkDevice                                    device,
-    uint32_t                                    swapchainCount,
-    const VkSwapchainCreateInfoKHR*             pCreateInfos,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSwapchainKHR*                             pSwapchains);
-#endif
-
-#ifdef VK_USE_PLATFORM_XLIB_KHR
-#define VK_KHR_xlib_surface 1
-#include <X11/Xlib.h>
-
-#define VK_KHR_XLIB_SURFACE_SPEC_VERSION  6
-#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
-
-typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
-
-typedef struct VkXlibSurfaceCreateInfoKHR {
-    VkStructureType                sType;
-    const void*                    pNext;
-    VkXlibSurfaceCreateFlagsKHR    flags;
-    Display*                       dpy;
-    Window                         window;
-} VkXlibSurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
-    VkInstance                                  instance,
-    const VkXlibSurfaceCreateInfoKHR*           pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex,
-    Display*                                    dpy,
-    VisualID                                    visualID);
-#endif
-#endif /* VK_USE_PLATFORM_XLIB_KHR */
-
-#ifdef VK_USE_PLATFORM_XCB_KHR
-#define VK_KHR_xcb_surface 1
-#include <xcb/xcb.h>
-
-#define VK_KHR_XCB_SURFACE_SPEC_VERSION   6
-#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
-
-typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
-
-typedef struct VkXcbSurfaceCreateInfoKHR {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkXcbSurfaceCreateFlagsKHR    flags;
-    xcb_connection_t*             connection;
-    xcb_window_t                  window;
-} VkXcbSurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
-    VkInstance                                  instance,
-    const VkXcbSurfaceCreateInfoKHR*            pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex,
-    xcb_connection_t*                           connection,
-    xcb_visualid_t                              visual_id);
-#endif
-#endif /* VK_USE_PLATFORM_XCB_KHR */
-
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
-#define VK_KHR_wayland_surface 1
-#include <wayland-client.h>
-
-#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
-#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
-
-typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
-
-typedef struct VkWaylandSurfaceCreateInfoKHR {
-    VkStructureType                   sType;
-    const void*                       pNext;
-    VkWaylandSurfaceCreateFlagsKHR    flags;
-    struct wl_display*                display;
-    struct wl_surface*                surface;
-} VkWaylandSurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(
-    VkInstance                                  instance,
-    const VkWaylandSurfaceCreateInfoKHR*        pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex,
-    struct wl_display*                          display);
-#endif
-#endif /* VK_USE_PLATFORM_WAYLAND_KHR */
-
-#ifdef VK_USE_PLATFORM_MIR_KHR
-#define VK_KHR_mir_surface 1
-#include <mir_toolkit/client_types.h>
-
-#define VK_KHR_MIR_SURFACE_SPEC_VERSION   4
-#define VK_KHR_MIR_SURFACE_EXTENSION_NAME "VK_KHR_mir_surface"
-
-typedef VkFlags VkMirSurfaceCreateFlagsKHR;
-
-typedef struct VkMirSurfaceCreateInfoKHR {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkMirSurfaceCreateFlagsKHR    flags;
-    MirConnection*                connection;
-    MirSurface*                   mirSurface;
-} VkMirSurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateMirSurfaceKHR)(VkInstance instance, const VkMirSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, MirConnection* connection);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR(
-    VkInstance                                  instance,
-    const VkMirSurfaceCreateInfoKHR*            pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentationSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex,
-    MirConnection*                              connection);
-#endif
-#endif /* VK_USE_PLATFORM_MIR_KHR */
+#include "vulkan_core.h"
 
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
-#define VK_KHR_android_surface 1
-
-#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
-#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface"
-
-typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
-
-typedef struct VkAndroidSurfaceCreateInfoKHR {
-    VkStructureType                   sType;
-    const void*                       pNext;
-    VkAndroidSurfaceCreateFlagsKHR    flags;
-    struct ANativeWindow*             window;
-} VkAndroidSurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
-    VkInstance                                  instance,
-    const VkAndroidSurfaceCreateInfoKHR*        pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-#endif
-#endif /* VK_USE_PLATFORM_ANDROID_KHR */
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHR_win32_surface 1
-#include <windows.h>
-
-#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
-#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface"
-
-typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
-
-typedef struct VkWin32SurfaceCreateInfoKHR {
-    VkStructureType                 sType;
-    const void*                     pNext;
-    VkWin32SurfaceCreateFlagsKHR    flags;
-    HINSTANCE                       hinstance;
-    HWND                            hwnd;
-} VkWin32SurfaceCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(
-    VkInstance                                  instance,
-    const VkWin32SurfaceCreateInfoKHR*          pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-
-VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t                                    queueFamilyIndex);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHR_sampler_mirror_clamp_to_edge 1
-#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
-#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
-
-
-#define VK_KHR_get_physical_device_properties2 1
-#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
-#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
-
-typedef struct VkPhysicalDeviceFeatures2KHR {
-    VkStructureType             sType;
-    void*                       pNext;
-    VkPhysicalDeviceFeatures    features;
-} VkPhysicalDeviceFeatures2KHR;
-
-typedef struct VkPhysicalDeviceProperties2KHR {
-    VkStructureType               sType;
-    void*                         pNext;
-    VkPhysicalDeviceProperties    properties;
-} VkPhysicalDeviceProperties2KHR;
-
-typedef struct VkFormatProperties2KHR {
-    VkStructureType       sType;
-    void*                 pNext;
-    VkFormatProperties    formatProperties;
-} VkFormatProperties2KHR;
-
-typedef struct VkImageFormatProperties2KHR {
-    VkStructureType            sType;
-    void*                      pNext;
-    VkImageFormatProperties    imageFormatProperties;
-} VkImageFormatProperties2KHR;
-
-typedef struct VkPhysicalDeviceImageFormatInfo2KHR {
-    VkStructureType       sType;
-    const void*           pNext;
-    VkFormat              format;
-    VkImageType           type;
-    VkImageTiling         tiling;
-    VkImageUsageFlags     usage;
-    VkImageCreateFlags    flags;
-} VkPhysicalDeviceImageFormatInfo2KHR;
-
-typedef struct VkQueueFamilyProperties2KHR {
-    VkStructureType            sType;
-    void*                      pNext;
-    VkQueueFamilyProperties    queueFamilyProperties;
-} VkQueueFamilyProperties2KHR;
-
-typedef struct VkPhysicalDeviceMemoryProperties2KHR {
-    VkStructureType                     sType;
-    void*                               pNext;
-    VkPhysicalDeviceMemoryProperties    memoryProperties;
-} VkPhysicalDeviceMemoryProperties2KHR;
-
-typedef struct VkSparseImageFormatProperties2KHR {
-    VkStructureType                  sType;
-    void*                            pNext;
-    VkSparseImageFormatProperties    properties;
-} VkSparseImageFormatProperties2KHR;
-
-typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR {
-    VkStructureType          sType;
-    const void*              pNext;
-    VkFormat                 format;
-    VkImageType              type;
-    VkSampleCountFlagBits    samples;
-    VkImageUsageFlags        usage;
-    VkImageTiling            tiling;
-} VkPhysicalDeviceSparseImageFormatInfo2KHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceFeatures2KHR*               pFeatures);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceProperties2KHR*             pProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkFormatProperties2KHR*                     pFormatProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceImageFormatInfo2KHR*  pImageFormatInfo,
-    VkImageFormatProperties2KHR*                pImageFormatProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    uint32_t*                                   pQueueFamilyPropertyCount,
-    VkQueueFamilyProperties2KHR*                pQueueFamilyProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    VkPhysicalDeviceMemoryProperties2KHR*       pMemoryProperties);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
-    uint32_t*                                   pPropertyCount,
-    VkSparseImageFormatProperties2KHR*          pProperties);
+#include "vulkan_android.h"
 #endif
 
-#define VK_KHR_shader_draw_parameters 1
-#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
-#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
 
-
-#define VK_KHR_maintenance1 1
-#define VK_KHR_MAINTENANCE1_SPEC_VERSION  1
-#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
-
-typedef VkFlags VkCommandPoolTrimFlagsKHR;
-
-typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(
-    VkDevice                                    device,
-    VkCommandPool                               commandPool,
-    VkCommandPoolTrimFlagsKHR                   flags);
+#ifdef VK_USE_PLATFORM_IOS_MVK
+#include "vulkan_ios.h"
 #endif
 
-#define VK_KHR_external_memory_capabilities 1
-#define VK_LUID_SIZE_KHR                  8
-#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities"
 
-
-typedef enum VkExternalMemoryHandleTypeFlagBitsKHR {
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = 0x00000008,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = 0x00000010,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = 0x00000020,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = 0x00000040,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalMemoryHandleTypeFlagBitsKHR;
-typedef VkFlags VkExternalMemoryHandleTypeFlagsKHR;
-
-typedef enum VkExternalMemoryFeatureFlagBitsKHR {
-    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = 0x00000004,
-    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalMemoryFeatureFlagBitsKHR;
-typedef VkFlags VkExternalMemoryFeatureFlagsKHR;
-
-typedef struct VkExternalMemoryPropertiesKHR {
-    VkExternalMemoryFeatureFlagsKHR       externalMemoryFeatures;
-    VkExternalMemoryHandleTypeFlagsKHR    exportFromImportedHandleTypes;
-    VkExternalMemoryHandleTypeFlagsKHR    compatibleHandleTypes;
-} VkExternalMemoryPropertiesKHR;
-
-typedef struct VkPhysicalDeviceExternalImageFormatInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-} VkPhysicalDeviceExternalImageFormatInfoKHR;
-
-typedef struct VkExternalImageFormatPropertiesKHR {
-    VkStructureType                  sType;
-    void*                            pNext;
-    VkExternalMemoryPropertiesKHR    externalMemoryProperties;
-} VkExternalImageFormatPropertiesKHR;
-
-typedef struct VkPhysicalDeviceExternalBufferInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkBufferCreateFlags                      flags;
-    VkBufferUsageFlags                       usage;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-} VkPhysicalDeviceExternalBufferInfoKHR;
-
-typedef struct VkExternalBufferPropertiesKHR {
-    VkStructureType                  sType;
-    void*                            pNext;
-    VkExternalMemoryPropertiesKHR    externalMemoryProperties;
-} VkExternalBufferPropertiesKHR;
-
-typedef struct VkPhysicalDeviceIDPropertiesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    uint8_t            deviceUUID[VK_UUID_SIZE];
-    uint8_t            driverUUID[VK_UUID_SIZE];
-    uint8_t            deviceLUID[VK_LUID_SIZE_KHR];
-    uint32_t           deviceNodeMask;
-    VkBool32           deviceLUIDValid;
-} VkPhysicalDeviceIDPropertiesKHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo, VkExternalBufferPropertiesKHR* pExternalBufferProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo,
-    VkExternalBufferPropertiesKHR*              pExternalBufferProperties);
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+#include "vulkan_macos.h"
 #endif
 
-#define VK_KHR_external_memory 1
-#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory"
-#define VK_QUEUE_FAMILY_EXTERNAL_KHR      (~0U-1)
 
-typedef struct VkExternalMemoryImageCreateInfoKHR {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkExternalMemoryHandleTypeFlagsKHR    handleTypes;
-} VkExternalMemoryImageCreateInfoKHR;
-
-typedef struct VkExternalMemoryBufferCreateInfoKHR {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkExternalMemoryHandleTypeFlagsKHR    handleTypes;
-} VkExternalMemoryBufferCreateInfoKHR;
-
-typedef struct VkExportMemoryAllocateInfoKHR {
-    VkStructureType                       sType;
-    const void*                           pNext;
-    VkExternalMemoryHandleTypeFlagsKHR    handleTypes;
-} VkExportMemoryAllocateInfoKHR;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHR_external_memory_win32 1
-#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
-
-typedef struct VkImportMemoryWin32HandleInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-    HANDLE                                   handle;
-    LPCWSTR                                  name;
-} VkImportMemoryWin32HandleInfoKHR;
-
-typedef struct VkExportMemoryWin32HandleInfoKHR {
-    VkStructureType               sType;
-    const void*                   pNext;
-    const SECURITY_ATTRIBUTES*    pAttributes;
-    DWORD                         dwAccess;
-    LPCWSTR                       name;
-} VkExportMemoryWin32HandleInfoKHR;
-
-typedef struct VkMemoryWin32HandlePropertiesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           memoryTypeBits;
-} VkMemoryWin32HandlePropertiesKHR;
-
-typedef struct VkMemoryGetWin32HandleInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkDeviceMemory                           memory;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-} VkMemoryGetWin32HandleInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHR handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(
-    VkDevice                                    device,
-    const VkMemoryGetWin32HandleInfoKHR*        pGetWin32HandleInfo,
-    HANDLE*                                     pHandle);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(
-    VkDevice                                    device,
-    VkExternalMemoryHandleTypeFlagBitsKHR       handleType,
-    HANDLE                                      handle,
-    VkMemoryWin32HandlePropertiesKHR*           pMemoryWin32HandleProperties);
+#ifdef VK_USE_PLATFORM_MIR_KHR
+#include <mir_toolkit/client_types.h>
+#include "vulkan_mir.h"
 #endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHR_external_memory_fd 1
-#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd"
-
-typedef struct VkImportMemoryFdInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-    int                                      fd;
-} VkImportMemoryFdInfoKHR;
-
-typedef struct VkMemoryFdPropertiesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           memoryTypeBits;
-} VkMemoryFdPropertiesKHR;
-
-typedef struct VkMemoryGetFdInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkDeviceMemory                           memory;
-    VkExternalMemoryHandleTypeFlagBitsKHR    handleType;
-} VkMemoryGetFdInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd);
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHR handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR(
-    VkDevice                                    device,
-    const VkMemoryGetFdInfoKHR*                 pGetFdInfo,
-    int*                                        pFd);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR(
-    VkDevice                                    device,
-    VkExternalMemoryHandleTypeFlagBitsKHR       handleType,
-    int                                         fd,
-    VkMemoryFdPropertiesKHR*                    pMemoryFdProperties);
-#endif
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHR_win32_keyed_mutex 1
-#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
-
-typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR {
-    VkStructureType          sType;
-    const void*              pNext;
-    uint32_t                 acquireCount;
-    const VkDeviceMemory*    pAcquireSyncs;
-    const uint64_t*          pAcquireKeys;
-    const uint32_t*          pAcquireTimeouts;
-    uint32_t                 releaseCount;
-    const VkDeviceMemory*    pReleaseSyncs;
-    const uint64_t*          pReleaseKeys;
-} VkWin32KeyedMutexAcquireReleaseInfoKHR;
-
-
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHR_external_semaphore_capabilities 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities"
-
-
-typedef enum VkExternalSemaphoreHandleTypeFlagBitsKHR {
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = 0x00000008,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000010,
-    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalSemaphoreHandleTypeFlagBitsKHR;
-typedef VkFlags VkExternalSemaphoreHandleTypeFlagsKHR;
-
-typedef enum VkExternalSemaphoreFeatureFlagBitsKHR {
-    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalSemaphoreFeatureFlagBitsKHR;
-typedef VkFlags VkExternalSemaphoreFeatureFlagsKHR;
-
-typedef struct VkPhysicalDeviceExternalSemaphoreInfoKHR {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkExternalSemaphoreHandleTypeFlagBitsKHR    handleType;
-} VkPhysicalDeviceExternalSemaphoreInfoKHR;
-
-typedef struct VkExternalSemaphorePropertiesKHR {
-    VkStructureType                          sType;
-    void*                                    pNext;
-    VkExternalSemaphoreHandleTypeFlagsKHR    exportFromImportedHandleTypes;
-    VkExternalSemaphoreHandleTypeFlagsKHR    compatibleHandleTypes;
-    VkExternalSemaphoreFeatureFlagsKHR       externalSemaphoreFeatures;
-} VkExternalSemaphorePropertiesKHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo, VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
-    VkExternalSemaphorePropertiesKHR*           pExternalSemaphoreProperties);
-#endif
-
-#define VK_KHR_external_semaphore 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore"
-
-
-typedef enum VkSemaphoreImportFlagBitsKHR {
-    VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
-    VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkSemaphoreImportFlagBitsKHR;
-typedef VkFlags VkSemaphoreImportFlagsKHR;
-
-typedef struct VkExportSemaphoreCreateInfoKHR {
-    VkStructureType                          sType;
-    const void*                              pNext;
-    VkExternalSemaphoreHandleTypeFlagsKHR    handleTypes;
-} VkExportSemaphoreCreateInfoKHR;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHR_external_semaphore_win32 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
-
-typedef struct VkImportSemaphoreWin32HandleInfoKHR {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkSemaphore                                 semaphore;
-    VkSemaphoreImportFlagsKHR                   flags;
-    VkExternalSemaphoreHandleTypeFlagBitsKHR    handleType;
-    HANDLE                                      handle;
-    LPCWSTR                                     name;
-} VkImportSemaphoreWin32HandleInfoKHR;
-
-typedef struct VkExportSemaphoreWin32HandleInfoKHR {
-    VkStructureType               sType;
-    const void*                   pNext;
-    const SECURITY_ATTRIBUTES*    pAttributes;
-    DWORD                         dwAccess;
-    LPCWSTR                       name;
-} VkExportSemaphoreWin32HandleInfoKHR;
-
-typedef struct VkD3D12FenceSubmitInfoKHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           waitSemaphoreValuesCount;
-    const uint64_t*    pWaitSemaphoreValues;
-    uint32_t           signalSemaphoreValuesCount;
-    const uint64_t*    pSignalSemaphoreValues;
-} VkD3D12FenceSubmitInfoKHR;
-
-typedef struct VkSemaphoreGetWin32HandleInfoKHR {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkSemaphore                                 semaphore;
-    VkExternalSemaphoreHandleTypeFlagBitsKHR    handleType;
-} VkSemaphoreGetWin32HandleInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR(
-    VkDevice                                    device,
-    const VkImportSemaphoreWin32HandleInfoKHR*  pImportSemaphoreWin32HandleInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR(
-    VkDevice                                    device,
-    const VkSemaphoreGetWin32HandleInfoKHR*     pGetWin32HandleInfo,
-    HANDLE*                                     pHandle);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHR_external_semaphore_fd 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
-
-typedef struct VkImportSemaphoreFdInfoKHR {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkSemaphore                                 semaphore;
-    VkSemaphoreImportFlagsKHR                   flags;
-    VkExternalSemaphoreHandleTypeFlagBitsKHR    handleType;
-    int                                         fd;
-} VkImportSemaphoreFdInfoKHR;
-
-typedef struct VkSemaphoreGetFdInfoKHR {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkSemaphore                                 semaphore;
-    VkExternalSemaphoreHandleTypeFlagBitsKHR    handleType;
-} VkSemaphoreGetFdInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR(
-    VkDevice                                    device,
-    const VkImportSemaphoreFdInfoKHR*           pImportSemaphoreFdInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR(
-    VkDevice                                    device,
-    const VkSemaphoreGetFdInfoKHR*              pGetFdInfo,
-    int*                                        pFd);
-#endif
-
-#define VK_KHR_push_descriptor 1
-#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
-#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
-
-typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           maxPushDescriptors;
-} VkPhysicalDevicePushDescriptorPropertiesKHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(
-    VkCommandBuffer                             commandBuffer,
-    VkPipelineBindPoint                         pipelineBindPoint,
-    VkPipelineLayout                            layout,
-    uint32_t                                    set,
-    uint32_t                                    descriptorWriteCount,
-    const VkWriteDescriptorSet*                 pDescriptorWrites);
-#endif
-
-#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"
-
-typedef struct VkPhysicalDevice16BitStorageFeaturesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           storageBuffer16BitAccess;
-    VkBool32           uniformAndStorageBuffer16BitAccess;
-    VkBool32           storagePushConstant16;
-    VkBool32           storageInputOutput16;
-} VkPhysicalDevice16BitStorageFeaturesKHR;
-
-
-
-#define VK_KHR_incremental_present 1
-#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
-#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
-
-typedef struct VkRectLayerKHR {
-    VkOffset2D    offset;
-    VkExtent2D    extent;
-    uint32_t      layer;
-} VkRectLayerKHR;
-
-typedef struct VkPresentRegionKHR {
-    uint32_t                 rectangleCount;
-    const VkRectLayerKHR*    pRectangles;
-} VkPresentRegionKHR;
-
-typedef struct VkPresentRegionsKHR {
-    VkStructureType              sType;
-    const void*                  pNext;
-    uint32_t                     swapchainCount;
-    const VkPresentRegionKHR*    pRegions;
-} VkPresentRegionsKHR;
-
-
-
-#define VK_KHR_descriptor_update_template 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR)
-
-#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
-#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
-
-
-typedef enum VkDescriptorUpdateTemplateTypeKHR {
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR,
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE_KHR = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR + 1),
-    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkDescriptorUpdateTemplateTypeKHR;
-
-typedef VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
-
-typedef struct VkDescriptorUpdateTemplateEntryKHR {
-    uint32_t            dstBinding;
-    uint32_t            dstArrayElement;
-    uint32_t            descriptorCount;
-    VkDescriptorType    descriptorType;
-    size_t              offset;
-    size_t              stride;
-} VkDescriptorUpdateTemplateEntryKHR;
-
-typedef struct VkDescriptorUpdateTemplateCreateInfoKHR {
-    VkStructureType                              sType;
-    void*                                        pNext;
-    VkDescriptorUpdateTemplateCreateFlagsKHR     flags;
-    uint32_t                                     descriptorUpdateEntryCount;
-    const VkDescriptorUpdateTemplateEntryKHR*    pDescriptorUpdateEntries;
-    VkDescriptorUpdateTemplateTypeKHR            templateType;
-    VkDescriptorSetLayout                        descriptorSetLayout;
-    VkPipelineBindPoint                          pipelineBindPoint;
-    VkPipelineLayout                             pipelineLayout;
-    uint32_t                                     set;
-} VkDescriptorUpdateTemplateCreateInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
-typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(
-    VkDevice                                    device,
-    const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDescriptorUpdateTemplateKHR*              pDescriptorUpdateTemplate);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(
-    VkDevice                                    device,
-    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(
-    VkDevice                                    device,
-    VkDescriptorSet                             descriptorSet,
-    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,
-    const void*                                 pData);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(
-    VkCommandBuffer                             commandBuffer,
-    VkDescriptorUpdateTemplateKHR               descriptorUpdateTemplate,
-    VkPipelineLayout                            layout,
-    uint32_t                                    set,
-    const void*                                 pData);
-#endif
-
-#define VK_KHR_shared_presentable_image 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-
-typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
-    VkStructureType      sType;
-    void*                pNext;
-    VkImageUsageFlags    sharedPresentSupportedUsageFlags;
-} VkSharedPresentSurfaceCapabilitiesKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain);
-#endif
-
-#define VK_KHR_external_fence_capabilities 1
-#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities"
-
-
-typedef enum VkExternalFenceHandleTypeFlagBitsKHR {
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000008,
-    VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalFenceHandleTypeFlagBitsKHR;
-typedef VkFlags VkExternalFenceHandleTypeFlagsKHR;
-
-typedef enum VkExternalFenceFeatureFlagBitsKHR {
-    VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
-    VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
-    VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkExternalFenceFeatureFlagBitsKHR;
-typedef VkFlags VkExternalFenceFeatureFlagsKHR;
-
-typedef struct VkPhysicalDeviceExternalFenceInfoKHR {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkExternalFenceHandleTypeFlagBitsKHR    handleType;
-} VkPhysicalDeviceExternalFenceInfoKHR;
-
-typedef struct VkExternalFencePropertiesKHR {
-    VkStructureType                      sType;
-    void*                                pNext;
-    VkExternalFenceHandleTypeFlagsKHR    exportFromImportedHandleTypes;
-    VkExternalFenceHandleTypeFlagsKHR    compatibleHandleTypes;
-    VkExternalFenceFeatureFlagsKHR       externalFenceFeatures;
-} VkExternalFencePropertiesKHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo, VkExternalFencePropertiesKHR* pExternalFenceProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo,
-    VkExternalFencePropertiesKHR*               pExternalFenceProperties);
-#endif
-
-#define VK_KHR_external_fence 1
-#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence"
-
-
-typedef enum VkFenceImportFlagBitsKHR {
-    VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
-    VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
-} VkFenceImportFlagBitsKHR;
-typedef VkFlags VkFenceImportFlagsKHR;
-
-typedef struct VkExportFenceCreateInfoKHR {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkExternalFenceHandleTypeFlagsKHR    handleTypes;
-} VkExportFenceCreateInfoKHR;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_KHR_external_fence_win32 1
-#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
-
-typedef struct VkImportFenceWin32HandleInfoKHR {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkFence                                 fence;
-    VkFenceImportFlagsKHR                   flags;
-    VkExternalFenceHandleTypeFlagBitsKHR    handleType;
-    HANDLE                                  handle;
-    LPCWSTR                                 name;
-} VkImportFenceWin32HandleInfoKHR;
-
-typedef struct VkExportFenceWin32HandleInfoKHR {
-    VkStructureType               sType;
-    const void*                   pNext;
-    const SECURITY_ATTRIBUTES*    pAttributes;
-    DWORD                         dwAccess;
-    LPCWSTR                       name;
-} VkExportFenceWin32HandleInfoKHR;
-
-typedef struct VkFenceGetWin32HandleInfoKHR {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkFence                                 fence;
-    VkExternalFenceHandleTypeFlagBitsKHR    handleType;
-} VkFenceGetWin32HandleInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR(
-    VkDevice                                    device,
-    const VkImportFenceWin32HandleInfoKHR*      pImportFenceWin32HandleInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR(
-    VkDevice                                    device,
-    const VkFenceGetWin32HandleInfoKHR*         pGetWin32HandleInfo,
-    HANDLE*                                     pHandle);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHR_external_fence_fd 1
-#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
-#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
-
-typedef struct VkImportFenceFdInfoKHR {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkFence                                 fence;
-    VkFenceImportFlagsKHR                   flags;
-    VkExternalFenceHandleTypeFlagBitsKHR    handleType;
-    int                                     fd;
-} VkImportFenceFdInfoKHR;
-
-typedef struct VkFenceGetFdInfoKHR {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkFence                                 fence;
-    VkExternalFenceHandleTypeFlagBitsKHR    handleType;
-} VkFenceGetFdInfoKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR(
-    VkDevice                                    device,
-    const VkImportFenceFdInfoKHR*               pImportFenceFdInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR(
-    VkDevice                                    device,
-    const VkFenceGetFdInfoKHR*                  pGetFdInfo,
-    int*                                        pFd);
-#endif
-
-#define VK_KHR_get_surface_capabilities2 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
-
-typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkSurfaceKHR       surface;
-} VkPhysicalDeviceSurfaceInfo2KHR;
-
-typedef struct VkSurfaceCapabilities2KHR {
-    VkStructureType             sType;
-    void*                       pNext;
-    VkSurfaceCapabilitiesKHR    surfaceCapabilities;
-} VkSurfaceCapabilities2KHR;
-
-typedef struct VkSurfaceFormat2KHR {
-    VkStructureType       sType;
-    void*                 pNext;
-    VkSurfaceFormatKHR    surfaceFormat;
-} VkSurfaceFormat2KHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
-    VkSurfaceCapabilities2KHR*                  pSurfaceCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
-    uint32_t*                                   pSurfaceFormatCount,
-    VkSurfaceFormat2KHR*                        pSurfaceFormats);
-#endif
-
-#define VK_KHR_variable_pointers 1
-#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1
-#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers"
-
-typedef struct VkPhysicalDeviceVariablePointerFeaturesKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           variablePointersStorageBuffer;
-    VkBool32           variablePointers;
-} VkPhysicalDeviceVariablePointerFeaturesKHR;
-
-
-
-#define VK_KHR_dedicated_allocation 1
-#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 1
-#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
-
-typedef struct VkMemoryDedicatedRequirementsKHR {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           prefersDedicatedAllocation;
-    VkBool32           requiresDedicatedAllocation;
-} VkMemoryDedicatedRequirementsKHR;
-
-typedef struct VkMemoryDedicatedAllocateInfoKHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkImage            image;
-    VkBuffer           buffer;
-} VkMemoryDedicatedAllocateInfoKHR;
-
-
-
-#define VK_KHR_storage_buffer_storage_class 1
-#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1
-#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class"
-
-
-#define VK_KHR_get_memory_requirements2 1
-#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1
-#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
-
-typedef struct VkBufferMemoryRequirementsInfo2KHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkBuffer           buffer;
-} VkBufferMemoryRequirementsInfo2KHR;
-
-typedef struct VkImageMemoryRequirementsInfo2KHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkImage            image;
-} VkImageMemoryRequirementsInfo2KHR;
-
-typedef struct VkImageSparseMemoryRequirementsInfo2KHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkImage            image;
-} VkImageSparseMemoryRequirementsInfo2KHR;
-
-typedef struct VkMemoryRequirements2KHR {
-    VkStructureType         sType;
-    void*                   pNext;
-    VkMemoryRequirements    memoryRequirements;
-} VkMemoryRequirements2KHR;
-
-typedef struct VkSparseImageMemoryRequirements2KHR {
-    VkStructureType                    sType;
-    void*                              pNext;
-    VkSparseImageMemoryRequirements    memoryRequirements;
-} VkSparseImageMemoryRequirements2KHR;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2KHR* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2KHR* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2KHR* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR(
-    VkDevice                                    device,
-    const VkImageMemoryRequirementsInfo2KHR*    pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements);
-
-VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR(
-    VkDevice                                    device,
-    const VkBufferMemoryRequirementsInfo2KHR*   pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements);
-
-VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR(
-    VkDevice                                    device,
-    const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
-    uint32_t*                                   pSparseMemoryRequirementCount,
-    VkSparseImageMemoryRequirements2KHR*        pSparseMemoryRequirements);
-#endif
-
-#define VK_EXT_debug_report 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  8
-#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
-#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
-#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT
-
-
-typedef enum VkDebugReportObjectTypeEXT {
-    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
-    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
-    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
-    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
-    VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
-    VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
-    VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,
-    VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
-    VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDebugReportObjectTypeEXT;
-
-
-typedef enum VkDebugReportFlagBitsEXT {
-    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
-    VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
-    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
-    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
-    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
-    VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDebugReportFlagBitsEXT;
-typedef VkFlags VkDebugReportFlagsEXT;
-
-typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
-    VkDebugReportFlagsEXT                       flags,
-    VkDebugReportObjectTypeEXT                  objectType,
-    uint64_t                                    object,
-    size_t                                      location,
-    int32_t                                     messageCode,
-    const char*                                 pLayerPrefix,
-    const char*                                 pMessage,
-    void*                                       pUserData);
-
-
-typedef struct VkDebugReportCallbackCreateInfoEXT {
-    VkStructureType                 sType;
-    const void*                     pNext;
-    VkDebugReportFlagsEXT           flags;
-    PFN_vkDebugReportCallbackEXT    pfnCallback;
-    void*                           pUserData;
-} VkDebugReportCallbackCreateInfoEXT;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
-typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
-    VkInstance                                  instance,
-    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDebugReportCallbackEXT*                   pCallback);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
-    VkInstance                                  instance,
-    VkDebugReportCallbackEXT                    callback,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
-    VkInstance                                  instance,
-    VkDebugReportFlagsEXT                       flags,
-    VkDebugReportObjectTypeEXT                  objectType,
-    uint64_t                                    object,
-    size_t                                      location,
-    int32_t                                     messageCode,
-    const char*                                 pLayerPrefix,
-    const char*                                 pMessage);
-#endif
-
-#define VK_NV_glsl_shader 1
-#define VK_NV_GLSL_SHADER_SPEC_VERSION    1
-#define VK_NV_GLSL_SHADER_EXTENSION_NAME  "VK_NV_glsl_shader"
-
-
-#define VK_IMG_filter_cubic 1
-#define VK_IMG_FILTER_CUBIC_SPEC_VERSION  1
-#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic"
-
-
-#define VK_AMD_rasterization_order 1
-#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
-#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order"
-
-
-typedef enum VkRasterizationOrderAMD {
-    VK_RASTERIZATION_ORDER_STRICT_AMD = 0,
-    VK_RASTERIZATION_ORDER_RELAXED_AMD = 1,
-    VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD,
-    VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD,
-    VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1),
-    VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF
-} VkRasterizationOrderAMD;
-
-typedef struct VkPipelineRasterizationStateRasterizationOrderAMD {
-    VkStructureType            sType;
-    const void*                pNext;
-    VkRasterizationOrderAMD    rasterizationOrder;
-} VkPipelineRasterizationStateRasterizationOrderAMD;
-
-
-
-#define VK_AMD_shader_trinary_minmax 1
-#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
-#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
-
-
-#define VK_AMD_shader_explicit_vertex_parameter 1
-#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
-#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
-
-
-#define VK_EXT_debug_marker 1
-#define VK_EXT_DEBUG_MARKER_SPEC_VERSION  4
-#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker"
-
-typedef struct VkDebugMarkerObjectNameInfoEXT {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkDebugReportObjectTypeEXT    objectType;
-    uint64_t                      object;
-    const char*                   pObjectName;
-} VkDebugMarkerObjectNameInfoEXT;
-
-typedef struct VkDebugMarkerObjectTagInfoEXT {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkDebugReportObjectTypeEXT    objectType;
-    uint64_t                      object;
-    uint64_t                      tagName;
-    size_t                        tagSize;
-    const void*                   pTag;
-} VkDebugMarkerObjectTagInfoEXT;
-
-typedef struct VkDebugMarkerMarkerInfoEXT {
-    VkStructureType    sType;
-    const void*        pNext;
-    const char*        pMarkerName;
-    float              color[4];
-} VkDebugMarkerMarkerInfoEXT;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, VkDebugMarkerObjectTagInfoEXT* pTagInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, VkDebugMarkerObjectNameInfoEXT* pNameInfo);
-typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
-typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer);
-typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT(
-    VkDevice                                    device,
-    VkDebugMarkerObjectTagInfoEXT*              pTagInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT(
-    VkDevice                                    device,
-    VkDebugMarkerObjectNameInfoEXT*             pNameInfo);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT(
-    VkCommandBuffer                             commandBuffer,
-    VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT(
-    VkCommandBuffer                             commandBuffer);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT(
-    VkCommandBuffer                             commandBuffer,
-    VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo);
-#endif
-
-#define VK_AMD_gcn_shader 1
-#define VK_AMD_GCN_SHADER_SPEC_VERSION    1
-#define VK_AMD_GCN_SHADER_EXTENSION_NAME  "VK_AMD_gcn_shader"
-
-
-#define VK_NV_dedicated_allocation 1
-#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
-#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
-
-typedef struct VkDedicatedAllocationImageCreateInfoNV {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkBool32           dedicatedAllocation;
-} VkDedicatedAllocationImageCreateInfoNV;
-
-typedef struct VkDedicatedAllocationBufferCreateInfoNV {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkBool32           dedicatedAllocation;
-} VkDedicatedAllocationBufferCreateInfoNV;
-
-typedef struct VkDedicatedAllocationMemoryAllocateInfoNV {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkImage            image;
-    VkBuffer           buffer;
-} VkDedicatedAllocationMemoryAllocateInfoNV;
-
-
-
-#define VK_AMD_draw_indirect_count 1
-#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
-#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
-
-typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
-typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset,
-    VkBuffer                                    countBuffer,
-    VkDeviceSize                                countBufferOffset,
-    uint32_t                                    maxDrawCount,
-    uint32_t                                    stride);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    buffer,
-    VkDeviceSize                                offset,
-    VkBuffer                                    countBuffer,
-    VkDeviceSize                                countBufferOffset,
-    uint32_t                                    maxDrawCount,
-    uint32_t                                    stride);
-#endif
-
-#define VK_AMD_negative_viewport_height 1
-#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
-#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
-
-
-#define VK_AMD_gpu_shader_half_float 1
-#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
-#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
-
-
-#define VK_AMD_shader_ballot 1
-#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
-#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
-
-
-#define VK_AMD_texture_gather_bias_lod 1
-#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
-#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
-
-typedef struct VkTextureLODGatherFormatPropertiesAMD {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           supportsTextureGatherLODBiasAMD;
-} VkTextureLODGatherFormatPropertiesAMD;
-
-
-
-#define VK_KHX_multiview 1
-#define VK_KHX_MULTIVIEW_SPEC_VERSION     1
-#define VK_KHX_MULTIVIEW_EXTENSION_NAME   "VK_KHX_multiview"
-
-typedef struct VkRenderPassMultiviewCreateInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           subpassCount;
-    const uint32_t*    pViewMasks;
-    uint32_t           dependencyCount;
-    const int32_t*     pViewOffsets;
-    uint32_t           correlationMaskCount;
-    const uint32_t*    pCorrelationMasks;
-} VkRenderPassMultiviewCreateInfoKHX;
-
-typedef struct VkPhysicalDeviceMultiviewFeaturesKHX {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           multiview;
-    VkBool32           multiviewGeometryShader;
-    VkBool32           multiviewTessellationShader;
-} VkPhysicalDeviceMultiviewFeaturesKHX;
-
-typedef struct VkPhysicalDeviceMultiviewPropertiesKHX {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           maxMultiviewViewCount;
-    uint32_t           maxMultiviewInstanceIndex;
-} VkPhysicalDeviceMultiviewPropertiesKHX;
-
-
-
-#define VK_IMG_format_pvrtc 1
-#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION  1
-#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
-
-
-#define VK_NV_external_memory_capabilities 1
-#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
-
-
-typedef enum VkExternalMemoryHandleTypeFlagBitsNV {
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
-    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
-} VkExternalMemoryHandleTypeFlagBitsNV;
-typedef VkFlags VkExternalMemoryHandleTypeFlagsNV;
-
-typedef enum VkExternalMemoryFeatureFlagBitsNV {
-    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
-    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
-    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
-    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
-} VkExternalMemoryFeatureFlagBitsNV;
-typedef VkFlags VkExternalMemoryFeatureFlagsNV;
-
-typedef struct VkExternalImageFormatPropertiesNV {
-    VkImageFormatProperties              imageFormatProperties;
-    VkExternalMemoryFeatureFlagsNV       externalMemoryFeatures;
-    VkExternalMemoryHandleTypeFlagsNV    exportFromImportedHandleTypes;
-    VkExternalMemoryHandleTypeFlagsNV    compatibleHandleTypes;
-} VkExternalImageFormatPropertiesNV;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
-    VkPhysicalDevice                            physicalDevice,
-    VkFormat                                    format,
-    VkImageType                                 type,
-    VkImageTiling                               tiling,
-    VkImageUsageFlags                           usage,
-    VkImageCreateFlags                          flags,
-    VkExternalMemoryHandleTypeFlagsNV           externalHandleType,
-    VkExternalImageFormatPropertiesNV*          pExternalImageFormatProperties);
-#endif
-
-#define VK_NV_external_memory 1
-#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
-#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
-
-typedef struct VkExternalMemoryImageCreateInfoNV {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkExternalMemoryHandleTypeFlagsNV    handleTypes;
-} VkExternalMemoryImageCreateInfoNV;
-
-typedef struct VkExportMemoryAllocateInfoNV {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkExternalMemoryHandleTypeFlagsNV    handleTypes;
-} VkExportMemoryAllocateInfoNV;
-
-
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_NV_external_memory_win32 1
-#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
-
-typedef struct VkImportMemoryWin32HandleInfoNV {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkExternalMemoryHandleTypeFlagsNV    handleType;
-    HANDLE                               handle;
-} VkImportMemoryWin32HandleInfoNV;
-
-typedef struct VkExportMemoryWin32HandleInfoNV {
-    VkStructureType               sType;
-    const void*                   pNext;
-    const SECURITY_ATTRIBUTES*    pAttributes;
-    DWORD                         dwAccess;
-} VkExportMemoryWin32HandleInfoNV;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV(
-    VkDevice                                    device,
-    VkDeviceMemory                              memory,
-    VkExternalMemoryHandleTypeFlagsNV           handleType,
-    HANDLE*                                     pHandle);
-#endif
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-#define VK_NV_win32_keyed_mutex 1
-#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
-
-typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV {
-    VkStructureType          sType;
-    const void*              pNext;
-    uint32_t                 acquireCount;
-    const VkDeviceMemory*    pAcquireSyncs;
-    const uint64_t*          pAcquireKeys;
-    const uint32_t*          pAcquireTimeoutMilliseconds;
-    uint32_t                 releaseCount;
-    const VkDeviceMemory*    pReleaseSyncs;
-    const uint64_t*          pReleaseKeys;
-} VkWin32KeyedMutexAcquireReleaseInfoNV;
-
-
-#endif /* VK_USE_PLATFORM_WIN32_KHR */
-
-#define VK_KHX_device_group 1
-#define VK_MAX_DEVICE_GROUP_SIZE_KHX      32
-#define VK_KHX_DEVICE_GROUP_SPEC_VERSION  1
-#define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
-
-
-typedef enum VkPeerMemoryFeatureFlagBitsKHX {
-    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,
-    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,
-    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,
-    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,
-    VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkPeerMemoryFeatureFlagBitsKHX;
-typedef VkFlags VkPeerMemoryFeatureFlagsKHX;
-
-typedef enum VkMemoryAllocateFlagBitsKHX {
-    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,
-    VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkMemoryAllocateFlagBitsKHX;
-typedef VkFlags VkMemoryAllocateFlagsKHX;
-
-typedef enum VkDeviceGroupPresentModeFlagBitsKHX {
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,
-    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,
-    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,
-    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
-    VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
-} VkDeviceGroupPresentModeFlagBitsKHX;
-typedef VkFlags VkDeviceGroupPresentModeFlagsKHX;
-
-typedef struct VkMemoryAllocateFlagsInfoKHX {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkMemoryAllocateFlagsKHX    flags;
-    uint32_t                    deviceMask;
-} VkMemoryAllocateFlagsInfoKHX;
-
-typedef struct VkBindBufferMemoryInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkBuffer           buffer;
-    VkDeviceMemory     memory;
-    VkDeviceSize       memoryOffset;
-    uint32_t           deviceIndexCount;
-    const uint32_t*    pDeviceIndices;
-} VkBindBufferMemoryInfoKHX;
-
-typedef struct VkBindImageMemoryInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkImage            image;
-    VkDeviceMemory     memory;
-    VkDeviceSize       memoryOffset;
-    uint32_t           deviceIndexCount;
-    const uint32_t*    pDeviceIndices;
-    uint32_t           SFRRectCount;
-    const VkRect2D*    pSFRRects;
-} VkBindImageMemoryInfoKHX;
-
-typedef struct VkDeviceGroupRenderPassBeginInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           deviceMask;
-    uint32_t           deviceRenderAreaCount;
-    const VkRect2D*    pDeviceRenderAreas;
-} VkDeviceGroupRenderPassBeginInfoKHX;
-
-typedef struct VkDeviceGroupCommandBufferBeginInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           deviceMask;
-} VkDeviceGroupCommandBufferBeginInfoKHX;
-
-typedef struct VkDeviceGroupSubmitInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           waitSemaphoreCount;
-    const uint32_t*    pWaitSemaphoreDeviceIndices;
-    uint32_t           commandBufferCount;
-    const uint32_t*    pCommandBufferDeviceMasks;
-    uint32_t           signalSemaphoreCount;
-    const uint32_t*    pSignalSemaphoreDeviceIndices;
-} VkDeviceGroupSubmitInfoKHX;
-
-typedef struct VkDeviceGroupBindSparseInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           resourceDeviceIndex;
-    uint32_t           memoryDeviceIndex;
-} VkDeviceGroupBindSparseInfoKHX;
-
-typedef struct VkDeviceGroupPresentCapabilitiesKHX {
-    VkStructureType                     sType;
-    const void*                         pNext;
-    uint32_t                            presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX];
-    VkDeviceGroupPresentModeFlagsKHX    modes;
-} VkDeviceGroupPresentCapabilitiesKHX;
-
-typedef struct VkImageSwapchainCreateInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkSwapchainKHR     swapchain;
-} VkImageSwapchainCreateInfoKHX;
-
-typedef struct VkBindImageMemorySwapchainInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkSwapchainKHR     swapchain;
-    uint32_t           imageIndex;
-} VkBindImageMemorySwapchainInfoKHX;
-
-typedef struct VkAcquireNextImageInfoKHX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkSwapchainKHR     swapchain;
-    uint64_t           timeout;
-    VkSemaphore        semaphore;
-    VkFence            fence;
-    uint32_t           deviceMask;
-} VkAcquireNextImageInfoKHX;
-
-typedef struct VkDeviceGroupPresentInfoKHX {
-    VkStructureType                        sType;
-    const void*                            pNext;
-    uint32_t                               swapchainCount;
-    const uint32_t*                        pDeviceMasks;
-    VkDeviceGroupPresentModeFlagBitsKHX    mode;
-} VkDeviceGroupPresentInfoKHX;
-
-typedef struct VkDeviceGroupSwapchainCreateInfoKHX {
-    VkStructureType                     sType;
-    const void*                         pNext;
-    VkDeviceGroupPresentModeFlagsKHX    modes;
-} VkDeviceGroupSwapchainCreateInfoKHX;
-
-
-typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);
-typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHX* pBindInfos);
-typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHX)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHX)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHX)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHX* pModes);
-typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHX)(VkDevice device, const VkAcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex);
-typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHX)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHX)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHX(
-    VkDevice                                    device,
-    uint32_t                                    heapIndex,
-    uint32_t                                    localDeviceIndex,
-    uint32_t                                    remoteDeviceIndex,
-    VkPeerMemoryFeatureFlagsKHX*                pPeerMemoryFeatures);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHX(
-    VkDevice                                    device,
-    uint32_t                                    bindInfoCount,
-    const VkBindBufferMemoryInfoKHX*            pBindInfos);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHX(
-    VkDevice                                    device,
-    uint32_t                                    bindInfoCount,
-    const VkBindImageMemoryInfoKHX*             pBindInfos);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHX(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    deviceMask);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHX(
-    VkDevice                                    device,
-    VkDeviceGroupPresentCapabilitiesKHX*        pDeviceGroupPresentCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX(
-    VkDevice                                    device,
-    VkSurfaceKHR                                surface,
-    VkDeviceGroupPresentModeFlagsKHX*           pModes);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHX(
-    VkDevice                                    device,
-    const VkAcquireNextImageInfoKHX*            pAcquireInfo,
-    uint32_t*                                   pImageIndex);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHX(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    baseGroupX,
-    uint32_t                                    baseGroupY,
-    uint32_t                                    baseGroupZ,
-    uint32_t                                    groupCountX,
-    uint32_t                                    groupCountY,
-    uint32_t                                    groupCountZ);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX(
-    VkPhysicalDevice                            physicalDevice,
-    VkSurfaceKHR                                surface,
-    uint32_t*                                   pRectCount,
-    VkRect2D*                                   pRects);
-#endif
-
-#define VK_EXT_validation_flags 1
-#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
-#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
-
-
-typedef enum VkValidationCheckEXT {
-    VK_VALIDATION_CHECK_ALL_EXT = 0,
-    VK_VALIDATION_CHECK_SHADERS_EXT = 1,
-    VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
-    VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT,
-    VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),
-    VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkValidationCheckEXT;
-
-typedef struct VkValidationFlagsEXT {
-    VkStructureType          sType;
-    const void*              pNext;
-    uint32_t                 disabledValidationCheckCount;
-    VkValidationCheckEXT*    pDisabledValidationChecks;
-} VkValidationFlagsEXT;
-
 
 
 #ifdef VK_USE_PLATFORM_VI_NN
-#define VK_NN_vi_surface 1
-#define VK_NN_VI_SURFACE_SPEC_VERSION     1
-#define VK_NN_VI_SURFACE_EXTENSION_NAME   "VK_NN_vi_surface"
-
-typedef VkFlags VkViSurfaceCreateFlagsNN;
-
-typedef struct VkViSurfaceCreateInfoNN {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkViSurfaceCreateFlagsNN    flags;
-    void*                       window;
-} VkViSurfaceCreateInfoNN;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
-    VkInstance                                  instance,
-    const VkViSurfaceCreateInfoNN*              pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-#endif
-#endif /* VK_USE_PLATFORM_VI_NN */
-
-#define VK_EXT_shader_subgroup_ballot 1
-#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
-#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
-
-
-#define VK_EXT_shader_subgroup_vote 1
-#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
-#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
-
-
-#define VK_KHX_device_group_creation 1
-#define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
-#define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
-
-typedef struct VkPhysicalDeviceGroupPropertiesKHX {
-    VkStructureType     sType;
-    void*               pNext;
-    uint32_t            physicalDeviceCount;
-    VkPhysicalDevice    physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];
-    VkBool32            subsetAllocation;
-} VkPhysicalDeviceGroupPropertiesKHX;
-
-typedef struct VkDeviceGroupDeviceCreateInfoKHX {
-    VkStructureType            sType;
-    const void*                pNext;
-    uint32_t                   physicalDeviceCount;
-    const VkPhysicalDevice*    pPhysicalDevices;
-} VkDeviceGroupDeviceCreateInfoKHX;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHX)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHX(
-    VkInstance                                  instance,
-    uint32_t*                                   pPhysicalDeviceGroupCount,
-    VkPhysicalDeviceGroupPropertiesKHX*         pPhysicalDeviceGroupProperties);
+#include "vulkan_vi.h"
 #endif
 
-#define VK_NVX_device_generated_commands 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
 
-#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
-#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
-
-
-typedef enum VkIndirectCommandsTokenTypeNVX {
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX,
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1),
-    VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkIndirectCommandsTokenTypeNVX;
-
-typedef enum VkObjectEntryTypeNVX {
-    VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
-    VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
-    VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
-    VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
-    VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
-    VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX,
-    VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX,
-    VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1),
-    VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkObjectEntryTypeNVX;
-
-
-typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX {
-    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
-    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
-    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
-    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
-    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkIndirectCommandsLayoutUsageFlagBitsNVX;
-typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX;
-
-typedef enum VkObjectEntryUsageFlagBitsNVX {
-    VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
-    VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
-    VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkObjectEntryUsageFlagBitsNVX;
-typedef VkFlags VkObjectEntryUsageFlagsNVX;
-
-typedef struct VkDeviceGeneratedCommandsFeaturesNVX {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkBool32           computeBindingPointSupport;
-} VkDeviceGeneratedCommandsFeaturesNVX;
-
-typedef struct VkDeviceGeneratedCommandsLimitsNVX {
-    VkStructureType    sType;
-    const void*        pNext;
-    uint32_t           maxIndirectCommandsLayoutTokenCount;
-    uint32_t           maxObjectEntryCounts;
-    uint32_t           minSequenceCountBufferOffsetAlignment;
-    uint32_t           minSequenceIndexBufferOffsetAlignment;
-    uint32_t           minCommandsTokenBufferOffsetAlignment;
-} VkDeviceGeneratedCommandsLimitsNVX;
-
-typedef struct VkIndirectCommandsTokenNVX {
-    VkIndirectCommandsTokenTypeNVX    tokenType;
-    VkBuffer                          buffer;
-    VkDeviceSize                      offset;
-} VkIndirectCommandsTokenNVX;
-
-typedef struct VkIndirectCommandsLayoutTokenNVX {
-    VkIndirectCommandsTokenTypeNVX    tokenType;
-    uint32_t                          bindingUnit;
-    uint32_t                          dynamicCount;
-    uint32_t                          divisor;
-} VkIndirectCommandsLayoutTokenNVX;
-
-typedef struct VkIndirectCommandsLayoutCreateInfoNVX {
-    VkStructureType                            sType;
-    const void*                                pNext;
-    VkPipelineBindPoint                        pipelineBindPoint;
-    VkIndirectCommandsLayoutUsageFlagsNVX      flags;
-    uint32_t                                   tokenCount;
-    const VkIndirectCommandsLayoutTokenNVX*    pTokens;
-} VkIndirectCommandsLayoutCreateInfoNVX;
-
-typedef struct VkCmdProcessCommandsInfoNVX {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    VkObjectTableNVX                     objectTable;
-    VkIndirectCommandsLayoutNVX          indirectCommandsLayout;
-    uint32_t                             indirectCommandsTokenCount;
-    const VkIndirectCommandsTokenNVX*    pIndirectCommandsTokens;
-    uint32_t                             maxSequencesCount;
-    VkCommandBuffer                      targetCommandBuffer;
-    VkBuffer                             sequencesCountBuffer;
-    VkDeviceSize                         sequencesCountOffset;
-    VkBuffer                             sequencesIndexBuffer;
-    VkDeviceSize                         sequencesIndexOffset;
-} VkCmdProcessCommandsInfoNVX;
-
-typedef struct VkCmdReserveSpaceForCommandsInfoNVX {
-    VkStructureType                sType;
-    const void*                    pNext;
-    VkObjectTableNVX               objectTable;
-    VkIndirectCommandsLayoutNVX    indirectCommandsLayout;
-    uint32_t                       maxSequencesCount;
-} VkCmdReserveSpaceForCommandsInfoNVX;
-
-typedef struct VkObjectTableCreateInfoNVX {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    uint32_t                             objectCount;
-    const VkObjectEntryTypeNVX*          pObjectEntryTypes;
-    const uint32_t*                      pObjectEntryCounts;
-    const VkObjectEntryUsageFlagsNVX*    pObjectEntryUsageFlags;
-    uint32_t                             maxUniformBuffersPerDescriptor;
-    uint32_t                             maxStorageBuffersPerDescriptor;
-    uint32_t                             maxStorageImagesPerDescriptor;
-    uint32_t                             maxSampledImagesPerDescriptor;
-    uint32_t                             maxPipelineLayouts;
-} VkObjectTableCreateInfoNVX;
-
-typedef struct VkObjectTableEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-} VkObjectTableEntryNVX;
-
-typedef struct VkObjectTablePipelineEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-    VkPipeline                    pipeline;
-} VkObjectTablePipelineEntryNVX;
-
-typedef struct VkObjectTableDescriptorSetEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-    VkPipelineLayout              pipelineLayout;
-    VkDescriptorSet               descriptorSet;
-} VkObjectTableDescriptorSetEntryNVX;
-
-typedef struct VkObjectTableVertexBufferEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-    VkBuffer                      buffer;
-} VkObjectTableVertexBufferEntryNVX;
-
-typedef struct VkObjectTableIndexBufferEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-    VkBuffer                      buffer;
-    VkIndexType                   indexType;
-} VkObjectTableIndexBufferEntryNVX;
-
-typedef struct VkObjectTablePushConstantEntryNVX {
-    VkObjectEntryTypeNVX          type;
-    VkObjectEntryUsageFlagsNVX    flags;
-    VkPipelineLayout              pipelineLayout;
-    VkShaderStageFlags            stageFlags;
-} VkObjectTablePushConstantEntryNVX;
-
-
-typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);
-typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);
-typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable);
-typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator);
-typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const*    ppObjectTableEntries, const uint32_t* pObjectIndices);
-typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices);
-typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX(
-    VkCommandBuffer                             commandBuffer,
-    const VkCmdProcessCommandsInfoNVX*          pProcessCommandsInfo);
-
-VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX(
-    VkCommandBuffer                             commandBuffer,
-    const VkCmdReserveSpaceForCommandsInfoNVX*  pReserveSpaceInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX(
-    VkDevice                                    device,
-    const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkIndirectCommandsLayoutNVX*                pIndirectCommandsLayout);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX(
-    VkDevice                                    device,
-    VkIndirectCommandsLayoutNVX                 indirectCommandsLayout,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX(
-    VkDevice                                    device,
-    const VkObjectTableCreateInfoNVX*           pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkObjectTableNVX*                           pObjectTable);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX(
-    VkDevice                                    device,
-    VkObjectTableNVX                            objectTable,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX(
-    VkDevice                                    device,
-    VkObjectTableNVX                            objectTable,
-    uint32_t                                    objectCount,
-    const VkObjectTableEntryNVX* const*         ppObjectTableEntries,
-    const uint32_t*                             pObjectIndices);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX(
-    VkDevice                                    device,
-    VkObjectTableNVX                            objectTable,
-    uint32_t                                    objectCount,
-    const VkObjectEntryTypeNVX*                 pObjectEntryTypes,
-    const uint32_t*                             pObjectIndices);
-
-VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
-    VkPhysicalDevice                            physicalDevice,
-    VkDeviceGeneratedCommandsFeaturesNVX*       pFeatures,
-    VkDeviceGeneratedCommandsLimitsNVX*         pLimits);
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+#include <wayland-client.h>
+#include "vulkan_wayland.h"
 #endif
 
-#define VK_NV_clip_space_w_scaling 1
-#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1
-#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling"
 
-typedef struct VkViewportWScalingNV {
-    float    xcoeff;
-    float    ycoeff;
-} VkViewportWScalingNV;
-
-typedef struct VkPipelineViewportWScalingStateCreateInfoNV {
-    VkStructureType                sType;
-    const void*                    pNext;
-    VkBool32                       viewportWScalingEnable;
-    uint32_t                       viewportCount;
-    const VkViewportWScalingNV*    pViewportWScalings;
-} VkPipelineViewportWScalingStateCreateInfoNV;
-
-
-typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    firstViewport,
-    uint32_t                                    viewportCount,
-    const VkViewportWScalingNV*                 pViewportWScalings);
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#include <windows.h>
+#include "vulkan_win32.h"
 #endif
 
-#define VK_EXT_direct_mode_display 1
-#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
-#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
 
-typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT(
-    VkPhysicalDevice                            physicalDevice,
-    VkDisplayKHR                                display);
+#ifdef VK_USE_PLATFORM_XCB_KHR
+#include <xcb/xcb.h>
+#include "vulkan_xcb.h"
 #endif
 
+
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+#include <X11/Xlib.h>
+#include "vulkan_xlib.h"
+#endif
+
+
 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
-#define VK_EXT_acquire_xlib_display 1
+#include <X11/Xlib.h>
 #include <X11/extensions/Xrandr.h>
-
-#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
-#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
-
-typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);
-typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
-    VkPhysicalDevice                            physicalDevice,
-    Display*                                    dpy,
-    VkDisplayKHR                                display);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(
-    VkPhysicalDevice                            physicalDevice,
-    Display*                                    dpy,
-    RROutput                                    rrOutput,
-    VkDisplayKHR*                               pDisplay);
-#endif
-#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
-
-#define VK_EXT_display_surface_counter 1
-#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
-#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
-
-
-typedef enum VkSurfaceCounterFlagBitsEXT {
-    VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
-    VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkSurfaceCounterFlagBitsEXT;
-typedef VkFlags VkSurfaceCounterFlagsEXT;
-
-typedef struct VkSurfaceCapabilities2EXT {
-    VkStructureType                  sType;
-    void*                            pNext;
-    uint32_t                         minImageCount;
-    uint32_t                         maxImageCount;
-    VkExtent2D                       currentExtent;
-    VkExtent2D                       minImageExtent;
-    VkExtent2D                       maxImageExtent;
-    uint32_t                         maxImageArrayLayers;
-    VkSurfaceTransformFlagsKHR       supportedTransforms;
-    VkSurfaceTransformFlagBitsKHR    currentTransform;
-    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;
-    VkImageUsageFlags                supportedUsageFlags;
-    VkSurfaceCounterFlagsEXT         supportedSurfaceCounters;
-} VkSurfaceCapabilities2EXT;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
-    VkPhysicalDevice                            physicalDevice,
-    VkSurfaceKHR                                surface,
-    VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities);
+#include "vulkan_xlib_xrandr.h"
 #endif
 
-#define VK_EXT_display_control 1
-#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
-#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control"
-
-
-typedef enum VkDisplayPowerStateEXT {
-    VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
-    VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
-    VK_DISPLAY_POWER_STATE_ON_EXT = 2,
-    VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT,
-    VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT,
-    VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1),
-    VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDisplayPowerStateEXT;
-
-typedef enum VkDeviceEventTypeEXT {
-    VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
-    VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
-    VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
-    VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1),
-    VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDeviceEventTypeEXT;
-
-typedef enum VkDisplayEventTypeEXT {
-    VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
-    VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
-    VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
-    VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1),
-    VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDisplayEventTypeEXT;
-
-typedef struct VkDisplayPowerInfoEXT {
-    VkStructureType           sType;
-    const void*               pNext;
-    VkDisplayPowerStateEXT    powerState;
-} VkDisplayPowerInfoEXT;
-
-typedef struct VkDeviceEventInfoEXT {
-    VkStructureType         sType;
-    const void*             pNext;
-    VkDeviceEventTypeEXT    deviceEvent;
-} VkDeviceEventInfoEXT;
-
-typedef struct VkDisplayEventInfoEXT {
-    VkStructureType          sType;
-    const void*              pNext;
-    VkDisplayEventTypeEXT    displayEvent;
-} VkDisplayEventInfoEXT;
-
-typedef struct VkSwapchainCounterCreateInfoEXT {
-    VkStructureType             sType;
-    const void*                 pNext;
-    VkSurfaceCounterFlagsEXT    surfaceCounters;
-} VkSwapchainCounterCreateInfoEXT;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo);
-typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
-typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT(
-    VkDevice                                    device,
-    VkDisplayKHR                                display,
-    const VkDisplayPowerInfoEXT*                pDisplayPowerInfo);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT(
-    VkDevice                                    device,
-    const VkDeviceEventInfoEXT*                 pDeviceEventInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkFence*                                    pFence);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT(
-    VkDevice                                    device,
-    VkDisplayKHR                                display,
-    const VkDisplayEventInfoEXT*                pDisplayEventInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkFence*                                    pFence);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    VkSurfaceCounterFlagBitsEXT                 counter,
-    uint64_t*                                   pCounterValue);
-#endif
-
-#define VK_GOOGLE_display_timing 1
-#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
-#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
-
-typedef struct VkRefreshCycleDurationGOOGLE {
-    uint64_t    refreshDuration;
-} VkRefreshCycleDurationGOOGLE;
-
-typedef struct VkPastPresentationTimingGOOGLE {
-    uint32_t    presentID;
-    uint64_t    desiredPresentTime;
-    uint64_t    actualPresentTime;
-    uint64_t    earliestPresentTime;
-    uint64_t    presentMargin;
-} VkPastPresentationTimingGOOGLE;
-
-typedef struct VkPresentTimeGOOGLE {
-    uint32_t    presentID;
-    uint64_t    desiredPresentTime;
-} VkPresentTimeGOOGLE;
-
-typedef struct VkPresentTimesInfoGOOGLE {
-    VkStructureType               sType;
-    const void*                   pNext;
-    uint32_t                      swapchainCount;
-    const VkPresentTimeGOOGLE*    pTimes;
-} VkPresentTimesInfoGOOGLE;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    VkRefreshCycleDurationGOOGLE*               pDisplayTimingProperties);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain,
-    uint32_t*                                   pPresentationTimingCount,
-    VkPastPresentationTimingGOOGLE*             pPresentationTimings);
-#endif
-
-#define VK_NV_sample_mask_override_coverage 1
-#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1
-#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage"
-
-
-#define VK_NV_geometry_shader_passthrough 1
-#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1
-#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough"
-
-
-#define VK_NV_viewport_array2 1
-#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1
-#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2"
-
-
-#define VK_NVX_multiview_per_view_attributes 1
-#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1
-#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes"
-
-typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           perViewPositionAllComponents;
-} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX;
-
-
-
-#define VK_NV_viewport_swizzle 1
-#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1
-#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle"
-
-
-typedef enum VkViewportCoordinateSwizzleNV {
-    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV,
-    VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1),
-    VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF
-} VkViewportCoordinateSwizzleNV;
-
-typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;
-
-typedef struct VkViewportSwizzleNV {
-    VkViewportCoordinateSwizzleNV    x;
-    VkViewportCoordinateSwizzleNV    y;
-    VkViewportCoordinateSwizzleNV    z;
-    VkViewportCoordinateSwizzleNV    w;
-} VkViewportSwizzleNV;
-
-typedef struct VkPipelineViewportSwizzleStateCreateInfoNV {
-    VkStructureType                                sType;
-    const void*                                    pNext;
-    VkPipelineViewportSwizzleStateCreateFlagsNV    flags;
-    uint32_t                                       viewportCount;
-    const VkViewportSwizzleNV*                     pViewportSwizzles;
-} VkPipelineViewportSwizzleStateCreateInfoNV;
-
-
-
-#define VK_EXT_discard_rectangles 1
-#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
-#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
-
-
-typedef enum VkDiscardRectangleModeEXT {
-    VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,
-    VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
-    VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT,
-    VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT,
-    VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1),
-    VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkDiscardRectangleModeEXT;
-
-typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT;
-
-typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           maxDiscardRectangles;
-} VkPhysicalDeviceDiscardRectanglePropertiesEXT;
-
-typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT {
-    VkStructureType                                  sType;
-    const void*                                      pNext;
-    VkPipelineDiscardRectangleStateCreateFlagsEXT    flags;
-    VkDiscardRectangleModeEXT                        discardRectangleMode;
-    uint32_t                                         discardRectangleCount;
-    const VkRect2D*                                  pDiscardRectangles;
-} VkPipelineDiscardRectangleStateCreateInfoEXT;
-
-
-typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT(
-    VkCommandBuffer                             commandBuffer,
-    uint32_t                                    firstDiscardRectangle,
-    uint32_t                                    discardRectangleCount,
-    const VkRect2D*                             pDiscardRectangles);
-#endif
-
-#define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
-
-
-#define VK_EXT_hdr_metadata 1
-#define VK_EXT_HDR_METADATA_SPEC_VERSION  1
-#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
-
-typedef struct VkXYColorEXT {
-    float    x;
-    float    y;
-} VkXYColorEXT;
-
-typedef struct VkHdrMetadataEXT {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkXYColorEXT       displayPrimaryRed;
-    VkXYColorEXT       displayPrimaryGreen;
-    VkXYColorEXT       displayPrimaryBlue;
-    VkXYColorEXT       whitePoint;
-    float              maxLuminance;
-    float              minLuminance;
-    float              maxContentLightLevel;
-    float              maxFrameAverageLightLevel;
-} VkHdrMetadataEXT;
-
-
-typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT(
-    VkDevice                                    device,
-    uint32_t                                    swapchainCount,
-    const VkSwapchainKHR*                       pSwapchains,
-    const VkHdrMetadataEXT*                     pMetadata);
-#endif
-
-#ifdef VK_USE_PLATFORM_IOS_MVK
-#define VK_MVK_ios_surface 1
-#define VK_MVK_IOS_SURFACE_SPEC_VERSION   2
-#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
-
-typedef VkFlags VkIOSSurfaceCreateFlagsMVK;
-
-typedef struct VkIOSSurfaceCreateInfoMVK {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkIOSSurfaceCreateFlagsMVK    flags;
-    const void*                   pView;
-} VkIOSSurfaceCreateInfoMVK;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(
-    VkInstance                                  instance,
-    const VkIOSSurfaceCreateInfoMVK*            pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-#endif
-#endif /* VK_USE_PLATFORM_IOS_MVK */
-
-#ifdef VK_USE_PLATFORM_MACOS_MVK
-#define VK_MVK_macos_surface 1
-#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2
-#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
-
-typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
-
-typedef struct VkMacOSSurfaceCreateInfoMVK {
-    VkStructureType                 sType;
-    const void*                     pNext;
-    VkMacOSSurfaceCreateFlagsMVK    flags;
-    const void*                     pView;
-} VkMacOSSurfaceCreateInfoMVK;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
-    VkInstance                                  instance,
-    const VkMacOSSurfaceCreateInfoMVK*          pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkSurfaceKHR*                               pSurface);
-#endif
-#endif /* VK_USE_PLATFORM_MACOS_MVK */
-
-#define VK_EXT_sampler_filter_minmax 1
-#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
-#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
-
-
-typedef enum VkSamplerReductionModeEXT {
-    VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0,
-    VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1,
-    VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2,
-    VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT,
-    VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT,
-    VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1),
-    VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkSamplerReductionModeEXT;
-
-typedef struct VkSamplerReductionModeCreateInfoEXT {
-    VkStructureType              sType;
-    const void*                  pNext;
-    VkSamplerReductionModeEXT    reductionMode;
-} VkSamplerReductionModeCreateInfoEXT;
-
-typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           filterMinmaxSingleComponentFormats;
-    VkBool32           filterMinmaxImageComponentMapping;
-} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT;
-
-
-
-#define VK_AMD_gpu_shader_int16 1
-#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
-#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
-
-
-#define VK_EXT_blend_operation_advanced 1
-#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
-#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
-
-
-typedef enum VkBlendOverlapEXT {
-    VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0,
-    VK_BLEND_OVERLAP_DISJOINT_EXT = 1,
-    VK_BLEND_OVERLAP_CONJOINT_EXT = 2,
-    VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT,
-    VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT,
-    VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1),
-    VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF
-} VkBlendOverlapEXT;
-
-typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           advancedBlendCoherentOperations;
-} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT;
-
-typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT {
-    VkStructureType    sType;
-    void*              pNext;
-    uint32_t           advancedBlendMaxColorAttachments;
-    VkBool32           advancedBlendIndependentBlend;
-    VkBool32           advancedBlendNonPremultipliedSrcColor;
-    VkBool32           advancedBlendNonPremultipliedDstColor;
-    VkBool32           advancedBlendCorrelatedOverlap;
-    VkBool32           advancedBlendAllOperations;
-} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT;
-
-typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT {
-    VkStructureType      sType;
-    const void*          pNext;
-    VkBool32             srcPremultiplied;
-    VkBool32             dstPremultiplied;
-    VkBlendOverlapEXT    blendOverlap;
-} VkPipelineColorBlendAdvancedStateCreateInfoEXT;
-
-
-
-#define VK_NV_fragment_coverage_to_color 1
-#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1
-#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color"
-
-typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV;
-
-typedef struct VkPipelineCoverageToColorStateCreateInfoNV {
-    VkStructureType                                sType;
-    const void*                                    pNext;
-    VkPipelineCoverageToColorStateCreateFlagsNV    flags;
-    VkBool32                                       coverageToColorEnable;
-    uint32_t                                       coverageToColorLocation;
-} VkPipelineCoverageToColorStateCreateInfoNV;
-
-
-
-#define VK_NV_framebuffer_mixed_samples 1
-#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1
-#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples"
-
-
-typedef enum VkCoverageModulationModeNV {
-    VK_COVERAGE_MODULATION_MODE_NONE_NV = 0,
-    VK_COVERAGE_MODULATION_MODE_RGB_NV = 1,
-    VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2,
-    VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3,
-    VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV,
-    VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV,
-    VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1),
-    VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF
-} VkCoverageModulationModeNV;
-
-typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV;
-
-typedef struct VkPipelineCoverageModulationStateCreateInfoNV {
-    VkStructureType                                   sType;
-    const void*                                       pNext;
-    VkPipelineCoverageModulationStateCreateFlagsNV    flags;
-    VkCoverageModulationModeNV                        coverageModulationMode;
-    VkBool32                                          coverageModulationTableEnable;
-    uint32_t                                          coverageModulationTableCount;
-    const float*                                      pCoverageModulationTable;
-} VkPipelineCoverageModulationStateCreateInfoNV;
-
-
-
-#define VK_NV_fill_rectangle 1
-#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
-#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+#endif // VULKAN_H_
diff --git a/vulkan/include/vulkan/vulkan_android.h b/vulkan/include/vulkan/vulkan_android.h
new file mode 100644
index 0000000..42521d9
--- /dev/null
+++ b/vulkan/include/vulkan/vulkan_android.h
@@ -0,0 +1,126 @@
+#ifndef VULKAN_ANDROID_H_
+#define VULKAN_ANDROID_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2015-2018 The Khronos Group Inc.
+**
+** 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.
+*/
+
+/*
+** This header is generated from the Khronos Vulkan XML API Registry.
+**
+*/
+
+
+#define VK_KHR_android_surface 1
+struct ANativeWindow;
+
+#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
+#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface"
+
+typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
+
+typedef struct VkAndroidSurfaceCreateInfoKHR {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkAndroidSurfaceCreateFlagsKHR    flags;
+    struct ANativeWindow*             window;
+} VkAndroidSurfaceCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
+    VkInstance                                  instance,
+    const VkAndroidSurfaceCreateInfoKHR*        pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSurfaceKHR*                               pSurface);
+#endif
+
+#define VK_ANDROID_external_memory_android_hardware_buffer 1
+struct AHardwareBuffer;
+
+#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 2
+#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer"
+
+typedef struct VkAndroidHardwareBufferUsageANDROID {
+    VkStructureType    sType;
+    void*              pNext;
+    uint64_t           androidHardwareBufferUsage;
+} VkAndroidHardwareBufferUsageANDROID;
+
+typedef struct VkAndroidHardwareBufferPropertiesANDROID {
+    VkStructureType    sType;
+    void*              pNext;
+    VkDeviceSize       allocationSize;
+    uint32_t           memoryTypeBits;
+} VkAndroidHardwareBufferPropertiesANDROID;
+
+typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID {
+    VkStructureType                  sType;
+    void*                            pNext;
+    VkFormat                         format;
+    uint64_t                         externalFormat;
+    VkFormatFeatureFlags             formatFeatures;
+    VkComponentMapping               samplerYcbcrConversionComponents;
+    VkSamplerYcbcrModelConversion    suggestedYcbcrModel;
+    VkSamplerYcbcrRange              suggestedYcbcrRange;
+    VkChromaLocation                 suggestedXChromaOffset;
+    VkChromaLocation                 suggestedYChromaOffset;
+} VkAndroidHardwareBufferFormatPropertiesANDROID;
+
+typedef struct VkImportAndroidHardwareBufferInfoANDROID {
+    VkStructureType            sType;
+    const void*                pNext;
+    struct AHardwareBuffer*    buffer;
+} VkImportAndroidHardwareBufferInfoANDROID;
+
+typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkDeviceMemory     memory;
+} VkMemoryGetAndroidHardwareBufferInfoANDROID;
+
+typedef struct VkExternalFormatANDROID {
+    VkStructureType    sType;
+    void*              pNext;
+    uint64_t           externalFormat;
+} VkExternalFormatANDROID;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID(
+    VkDevice                                    device,
+    const struct AHardwareBuffer*               buffer,
+    VkAndroidHardwareBufferPropertiesANDROID*   pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID(
+    VkDevice                                    device,
+    const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
+    struct AHardwareBuffer**                    pBuffer);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
new file mode 100644
index 0000000..6e5ea80
--- /dev/null
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -0,0 +1,7300 @@
+#ifndef VULKAN_CORE_H_
+#define VULKAN_CORE_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2015-2018 The Khronos Group Inc.
+**
+** 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.
+*/
+
+/*
+** This header is generated from the Khronos Vulkan XML API Registry.
+**
+*/
+
+
+#define VK_VERSION_1_0 1
+#include "vk_platform.h"
+
+#define VK_MAKE_VERSION(major, minor, patch) \
+    (((major) << 22) | ((minor) << 12) | (patch))
+
+// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.
+//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0
+
+// Vulkan 1.0 version number
+#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)// Patch version should always be set to 0
+
+#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#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 68
+
+
+#define VK_NULL_HANDLE 0
+        
+
+
+#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
+
+
+#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
+#else
+        #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
+#endif
+#endif
+        
+
+
+typedef uint32_t VkFlags;
+typedef uint32_t VkBool32;
+typedef uint64_t VkDeviceSize;
+typedef uint32_t VkSampleMask;
+
+VK_DEFINE_HANDLE(VkInstance)
+VK_DEFINE_HANDLE(VkPhysicalDevice)
+VK_DEFINE_HANDLE(VkDevice)
+VK_DEFINE_HANDLE(VkQueue)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore)
+VK_DEFINE_HANDLE(VkCommandBuffer)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool)
+
+#define VK_LOD_CLAMP_NONE                 1000.0f
+#define VK_REMAINING_MIP_LEVELS           (~0U)
+#define VK_REMAINING_ARRAY_LAYERS         (~0U)
+#define VK_WHOLE_SIZE                     (~0ULL)
+#define VK_ATTACHMENT_UNUSED              (~0U)
+#define VK_TRUE                           1
+#define VK_FALSE                          0
+#define VK_QUEUE_FAMILY_IGNORED           (~0U)
+#define VK_SUBPASS_EXTERNAL               (~0U)
+#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE  256
+#define VK_UUID_SIZE                      16
+#define VK_MAX_MEMORY_TYPES               32
+#define VK_MAX_MEMORY_HEAPS               16
+#define VK_MAX_EXTENSION_NAME_SIZE        256
+#define VK_MAX_DESCRIPTION_SIZE           256
+
+
+typedef enum VkPipelineCacheHeaderVersion {
+    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
+    VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,
+    VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE,
+    VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1),
+    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineCacheHeaderVersion;
+
+typedef enum VkResult {
+    VK_SUCCESS = 0,
+    VK_NOT_READY = 1,
+    VK_TIMEOUT = 2,
+    VK_EVENT_SET = 3,
+    VK_EVENT_RESET = 4,
+    VK_INCOMPLETE = 5,
+    VK_ERROR_OUT_OF_HOST_MEMORY = -1,
+    VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
+    VK_ERROR_INITIALIZATION_FAILED = -3,
+    VK_ERROR_DEVICE_LOST = -4,
+    VK_ERROR_MEMORY_MAP_FAILED = -5,
+    VK_ERROR_LAYER_NOT_PRESENT = -6,
+    VK_ERROR_EXTENSION_NOT_PRESENT = -7,
+    VK_ERROR_FEATURE_NOT_PRESENT = -8,
+    VK_ERROR_INCOMPATIBLE_DRIVER = -9,
+    VK_ERROR_TOO_MANY_OBJECTS = -10,
+    VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
+    VK_ERROR_FRAGMENTED_POOL = -12,
+    VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000,
+    VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003,
+    VK_ERROR_SURFACE_LOST_KHR = -1000000000,
+    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
+    VK_SUBOPTIMAL_KHR = 1000001003,
+    VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
+    VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
+    VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
+    VK_ERROR_INVALID_SHADER_NV = -1000012000,
+    VK_ERROR_NOT_PERMITTED_EXT = -1000174001,
+    VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY,
+    VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE,
+    VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
+    VK_RESULT_END_RANGE = VK_INCOMPLETE,
+    VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
+    VK_RESULT_MAX_ENUM = 0x7FFFFFFF
+} VkResult;
+
+typedef enum VkStructureType {
+    VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
+    VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
+    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
+    VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
+    VK_STRUCTURE_TYPE_SUBMIT_INFO = 4,
+    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5,
+    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6,
+    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7,
+    VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8,
+    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9,
+    VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10,
+    VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11,
+    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12,
+    VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13,
+    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15,
+    VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16,
+    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17,
+    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18,
+    VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19,
+    VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,
+    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21,
+    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23,
+    VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24,
+    VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25,
+    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26,
+    VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27,
+    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28,
+    VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29,
+    VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30,
+    VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35,
+    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36,
+    VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37,
+    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38,
+    VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39,
+    VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40,
+    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41,
+    VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42,
+    VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43,
+    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44,
+    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45,
+    VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,
+    VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
+    VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001,
+    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001,
+    VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000,
+    VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001,
+    VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002,
+    VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001,
+    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002,
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002,
+    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
+    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000,
+    VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002,
+    VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002,
+    VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000,
+    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002,
+    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000,
+    VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001,
+    VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000,
+    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000,
+    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000,
+    VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
+    VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
+    VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009,
+    VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012,
+    VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
+    VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,
+    VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000,
+    VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
+    VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
+    VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
+    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
+    VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
+    VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
+    VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,
+    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
+    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
+    VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
+    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
+    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
+    VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+    VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
+    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
+    VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+    VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
+    VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
+    VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003,
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000,
+    VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001,
+    VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002,
+    VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000,
+    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000,
+    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001,
+    VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002,
+    VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003,
+    VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000,
+    VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
+    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,
+    VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
+    VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
+    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
+    VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
+    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000,
+    VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
+    VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
+    VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
+    VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
+    VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,
+    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
+    VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001,
+    VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
+    VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
+    VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000,
+    VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001,
+    VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002,
+    VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000,
+    VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
+    VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
+    VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
+    VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003,
+    VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004,
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000,
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001,
+    VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002,
+    VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003,
+    VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004,
+    VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
+    VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
+    VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001,
+    VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003,
+    VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004,
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
+    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
+    VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
+    VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+    VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
+    VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
+    VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000,
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000,
+    VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
+    VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2,
+    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES,
+    VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
+    VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO,
+    VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
+    VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
+    VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
+    VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO,
+    VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES,
+    VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES,
+    VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
+    VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
+    VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
+    VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
+    VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2,
+    VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
+    VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO,
+    VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
+    VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES,
+    VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,
+    VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT,
+    VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+    VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
+    VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkStructureType;
+
+typedef enum VkSystemAllocationScope {
+    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0,
+    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1,
+    VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2,
+    VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3,
+    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4,
+    VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND,
+    VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE,
+    VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1),
+    VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF
+} VkSystemAllocationScope;
+
+typedef enum VkInternalAllocationType {
+    VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0,
+    VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,
+    VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE,
+    VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1),
+    VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkInternalAllocationType;
+
+typedef enum VkFormat {
+    VK_FORMAT_UNDEFINED = 0,
+    VK_FORMAT_R4G4_UNORM_PACK8 = 1,
+    VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
+    VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
+    VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
+    VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
+    VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
+    VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
+    VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
+    VK_FORMAT_R8_UNORM = 9,
+    VK_FORMAT_R8_SNORM = 10,
+    VK_FORMAT_R8_USCALED = 11,
+    VK_FORMAT_R8_SSCALED = 12,
+    VK_FORMAT_R8_UINT = 13,
+    VK_FORMAT_R8_SINT = 14,
+    VK_FORMAT_R8_SRGB = 15,
+    VK_FORMAT_R8G8_UNORM = 16,
+    VK_FORMAT_R8G8_SNORM = 17,
+    VK_FORMAT_R8G8_USCALED = 18,
+    VK_FORMAT_R8G8_SSCALED = 19,
+    VK_FORMAT_R8G8_UINT = 20,
+    VK_FORMAT_R8G8_SINT = 21,
+    VK_FORMAT_R8G8_SRGB = 22,
+    VK_FORMAT_R8G8B8_UNORM = 23,
+    VK_FORMAT_R8G8B8_SNORM = 24,
+    VK_FORMAT_R8G8B8_USCALED = 25,
+    VK_FORMAT_R8G8B8_SSCALED = 26,
+    VK_FORMAT_R8G8B8_UINT = 27,
+    VK_FORMAT_R8G8B8_SINT = 28,
+    VK_FORMAT_R8G8B8_SRGB = 29,
+    VK_FORMAT_B8G8R8_UNORM = 30,
+    VK_FORMAT_B8G8R8_SNORM = 31,
+    VK_FORMAT_B8G8R8_USCALED = 32,
+    VK_FORMAT_B8G8R8_SSCALED = 33,
+    VK_FORMAT_B8G8R8_UINT = 34,
+    VK_FORMAT_B8G8R8_SINT = 35,
+    VK_FORMAT_B8G8R8_SRGB = 36,
+    VK_FORMAT_R8G8B8A8_UNORM = 37,
+    VK_FORMAT_R8G8B8A8_SNORM = 38,
+    VK_FORMAT_R8G8B8A8_USCALED = 39,
+    VK_FORMAT_R8G8B8A8_SSCALED = 40,
+    VK_FORMAT_R8G8B8A8_UINT = 41,
+    VK_FORMAT_R8G8B8A8_SINT = 42,
+    VK_FORMAT_R8G8B8A8_SRGB = 43,
+    VK_FORMAT_B8G8R8A8_UNORM = 44,
+    VK_FORMAT_B8G8R8A8_SNORM = 45,
+    VK_FORMAT_B8G8R8A8_USCALED = 46,
+    VK_FORMAT_B8G8R8A8_SSCALED = 47,
+    VK_FORMAT_B8G8R8A8_UINT = 48,
+    VK_FORMAT_B8G8R8A8_SINT = 49,
+    VK_FORMAT_B8G8R8A8_SRGB = 50,
+    VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
+    VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
+    VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
+    VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
+    VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
+    VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
+    VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
+    VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
+    VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
+    VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
+    VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
+    VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
+    VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
+    VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
+    VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
+    VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
+    VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
+    VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
+    VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
+    VK_FORMAT_R16_UNORM = 70,
+    VK_FORMAT_R16_SNORM = 71,
+    VK_FORMAT_R16_USCALED = 72,
+    VK_FORMAT_R16_SSCALED = 73,
+    VK_FORMAT_R16_UINT = 74,
+    VK_FORMAT_R16_SINT = 75,
+    VK_FORMAT_R16_SFLOAT = 76,
+    VK_FORMAT_R16G16_UNORM = 77,
+    VK_FORMAT_R16G16_SNORM = 78,
+    VK_FORMAT_R16G16_USCALED = 79,
+    VK_FORMAT_R16G16_SSCALED = 80,
+    VK_FORMAT_R16G16_UINT = 81,
+    VK_FORMAT_R16G16_SINT = 82,
+    VK_FORMAT_R16G16_SFLOAT = 83,
+    VK_FORMAT_R16G16B16_UNORM = 84,
+    VK_FORMAT_R16G16B16_SNORM = 85,
+    VK_FORMAT_R16G16B16_USCALED = 86,
+    VK_FORMAT_R16G16B16_SSCALED = 87,
+    VK_FORMAT_R16G16B16_UINT = 88,
+    VK_FORMAT_R16G16B16_SINT = 89,
+    VK_FORMAT_R16G16B16_SFLOAT = 90,
+    VK_FORMAT_R16G16B16A16_UNORM = 91,
+    VK_FORMAT_R16G16B16A16_SNORM = 92,
+    VK_FORMAT_R16G16B16A16_USCALED = 93,
+    VK_FORMAT_R16G16B16A16_SSCALED = 94,
+    VK_FORMAT_R16G16B16A16_UINT = 95,
+    VK_FORMAT_R16G16B16A16_SINT = 96,
+    VK_FORMAT_R16G16B16A16_SFLOAT = 97,
+    VK_FORMAT_R32_UINT = 98,
+    VK_FORMAT_R32_SINT = 99,
+    VK_FORMAT_R32_SFLOAT = 100,
+    VK_FORMAT_R32G32_UINT = 101,
+    VK_FORMAT_R32G32_SINT = 102,
+    VK_FORMAT_R32G32_SFLOAT = 103,
+    VK_FORMAT_R32G32B32_UINT = 104,
+    VK_FORMAT_R32G32B32_SINT = 105,
+    VK_FORMAT_R32G32B32_SFLOAT = 106,
+    VK_FORMAT_R32G32B32A32_UINT = 107,
+    VK_FORMAT_R32G32B32A32_SINT = 108,
+    VK_FORMAT_R32G32B32A32_SFLOAT = 109,
+    VK_FORMAT_R64_UINT = 110,
+    VK_FORMAT_R64_SINT = 111,
+    VK_FORMAT_R64_SFLOAT = 112,
+    VK_FORMAT_R64G64_UINT = 113,
+    VK_FORMAT_R64G64_SINT = 114,
+    VK_FORMAT_R64G64_SFLOAT = 115,
+    VK_FORMAT_R64G64B64_UINT = 116,
+    VK_FORMAT_R64G64B64_SINT = 117,
+    VK_FORMAT_R64G64B64_SFLOAT = 118,
+    VK_FORMAT_R64G64B64A64_UINT = 119,
+    VK_FORMAT_R64G64B64A64_SINT = 120,
+    VK_FORMAT_R64G64B64A64_SFLOAT = 121,
+    VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
+    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
+    VK_FORMAT_D16_UNORM = 124,
+    VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
+    VK_FORMAT_D32_SFLOAT = 126,
+    VK_FORMAT_S8_UINT = 127,
+    VK_FORMAT_D16_UNORM_S8_UINT = 128,
+    VK_FORMAT_D24_UNORM_S8_UINT = 129,
+    VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
+    VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
+    VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
+    VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
+    VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
+    VK_FORMAT_BC2_UNORM_BLOCK = 135,
+    VK_FORMAT_BC2_SRGB_BLOCK = 136,
+    VK_FORMAT_BC3_UNORM_BLOCK = 137,
+    VK_FORMAT_BC3_SRGB_BLOCK = 138,
+    VK_FORMAT_BC4_UNORM_BLOCK = 139,
+    VK_FORMAT_BC4_SNORM_BLOCK = 140,
+    VK_FORMAT_BC5_UNORM_BLOCK = 141,
+    VK_FORMAT_BC5_SNORM_BLOCK = 142,
+    VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
+    VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
+    VK_FORMAT_BC7_UNORM_BLOCK = 145,
+    VK_FORMAT_BC7_SRGB_BLOCK = 146,
+    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
+    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
+    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
+    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
+    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
+    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
+    VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
+    VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
+    VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
+    VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
+    VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
+    VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
+    VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
+    VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
+    VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
+    VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
+    VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
+    VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
+    VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
+    VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
+    VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
+    VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
+    VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
+    VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
+    VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
+    VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
+    VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
+    VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
+    VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
+    VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
+    VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
+    VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
+    VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
+    VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
+    VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
+    VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
+    VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
+    VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+    VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
+    VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
+    VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
+    VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
+    VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
+    VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
+    VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
+    VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
+    VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
+    VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
+    VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
+    VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
+    VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
+    VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
+    VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM,
+    VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM,
+    VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
+    VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+    VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
+    VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
+    VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
+    VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16,
+    VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
+    VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+    VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
+    VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
+    VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
+    VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
+    VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16,
+    VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
+    VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
+    VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
+    VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
+    VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
+    VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
+    VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM,
+    VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM,
+    VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
+    VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
+    VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
+    VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
+    VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
+    VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED,
+    VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
+    VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1),
+    VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
+} VkFormat;
+
+typedef enum VkImageType {
+    VK_IMAGE_TYPE_1D = 0,
+    VK_IMAGE_TYPE_2D = 1,
+    VK_IMAGE_TYPE_3D = 2,
+    VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D,
+    VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D,
+    VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1),
+    VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkImageType;
+
+typedef enum VkImageTiling {
+    VK_IMAGE_TILING_OPTIMAL = 0,
+    VK_IMAGE_TILING_LINEAR = 1,
+    VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,
+    VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,
+    VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),
+    VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF
+} VkImageTiling;
+
+typedef enum VkPhysicalDeviceType {
+    VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
+    VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
+    VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
+    VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
+    VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
+    VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER,
+    VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU,
+    VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1),
+    VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkPhysicalDeviceType;
+
+typedef enum VkQueryType {
+    VK_QUERY_TYPE_OCCLUSION = 0,
+    VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
+    VK_QUERY_TYPE_TIMESTAMP = 2,
+    VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
+    VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,
+    VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),
+    VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkQueryType;
+
+typedef enum VkSharingMode {
+    VK_SHARING_MODE_EXCLUSIVE = 0,
+    VK_SHARING_MODE_CONCURRENT = 1,
+    VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE,
+    VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT,
+    VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1),
+    VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF
+} VkSharingMode;
+
+typedef enum VkImageLayout {
+    VK_IMAGE_LAYOUT_UNDEFINED = 0,
+    VK_IMAGE_LAYOUT_GENERAL = 1,
+    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2,
+    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3,
+    VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4,
+    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5,
+    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6,
+    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7,
+    VK_IMAGE_LAYOUT_PREINITIALIZED = 8,
+    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
+    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
+    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
+    VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
+    VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
+    VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
+    VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED,
+    VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED,
+    VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1),
+    VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF
+} VkImageLayout;
+
+typedef enum VkImageViewType {
+    VK_IMAGE_VIEW_TYPE_1D = 0,
+    VK_IMAGE_VIEW_TYPE_2D = 1,
+    VK_IMAGE_VIEW_TYPE_3D = 2,
+    VK_IMAGE_VIEW_TYPE_CUBE = 3,
+    VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4,
+    VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5,
+    VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6,
+    VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D,
+    VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
+    VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1),
+    VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkImageViewType;
+
+typedef enum VkComponentSwizzle {
+    VK_COMPONENT_SWIZZLE_IDENTITY = 0,
+    VK_COMPONENT_SWIZZLE_ZERO = 1,
+    VK_COMPONENT_SWIZZLE_ONE = 2,
+    VK_COMPONENT_SWIZZLE_R = 3,
+    VK_COMPONENT_SWIZZLE_G = 4,
+    VK_COMPONENT_SWIZZLE_B = 5,
+    VK_COMPONENT_SWIZZLE_A = 6,
+    VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY,
+    VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A,
+    VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1),
+    VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF
+} VkComponentSwizzle;
+
+typedef enum VkVertexInputRate {
+    VK_VERTEX_INPUT_RATE_VERTEX = 0,
+    VK_VERTEX_INPUT_RATE_INSTANCE = 1,
+    VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX,
+    VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE,
+    VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1),
+    VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF
+} VkVertexInputRate;
+
+typedef enum VkPrimitiveTopology {
+    VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,
+    VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,
+    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,
+    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,
+    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,
+    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,
+    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,
+    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,
+    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,
+    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,
+    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,
+    VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+    VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
+    VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1),
+    VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF
+} VkPrimitiveTopology;
+
+typedef enum VkPolygonMode {
+    VK_POLYGON_MODE_FILL = 0,
+    VK_POLYGON_MODE_LINE = 1,
+    VK_POLYGON_MODE_POINT = 2,
+    VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
+    VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL,
+    VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT,
+    VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1),
+    VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF
+} VkPolygonMode;
+
+typedef enum VkFrontFace {
+    VK_FRONT_FACE_COUNTER_CLOCKWISE = 0,
+    VK_FRONT_FACE_CLOCKWISE = 1,
+    VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE,
+    VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE,
+    VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1),
+    VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF
+} VkFrontFace;
+
+typedef enum VkCompareOp {
+    VK_COMPARE_OP_NEVER = 0,
+    VK_COMPARE_OP_LESS = 1,
+    VK_COMPARE_OP_EQUAL = 2,
+    VK_COMPARE_OP_LESS_OR_EQUAL = 3,
+    VK_COMPARE_OP_GREATER = 4,
+    VK_COMPARE_OP_NOT_EQUAL = 5,
+    VK_COMPARE_OP_GREATER_OR_EQUAL = 6,
+    VK_COMPARE_OP_ALWAYS = 7,
+    VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER,
+    VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS,
+    VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1),
+    VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF
+} VkCompareOp;
+
+typedef enum VkStencilOp {
+    VK_STENCIL_OP_KEEP = 0,
+    VK_STENCIL_OP_ZERO = 1,
+    VK_STENCIL_OP_REPLACE = 2,
+    VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3,
+    VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4,
+    VK_STENCIL_OP_INVERT = 5,
+    VK_STENCIL_OP_INCREMENT_AND_WRAP = 6,
+    VK_STENCIL_OP_DECREMENT_AND_WRAP = 7,
+    VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP,
+    VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP,
+    VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1),
+    VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF
+} VkStencilOp;
+
+typedef enum VkLogicOp {
+    VK_LOGIC_OP_CLEAR = 0,
+    VK_LOGIC_OP_AND = 1,
+    VK_LOGIC_OP_AND_REVERSE = 2,
+    VK_LOGIC_OP_COPY = 3,
+    VK_LOGIC_OP_AND_INVERTED = 4,
+    VK_LOGIC_OP_NO_OP = 5,
+    VK_LOGIC_OP_XOR = 6,
+    VK_LOGIC_OP_OR = 7,
+    VK_LOGIC_OP_NOR = 8,
+    VK_LOGIC_OP_EQUIVALENT = 9,
+    VK_LOGIC_OP_INVERT = 10,
+    VK_LOGIC_OP_OR_REVERSE = 11,
+    VK_LOGIC_OP_COPY_INVERTED = 12,
+    VK_LOGIC_OP_OR_INVERTED = 13,
+    VK_LOGIC_OP_NAND = 14,
+    VK_LOGIC_OP_SET = 15,
+    VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR,
+    VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET,
+    VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1),
+    VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF
+} VkLogicOp;
+
+typedef enum VkBlendFactor {
+    VK_BLEND_FACTOR_ZERO = 0,
+    VK_BLEND_FACTOR_ONE = 1,
+    VK_BLEND_FACTOR_SRC_COLOR = 2,
+    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
+    VK_BLEND_FACTOR_DST_COLOR = 4,
+    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
+    VK_BLEND_FACTOR_SRC_ALPHA = 6,
+    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
+    VK_BLEND_FACTOR_DST_ALPHA = 8,
+    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
+    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
+    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
+    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
+    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
+    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
+    VK_BLEND_FACTOR_SRC1_COLOR = 15,
+    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
+    VK_BLEND_FACTOR_SRC1_ALPHA = 17,
+    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
+    VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO,
+    VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
+    VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1),
+    VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF
+} VkBlendFactor;
+
+typedef enum VkBlendOp {
+    VK_BLEND_OP_ADD = 0,
+    VK_BLEND_OP_SUBTRACT = 1,
+    VK_BLEND_OP_REVERSE_SUBTRACT = 2,
+    VK_BLEND_OP_MIN = 3,
+    VK_BLEND_OP_MAX = 4,
+    VK_BLEND_OP_ZERO_EXT = 1000148000,
+    VK_BLEND_OP_SRC_EXT = 1000148001,
+    VK_BLEND_OP_DST_EXT = 1000148002,
+    VK_BLEND_OP_SRC_OVER_EXT = 1000148003,
+    VK_BLEND_OP_DST_OVER_EXT = 1000148004,
+    VK_BLEND_OP_SRC_IN_EXT = 1000148005,
+    VK_BLEND_OP_DST_IN_EXT = 1000148006,
+    VK_BLEND_OP_SRC_OUT_EXT = 1000148007,
+    VK_BLEND_OP_DST_OUT_EXT = 1000148008,
+    VK_BLEND_OP_SRC_ATOP_EXT = 1000148009,
+    VK_BLEND_OP_DST_ATOP_EXT = 1000148010,
+    VK_BLEND_OP_XOR_EXT = 1000148011,
+    VK_BLEND_OP_MULTIPLY_EXT = 1000148012,
+    VK_BLEND_OP_SCREEN_EXT = 1000148013,
+    VK_BLEND_OP_OVERLAY_EXT = 1000148014,
+    VK_BLEND_OP_DARKEN_EXT = 1000148015,
+    VK_BLEND_OP_LIGHTEN_EXT = 1000148016,
+    VK_BLEND_OP_COLORDODGE_EXT = 1000148017,
+    VK_BLEND_OP_COLORBURN_EXT = 1000148018,
+    VK_BLEND_OP_HARDLIGHT_EXT = 1000148019,
+    VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020,
+    VK_BLEND_OP_DIFFERENCE_EXT = 1000148021,
+    VK_BLEND_OP_EXCLUSION_EXT = 1000148022,
+    VK_BLEND_OP_INVERT_EXT = 1000148023,
+    VK_BLEND_OP_INVERT_RGB_EXT = 1000148024,
+    VK_BLEND_OP_LINEARDODGE_EXT = 1000148025,
+    VK_BLEND_OP_LINEARBURN_EXT = 1000148026,
+    VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027,
+    VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028,
+    VK_BLEND_OP_PINLIGHT_EXT = 1000148029,
+    VK_BLEND_OP_HARDMIX_EXT = 1000148030,
+    VK_BLEND_OP_HSL_HUE_EXT = 1000148031,
+    VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032,
+    VK_BLEND_OP_HSL_COLOR_EXT = 1000148033,
+    VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034,
+    VK_BLEND_OP_PLUS_EXT = 1000148035,
+    VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036,
+    VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037,
+    VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038,
+    VK_BLEND_OP_MINUS_EXT = 1000148039,
+    VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040,
+    VK_BLEND_OP_CONTRAST_EXT = 1000148041,
+    VK_BLEND_OP_INVERT_OVG_EXT = 1000148042,
+    VK_BLEND_OP_RED_EXT = 1000148043,
+    VK_BLEND_OP_GREEN_EXT = 1000148044,
+    VK_BLEND_OP_BLUE_EXT = 1000148045,
+    VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD,
+    VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX,
+    VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1),
+    VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF
+} VkBlendOp;
+
+typedef enum VkDynamicState {
+    VK_DYNAMIC_STATE_VIEWPORT = 0,
+    VK_DYNAMIC_STATE_SCISSOR = 1,
+    VK_DYNAMIC_STATE_LINE_WIDTH = 2,
+    VK_DYNAMIC_STATE_DEPTH_BIAS = 3,
+    VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,
+    VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5,
+    VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,
+    VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,
+    VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
+    VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
+    VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
+    VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000,
+    VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT,
+    VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE,
+    VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1),
+    VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF
+} VkDynamicState;
+
+typedef enum VkFilter {
+    VK_FILTER_NEAREST = 0,
+    VK_FILTER_LINEAR = 1,
+    VK_FILTER_CUBIC_IMG = 1000015000,
+    VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST,
+    VK_FILTER_END_RANGE = VK_FILTER_LINEAR,
+    VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1),
+    VK_FILTER_MAX_ENUM = 0x7FFFFFFF
+} VkFilter;
+
+typedef enum VkSamplerMipmapMode {
+    VK_SAMPLER_MIPMAP_MODE_NEAREST = 0,
+    VK_SAMPLER_MIPMAP_MODE_LINEAR = 1,
+    VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST,
+    VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR,
+    VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1),
+    VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerMipmapMode;
+
+typedef enum VkSamplerAddressMode {
+    VK_SAMPLER_ADDRESS_MODE_REPEAT = 0,
+    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1,
+    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2,
+    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3,
+    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4,
+    VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+    VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
+    VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1),
+    VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerAddressMode;
+
+typedef enum VkBorderColor {
+    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0,
+    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1,
+    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2,
+    VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3,
+    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4,
+    VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5,
+    VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+    VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE,
+    VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1),
+    VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF
+} VkBorderColor;
+
+typedef enum VkDescriptorType {
+    VK_DESCRIPTOR_TYPE_SAMPLER = 0,
+    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1,
+    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2,
+    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3,
+    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4,
+    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5,
+    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6,
+    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7,
+    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
+    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
+    VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
+    VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
+    VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+    VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
+    VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorType;
+
+typedef enum VkAttachmentLoadOp {
+    VK_ATTACHMENT_LOAD_OP_LOAD = 0,
+    VK_ATTACHMENT_LOAD_OP_CLEAR = 1,
+    VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2,
+    VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD,
+    VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+    VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1),
+    VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF
+} VkAttachmentLoadOp;
+
+typedef enum VkAttachmentStoreOp {
+    VK_ATTACHMENT_STORE_OP_STORE = 0,
+    VK_ATTACHMENT_STORE_OP_DONT_CARE = 1,
+    VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE,
+    VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+    VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1),
+    VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF
+} VkAttachmentStoreOp;
+
+typedef enum VkPipelineBindPoint {
+    VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
+    VK_PIPELINE_BIND_POINT_COMPUTE = 1,
+    VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,
+    VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,
+    VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),
+    VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineBindPoint;
+
+typedef enum VkCommandBufferLevel {
+    VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0,
+    VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1,
+    VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+    VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY,
+    VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1),
+    VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF
+} VkCommandBufferLevel;
+
+typedef enum VkIndexType {
+    VK_INDEX_TYPE_UINT16 = 0,
+    VK_INDEX_TYPE_UINT32 = 1,
+    VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,
+    VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,
+    VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),
+    VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkIndexType;
+
+typedef enum VkSubpassContents {
+    VK_SUBPASS_CONTENTS_INLINE = 0,
+    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1,
+    VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE,
+    VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS,
+    VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1),
+    VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
+} VkSubpassContents;
+
+typedef enum VkObjectType {
+    VK_OBJECT_TYPE_UNKNOWN = 0,
+    VK_OBJECT_TYPE_INSTANCE = 1,
+    VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
+    VK_OBJECT_TYPE_DEVICE = 3,
+    VK_OBJECT_TYPE_QUEUE = 4,
+    VK_OBJECT_TYPE_SEMAPHORE = 5,
+    VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
+    VK_OBJECT_TYPE_FENCE = 7,
+    VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
+    VK_OBJECT_TYPE_BUFFER = 9,
+    VK_OBJECT_TYPE_IMAGE = 10,
+    VK_OBJECT_TYPE_EVENT = 11,
+    VK_OBJECT_TYPE_QUERY_POOL = 12,
+    VK_OBJECT_TYPE_BUFFER_VIEW = 13,
+    VK_OBJECT_TYPE_IMAGE_VIEW = 14,
+    VK_OBJECT_TYPE_SHADER_MODULE = 15,
+    VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
+    VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
+    VK_OBJECT_TYPE_RENDER_PASS = 18,
+    VK_OBJECT_TYPE_PIPELINE = 19,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
+    VK_OBJECT_TYPE_SAMPLER = 21,
+    VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
+    VK_OBJECT_TYPE_FRAMEBUFFER = 24,
+    VK_OBJECT_TYPE_COMMAND_POOL = 25,
+    VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
+    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
+    VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
+    VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
+    VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
+    VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
+    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
+    VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
+    VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+    VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
+    VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
+    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE,
+    VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,
+    VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
+    VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,
+    VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),
+    VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkObjectType;
+
+typedef VkFlags VkInstanceCreateFlags;
+
+typedef enum VkFormatFeatureFlagBits {
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001,
+    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002,
+    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004,
+    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008,
+    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010,
+    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020,
+    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040,
+    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080,
+    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100,
+    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200,
+    VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400,
+    VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
+    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000,
+    VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000,
+    VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000,
+    VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000,
+    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000,
+    VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT,
+    VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
+    VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT,
+    VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT,
+    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT,
+    VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkFormatFeatureFlagBits;
+typedef VkFlags VkFormatFeatureFlags;
+
+typedef enum VkImageUsageFlagBits {
+    VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001,
+    VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002,
+    VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004,
+    VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008,
+    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010,
+    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020,
+    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040,
+    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080,
+    VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkImageUsageFlagBits;
+typedef VkFlags VkImageUsageFlags;
+
+typedef enum VkImageCreateFlagBits {
+    VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001,
+    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
+    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
+    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,
+    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,
+    VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400,
+    VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040,
+    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020,
+    VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080,
+    VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100,
+    VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800,
+    VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200,
+    VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
+    VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT,
+    VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT,
+    VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT,
+    VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT,
+    VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT,
+    VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT,
+    VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkImageCreateFlagBits;
+typedef VkFlags VkImageCreateFlags;
+
+typedef enum VkSampleCountFlagBits {
+    VK_SAMPLE_COUNT_1_BIT = 0x00000001,
+    VK_SAMPLE_COUNT_2_BIT = 0x00000002,
+    VK_SAMPLE_COUNT_4_BIT = 0x00000004,
+    VK_SAMPLE_COUNT_8_BIT = 0x00000008,
+    VK_SAMPLE_COUNT_16_BIT = 0x00000010,
+    VK_SAMPLE_COUNT_32_BIT = 0x00000020,
+    VK_SAMPLE_COUNT_64_BIT = 0x00000040,
+    VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSampleCountFlagBits;
+typedef VkFlags VkSampleCountFlags;
+
+typedef enum VkQueueFlagBits {
+    VK_QUEUE_GRAPHICS_BIT = 0x00000001,
+    VK_QUEUE_COMPUTE_BIT = 0x00000002,
+    VK_QUEUE_TRANSFER_BIT = 0x00000004,
+    VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008,
+    VK_QUEUE_PROTECTED_BIT = 0x00000010,
+    VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkQueueFlagBits;
+typedef VkFlags VkQueueFlags;
+
+typedef enum VkMemoryPropertyFlagBits {
+    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,
+    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,
+    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
+    VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
+    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
+    VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
+    VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkMemoryPropertyFlagBits;
+typedef VkFlags VkMemoryPropertyFlags;
+
+typedef enum VkMemoryHeapFlagBits {
+    VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
+    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
+    VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT,
+    VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkMemoryHeapFlagBits;
+typedef VkFlags VkMemoryHeapFlags;
+typedef VkFlags VkDeviceCreateFlags;
+
+typedef enum VkDeviceQueueCreateFlagBits {
+    VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001,
+    VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDeviceQueueCreateFlagBits;
+typedef VkFlags VkDeviceQueueCreateFlags;
+
+typedef enum VkPipelineStageFlagBits {
+    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001,
+    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002,
+    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004,
+    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008,
+    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010,
+    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020,
+    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040,
+    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080,
+    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100,
+    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200,
+    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400,
+    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800,
+    VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000,
+    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000,
+    VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
+    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
+    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
+    VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
+    VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineStageFlagBits;
+typedef VkFlags VkPipelineStageFlags;
+typedef VkFlags VkMemoryMapFlags;
+
+typedef enum VkImageAspectFlagBits {
+    VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001,
+    VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,
+    VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,
+    VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,
+    VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
+    VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
+    VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+    VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT,
+    VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT,
+    VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT,
+    VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkImageAspectFlagBits;
+typedef VkFlags VkImageAspectFlags;
+
+typedef enum VkSparseImageFormatFlagBits {
+    VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001,
+    VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002,
+    VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004,
+    VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSparseImageFormatFlagBits;
+typedef VkFlags VkSparseImageFormatFlags;
+
+typedef enum VkSparseMemoryBindFlagBits {
+    VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001,
+    VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSparseMemoryBindFlagBits;
+typedef VkFlags VkSparseMemoryBindFlags;
+
+typedef enum VkFenceCreateFlagBits {
+    VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001,
+    VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkFenceCreateFlagBits;
+typedef VkFlags VkFenceCreateFlags;
+typedef VkFlags VkSemaphoreCreateFlags;
+typedef VkFlags VkEventCreateFlags;
+typedef VkFlags VkQueryPoolCreateFlags;
+
+typedef enum VkQueryPipelineStatisticFlagBits {
+    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001,
+    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002,
+    VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004,
+    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008,
+    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010,
+    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020,
+    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040,
+    VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080,
+    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100,
+    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200,
+    VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400,
+    VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkQueryPipelineStatisticFlagBits;
+typedef VkFlags VkQueryPipelineStatisticFlags;
+
+typedef enum VkQueryResultFlagBits {
+    VK_QUERY_RESULT_64_BIT = 0x00000001,
+    VK_QUERY_RESULT_WAIT_BIT = 0x00000002,
+    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004,
+    VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008,
+    VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkQueryResultFlagBits;
+typedef VkFlags VkQueryResultFlags;
+
+typedef enum VkBufferCreateFlagBits {
+    VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001,
+    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002,
+    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
+    VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008,
+    VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkBufferCreateFlagBits;
+typedef VkFlags VkBufferCreateFlags;
+
+typedef enum VkBufferUsageFlagBits {
+    VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001,
+    VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002,
+    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004,
+    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008,
+    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010,
+    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020,
+    VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
+    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
+    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
+    VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkBufferUsageFlagBits;
+typedef VkFlags VkBufferUsageFlags;
+typedef VkFlags VkBufferViewCreateFlags;
+typedef VkFlags VkImageViewCreateFlags;
+typedef VkFlags VkShaderModuleCreateFlags;
+typedef VkFlags VkPipelineCacheCreateFlags;
+
+typedef enum VkPipelineCreateFlagBits {
+    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
+    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
+    VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
+    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
+    VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
+    VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT,
+    VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE,
+    VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineCreateFlagBits;
+typedef VkFlags VkPipelineCreateFlags;
+typedef VkFlags VkPipelineShaderStageCreateFlags;
+
+typedef enum VkShaderStageFlagBits {
+    VK_SHADER_STAGE_VERTEX_BIT = 0x00000001,
+    VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002,
+    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004,
+    VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008,
+    VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010,
+    VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
+    VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
+    VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
+    VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkShaderStageFlagBits;
+typedef VkFlags VkPipelineVertexInputStateCreateFlags;
+typedef VkFlags VkPipelineInputAssemblyStateCreateFlags;
+typedef VkFlags VkPipelineTessellationStateCreateFlags;
+typedef VkFlags VkPipelineViewportStateCreateFlags;
+typedef VkFlags VkPipelineRasterizationStateCreateFlags;
+
+typedef enum VkCullModeFlagBits {
+    VK_CULL_MODE_NONE = 0,
+    VK_CULL_MODE_FRONT_BIT = 0x00000001,
+    VK_CULL_MODE_BACK_BIT = 0x00000002,
+    VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
+    VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkCullModeFlagBits;
+typedef VkFlags VkCullModeFlags;
+typedef VkFlags VkPipelineMultisampleStateCreateFlags;
+typedef VkFlags VkPipelineDepthStencilStateCreateFlags;
+typedef VkFlags VkPipelineColorBlendStateCreateFlags;
+
+typedef enum VkColorComponentFlagBits {
+    VK_COLOR_COMPONENT_R_BIT = 0x00000001,
+    VK_COLOR_COMPONENT_G_BIT = 0x00000002,
+    VK_COLOR_COMPONENT_B_BIT = 0x00000004,
+    VK_COLOR_COMPONENT_A_BIT = 0x00000008,
+    VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkColorComponentFlagBits;
+typedef VkFlags VkColorComponentFlags;
+typedef VkFlags VkPipelineDynamicStateCreateFlags;
+typedef VkFlags VkPipelineLayoutCreateFlags;
+typedef VkFlags VkShaderStageFlags;
+typedef VkFlags VkSamplerCreateFlags;
+
+typedef enum VkDescriptorSetLayoutCreateFlagBits {
+    VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
+    VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorSetLayoutCreateFlagBits;
+typedef VkFlags VkDescriptorSetLayoutCreateFlags;
+
+typedef enum VkDescriptorPoolCreateFlagBits {
+    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,
+    VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorPoolCreateFlagBits;
+typedef VkFlags VkDescriptorPoolCreateFlags;
+typedef VkFlags VkDescriptorPoolResetFlags;
+typedef VkFlags VkFramebufferCreateFlags;
+typedef VkFlags VkRenderPassCreateFlags;
+
+typedef enum VkAttachmentDescriptionFlagBits {
+    VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001,
+    VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkAttachmentDescriptionFlagBits;
+typedef VkFlags VkAttachmentDescriptionFlags;
+
+typedef enum VkSubpassDescriptionFlagBits {
+    VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,
+    VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
+    VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSubpassDescriptionFlagBits;
+typedef VkFlags VkSubpassDescriptionFlags;
+
+typedef enum VkAccessFlagBits {
+    VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,
+    VK_ACCESS_INDEX_READ_BIT = 0x00000002,
+    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,
+    VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,
+    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,
+    VK_ACCESS_SHADER_READ_BIT = 0x00000020,
+    VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,
+    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,
+    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,
+    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,
+    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,
+    VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,
+    VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,
+    VK_ACCESS_HOST_READ_BIT = 0x00002000,
+    VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
+    VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
+    VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+    VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
+    VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
+    VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
+    VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkAccessFlagBits;
+typedef VkFlags VkAccessFlags;
+
+typedef enum VkDependencyFlagBits {
+    VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
+    VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004,
+    VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
+    VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT,
+    VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT,
+    VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDependencyFlagBits;
+typedef VkFlags VkDependencyFlags;
+
+typedef enum VkCommandPoolCreateFlagBits {
+    VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001,
+    VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002,
+    VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004,
+    VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkCommandPoolCreateFlagBits;
+typedef VkFlags VkCommandPoolCreateFlags;
+
+typedef enum VkCommandPoolResetFlagBits {
+    VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
+    VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkCommandPoolResetFlagBits;
+typedef VkFlags VkCommandPoolResetFlags;
+
+typedef enum VkCommandBufferUsageFlagBits {
+    VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001,
+    VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002,
+    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004,
+    VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkCommandBufferUsageFlagBits;
+typedef VkFlags VkCommandBufferUsageFlags;
+
+typedef enum VkQueryControlFlagBits {
+    VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001,
+    VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkQueryControlFlagBits;
+typedef VkFlags VkQueryControlFlags;
+
+typedef enum VkCommandBufferResetFlagBits {
+    VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001,
+    VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkCommandBufferResetFlagBits;
+typedef VkFlags VkCommandBufferResetFlags;
+
+typedef enum VkStencilFaceFlagBits {
+    VK_STENCIL_FACE_FRONT_BIT = 0x00000001,
+    VK_STENCIL_FACE_BACK_BIT = 0x00000002,
+    VK_STENCIL_FRONT_AND_BACK = 0x00000003,
+    VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkStencilFaceFlagBits;
+typedef VkFlags VkStencilFaceFlags;
+
+typedef struct VkApplicationInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    const char*        pApplicationName;
+    uint32_t           applicationVersion;
+    const char*        pEngineName;
+    uint32_t           engineVersion;
+    uint32_t           apiVersion;
+} VkApplicationInfo;
+
+typedef struct VkInstanceCreateInfo {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkInstanceCreateFlags       flags;
+    const VkApplicationInfo*    pApplicationInfo;
+    uint32_t                    enabledLayerCount;
+    const char* const*          ppEnabledLayerNames;
+    uint32_t                    enabledExtensionCount;
+    const char* const*          ppEnabledExtensionNames;
+} VkInstanceCreateInfo;
+
+typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)(
+    void*                                       pUserData,
+    size_t                                      size,
+    size_t                                      alignment,
+    VkSystemAllocationScope                     allocationScope);
+
+typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)(
+    void*                                       pUserData,
+    void*                                       pOriginal,
+    size_t                                      size,
+    size_t                                      alignment,
+    VkSystemAllocationScope                     allocationScope);
+
+typedef void (VKAPI_PTR *PFN_vkFreeFunction)(
+    void*                                       pUserData,
+    void*                                       pMemory);
+
+typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)(
+    void*                                       pUserData,
+    size_t                                      size,
+    VkInternalAllocationType                    allocationType,
+    VkSystemAllocationScope                     allocationScope);
+
+typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)(
+    void*                                       pUserData,
+    size_t                                      size,
+    VkInternalAllocationType                    allocationType,
+    VkSystemAllocationScope                     allocationScope);
+
+typedef struct VkAllocationCallbacks {
+    void*                                   pUserData;
+    PFN_vkAllocationFunction                pfnAllocation;
+    PFN_vkReallocationFunction              pfnReallocation;
+    PFN_vkFreeFunction                      pfnFree;
+    PFN_vkInternalAllocationNotification    pfnInternalAllocation;
+    PFN_vkInternalFreeNotification          pfnInternalFree;
+} VkAllocationCallbacks;
+
+typedef struct VkPhysicalDeviceFeatures {
+    VkBool32    robustBufferAccess;
+    VkBool32    fullDrawIndexUint32;
+    VkBool32    imageCubeArray;
+    VkBool32    independentBlend;
+    VkBool32    geometryShader;
+    VkBool32    tessellationShader;
+    VkBool32    sampleRateShading;
+    VkBool32    dualSrcBlend;
+    VkBool32    logicOp;
+    VkBool32    multiDrawIndirect;
+    VkBool32    drawIndirectFirstInstance;
+    VkBool32    depthClamp;
+    VkBool32    depthBiasClamp;
+    VkBool32    fillModeNonSolid;
+    VkBool32    depthBounds;
+    VkBool32    wideLines;
+    VkBool32    largePoints;
+    VkBool32    alphaToOne;
+    VkBool32    multiViewport;
+    VkBool32    samplerAnisotropy;
+    VkBool32    textureCompressionETC2;
+    VkBool32    textureCompressionASTC_LDR;
+    VkBool32    textureCompressionBC;
+    VkBool32    occlusionQueryPrecise;
+    VkBool32    pipelineStatisticsQuery;
+    VkBool32    vertexPipelineStoresAndAtomics;
+    VkBool32    fragmentStoresAndAtomics;
+    VkBool32    shaderTessellationAndGeometryPointSize;
+    VkBool32    shaderImageGatherExtended;
+    VkBool32    shaderStorageImageExtendedFormats;
+    VkBool32    shaderStorageImageMultisample;
+    VkBool32    shaderStorageImageReadWithoutFormat;
+    VkBool32    shaderStorageImageWriteWithoutFormat;
+    VkBool32    shaderUniformBufferArrayDynamicIndexing;
+    VkBool32    shaderSampledImageArrayDynamicIndexing;
+    VkBool32    shaderStorageBufferArrayDynamicIndexing;
+    VkBool32    shaderStorageImageArrayDynamicIndexing;
+    VkBool32    shaderClipDistance;
+    VkBool32    shaderCullDistance;
+    VkBool32    shaderFloat64;
+    VkBool32    shaderInt64;
+    VkBool32    shaderInt16;
+    VkBool32    shaderResourceResidency;
+    VkBool32    shaderResourceMinLod;
+    VkBool32    sparseBinding;
+    VkBool32    sparseResidencyBuffer;
+    VkBool32    sparseResidencyImage2D;
+    VkBool32    sparseResidencyImage3D;
+    VkBool32    sparseResidency2Samples;
+    VkBool32    sparseResidency4Samples;
+    VkBool32    sparseResidency8Samples;
+    VkBool32    sparseResidency16Samples;
+    VkBool32    sparseResidencyAliased;
+    VkBool32    variableMultisampleRate;
+    VkBool32    inheritedQueries;
+} VkPhysicalDeviceFeatures;
+
+typedef struct VkFormatProperties {
+    VkFormatFeatureFlags    linearTilingFeatures;
+    VkFormatFeatureFlags    optimalTilingFeatures;
+    VkFormatFeatureFlags    bufferFeatures;
+} VkFormatProperties;
+
+typedef struct VkExtent3D {
+    uint32_t    width;
+    uint32_t    height;
+    uint32_t    depth;
+} VkExtent3D;
+
+typedef struct VkImageFormatProperties {
+    VkExtent3D            maxExtent;
+    uint32_t              maxMipLevels;
+    uint32_t              maxArrayLayers;
+    VkSampleCountFlags    sampleCounts;
+    VkDeviceSize          maxResourceSize;
+} VkImageFormatProperties;
+
+typedef struct VkPhysicalDeviceLimits {
+    uint32_t              maxImageDimension1D;
+    uint32_t              maxImageDimension2D;
+    uint32_t              maxImageDimension3D;
+    uint32_t              maxImageDimensionCube;
+    uint32_t              maxImageArrayLayers;
+    uint32_t              maxTexelBufferElements;
+    uint32_t              maxUniformBufferRange;
+    uint32_t              maxStorageBufferRange;
+    uint32_t              maxPushConstantsSize;
+    uint32_t              maxMemoryAllocationCount;
+    uint32_t              maxSamplerAllocationCount;
+    VkDeviceSize          bufferImageGranularity;
+    VkDeviceSize          sparseAddressSpaceSize;
+    uint32_t              maxBoundDescriptorSets;
+    uint32_t              maxPerStageDescriptorSamplers;
+    uint32_t              maxPerStageDescriptorUniformBuffers;
+    uint32_t              maxPerStageDescriptorStorageBuffers;
+    uint32_t              maxPerStageDescriptorSampledImages;
+    uint32_t              maxPerStageDescriptorStorageImages;
+    uint32_t              maxPerStageDescriptorInputAttachments;
+    uint32_t              maxPerStageResources;
+    uint32_t              maxDescriptorSetSamplers;
+    uint32_t              maxDescriptorSetUniformBuffers;
+    uint32_t              maxDescriptorSetUniformBuffersDynamic;
+    uint32_t              maxDescriptorSetStorageBuffers;
+    uint32_t              maxDescriptorSetStorageBuffersDynamic;
+    uint32_t              maxDescriptorSetSampledImages;
+    uint32_t              maxDescriptorSetStorageImages;
+    uint32_t              maxDescriptorSetInputAttachments;
+    uint32_t              maxVertexInputAttributes;
+    uint32_t              maxVertexInputBindings;
+    uint32_t              maxVertexInputAttributeOffset;
+    uint32_t              maxVertexInputBindingStride;
+    uint32_t              maxVertexOutputComponents;
+    uint32_t              maxTessellationGenerationLevel;
+    uint32_t              maxTessellationPatchSize;
+    uint32_t              maxTessellationControlPerVertexInputComponents;
+    uint32_t              maxTessellationControlPerVertexOutputComponents;
+    uint32_t              maxTessellationControlPerPatchOutputComponents;
+    uint32_t              maxTessellationControlTotalOutputComponents;
+    uint32_t              maxTessellationEvaluationInputComponents;
+    uint32_t              maxTessellationEvaluationOutputComponents;
+    uint32_t              maxGeometryShaderInvocations;
+    uint32_t              maxGeometryInputComponents;
+    uint32_t              maxGeometryOutputComponents;
+    uint32_t              maxGeometryOutputVertices;
+    uint32_t              maxGeometryTotalOutputComponents;
+    uint32_t              maxFragmentInputComponents;
+    uint32_t              maxFragmentOutputAttachments;
+    uint32_t              maxFragmentDualSrcAttachments;
+    uint32_t              maxFragmentCombinedOutputResources;
+    uint32_t              maxComputeSharedMemorySize;
+    uint32_t              maxComputeWorkGroupCount[3];
+    uint32_t              maxComputeWorkGroupInvocations;
+    uint32_t              maxComputeWorkGroupSize[3];
+    uint32_t              subPixelPrecisionBits;
+    uint32_t              subTexelPrecisionBits;
+    uint32_t              mipmapPrecisionBits;
+    uint32_t              maxDrawIndexedIndexValue;
+    uint32_t              maxDrawIndirectCount;
+    float                 maxSamplerLodBias;
+    float                 maxSamplerAnisotropy;
+    uint32_t              maxViewports;
+    uint32_t              maxViewportDimensions[2];
+    float                 viewportBoundsRange[2];
+    uint32_t              viewportSubPixelBits;
+    size_t                minMemoryMapAlignment;
+    VkDeviceSize          minTexelBufferOffsetAlignment;
+    VkDeviceSize          minUniformBufferOffsetAlignment;
+    VkDeviceSize          minStorageBufferOffsetAlignment;
+    int32_t               minTexelOffset;
+    uint32_t              maxTexelOffset;
+    int32_t               minTexelGatherOffset;
+    uint32_t              maxTexelGatherOffset;
+    float                 minInterpolationOffset;
+    float                 maxInterpolationOffset;
+    uint32_t              subPixelInterpolationOffsetBits;
+    uint32_t              maxFramebufferWidth;
+    uint32_t              maxFramebufferHeight;
+    uint32_t              maxFramebufferLayers;
+    VkSampleCountFlags    framebufferColorSampleCounts;
+    VkSampleCountFlags    framebufferDepthSampleCounts;
+    VkSampleCountFlags    framebufferStencilSampleCounts;
+    VkSampleCountFlags    framebufferNoAttachmentsSampleCounts;
+    uint32_t              maxColorAttachments;
+    VkSampleCountFlags    sampledImageColorSampleCounts;
+    VkSampleCountFlags    sampledImageIntegerSampleCounts;
+    VkSampleCountFlags    sampledImageDepthSampleCounts;
+    VkSampleCountFlags    sampledImageStencilSampleCounts;
+    VkSampleCountFlags    storageImageSampleCounts;
+    uint32_t              maxSampleMaskWords;
+    VkBool32              timestampComputeAndGraphics;
+    float                 timestampPeriod;
+    uint32_t              maxClipDistances;
+    uint32_t              maxCullDistances;
+    uint32_t              maxCombinedClipAndCullDistances;
+    uint32_t              discreteQueuePriorities;
+    float                 pointSizeRange[2];
+    float                 lineWidthRange[2];
+    float                 pointSizeGranularity;
+    float                 lineWidthGranularity;
+    VkBool32              strictLines;
+    VkBool32              standardSampleLocations;
+    VkDeviceSize          optimalBufferCopyOffsetAlignment;
+    VkDeviceSize          optimalBufferCopyRowPitchAlignment;
+    VkDeviceSize          nonCoherentAtomSize;
+} VkPhysicalDeviceLimits;
+
+typedef struct VkPhysicalDeviceSparseProperties {
+    VkBool32    residencyStandard2DBlockShape;
+    VkBool32    residencyStandard2DMultisampleBlockShape;
+    VkBool32    residencyStandard3DBlockShape;
+    VkBool32    residencyAlignedMipSize;
+    VkBool32    residencyNonResidentStrict;
+} VkPhysicalDeviceSparseProperties;
+
+typedef struct VkPhysicalDeviceProperties {
+    uint32_t                            apiVersion;
+    uint32_t                            driverVersion;
+    uint32_t                            vendorID;
+    uint32_t                            deviceID;
+    VkPhysicalDeviceType                deviceType;
+    char                                deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
+    uint8_t                             pipelineCacheUUID[VK_UUID_SIZE];
+    VkPhysicalDeviceLimits              limits;
+    VkPhysicalDeviceSparseProperties    sparseProperties;
+} VkPhysicalDeviceProperties;
+
+typedef struct VkQueueFamilyProperties {
+    VkQueueFlags    queueFlags;
+    uint32_t        queueCount;
+    uint32_t        timestampValidBits;
+    VkExtent3D      minImageTransferGranularity;
+} VkQueueFamilyProperties;
+
+typedef struct VkMemoryType {
+    VkMemoryPropertyFlags    propertyFlags;
+    uint32_t                 heapIndex;
+} VkMemoryType;
+
+typedef struct VkMemoryHeap {
+    VkDeviceSize         size;
+    VkMemoryHeapFlags    flags;
+} VkMemoryHeap;
+
+typedef struct VkPhysicalDeviceMemoryProperties {
+    uint32_t        memoryTypeCount;
+    VkMemoryType    memoryTypes[VK_MAX_MEMORY_TYPES];
+    uint32_t        memoryHeapCount;
+    VkMemoryHeap    memoryHeaps[VK_MAX_MEMORY_HEAPS];
+} VkPhysicalDeviceMemoryProperties;
+
+typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
+typedef struct VkDeviceQueueCreateInfo {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkDeviceQueueCreateFlags    flags;
+    uint32_t                    queueFamilyIndex;
+    uint32_t                    queueCount;
+    const float*                pQueuePriorities;
+} VkDeviceQueueCreateInfo;
+
+typedef struct VkDeviceCreateInfo {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkDeviceCreateFlags                flags;
+    uint32_t                           queueCreateInfoCount;
+    const VkDeviceQueueCreateInfo*     pQueueCreateInfos;
+    uint32_t                           enabledLayerCount;
+    const char* const*                 ppEnabledLayerNames;
+    uint32_t                           enabledExtensionCount;
+    const char* const*                 ppEnabledExtensionNames;
+    const VkPhysicalDeviceFeatures*    pEnabledFeatures;
+} VkDeviceCreateInfo;
+
+typedef struct VkExtensionProperties {
+    char        extensionName[VK_MAX_EXTENSION_NAME_SIZE];
+    uint32_t    specVersion;
+} VkExtensionProperties;
+
+typedef struct VkLayerProperties {
+    char        layerName[VK_MAX_EXTENSION_NAME_SIZE];
+    uint32_t    specVersion;
+    uint32_t    implementationVersion;
+    char        description[VK_MAX_DESCRIPTION_SIZE];
+} VkLayerProperties;
+
+typedef struct VkSubmitInfo {
+    VkStructureType                sType;
+    const void*                    pNext;
+    uint32_t                       waitSemaphoreCount;
+    const VkSemaphore*             pWaitSemaphores;
+    const VkPipelineStageFlags*    pWaitDstStageMask;
+    uint32_t                       commandBufferCount;
+    const VkCommandBuffer*         pCommandBuffers;
+    uint32_t                       signalSemaphoreCount;
+    const VkSemaphore*             pSignalSemaphores;
+} VkSubmitInfo;
+
+typedef struct VkMemoryAllocateInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkDeviceSize       allocationSize;
+    uint32_t           memoryTypeIndex;
+} VkMemoryAllocateInfo;
+
+typedef struct VkMappedMemoryRange {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkDeviceMemory     memory;
+    VkDeviceSize       offset;
+    VkDeviceSize       size;
+} VkMappedMemoryRange;
+
+typedef struct VkMemoryRequirements {
+    VkDeviceSize    size;
+    VkDeviceSize    alignment;
+    uint32_t        memoryTypeBits;
+} VkMemoryRequirements;
+
+typedef struct VkSparseImageFormatProperties {
+    VkImageAspectFlags          aspectMask;
+    VkExtent3D                  imageGranularity;
+    VkSparseImageFormatFlags    flags;
+} VkSparseImageFormatProperties;
+
+typedef struct VkSparseImageMemoryRequirements {
+    VkSparseImageFormatProperties    formatProperties;
+    uint32_t                         imageMipTailFirstLod;
+    VkDeviceSize                     imageMipTailSize;
+    VkDeviceSize                     imageMipTailOffset;
+    VkDeviceSize                     imageMipTailStride;
+} VkSparseImageMemoryRequirements;
+
+typedef struct VkSparseMemoryBind {
+    VkDeviceSize               resourceOffset;
+    VkDeviceSize               size;
+    VkDeviceMemory             memory;
+    VkDeviceSize               memoryOffset;
+    VkSparseMemoryBindFlags    flags;
+} VkSparseMemoryBind;
+
+typedef struct VkSparseBufferMemoryBindInfo {
+    VkBuffer                     buffer;
+    uint32_t                     bindCount;
+    const VkSparseMemoryBind*    pBinds;
+} VkSparseBufferMemoryBindInfo;
+
+typedef struct VkSparseImageOpaqueMemoryBindInfo {
+    VkImage                      image;
+    uint32_t                     bindCount;
+    const VkSparseMemoryBind*    pBinds;
+} VkSparseImageOpaqueMemoryBindInfo;
+
+typedef struct VkImageSubresource {
+    VkImageAspectFlags    aspectMask;
+    uint32_t              mipLevel;
+    uint32_t              arrayLayer;
+} VkImageSubresource;
+
+typedef struct VkOffset3D {
+    int32_t    x;
+    int32_t    y;
+    int32_t    z;
+} VkOffset3D;
+
+typedef struct VkSparseImageMemoryBind {
+    VkImageSubresource         subresource;
+    VkOffset3D                 offset;
+    VkExtent3D                 extent;
+    VkDeviceMemory             memory;
+    VkDeviceSize               memoryOffset;
+    VkSparseMemoryBindFlags    flags;
+} VkSparseImageMemoryBind;
+
+typedef struct VkSparseImageMemoryBindInfo {
+    VkImage                           image;
+    uint32_t                          bindCount;
+    const VkSparseImageMemoryBind*    pBinds;
+} VkSparseImageMemoryBindInfo;
+
+typedef struct VkBindSparseInfo {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    uint32_t                                    waitSemaphoreCount;
+    const VkSemaphore*                          pWaitSemaphores;
+    uint32_t                                    bufferBindCount;
+    const VkSparseBufferMemoryBindInfo*         pBufferBinds;
+    uint32_t                                    imageOpaqueBindCount;
+    const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds;
+    uint32_t                                    imageBindCount;
+    const VkSparseImageMemoryBindInfo*          pImageBinds;
+    uint32_t                                    signalSemaphoreCount;
+    const VkSemaphore*                          pSignalSemaphores;
+} VkBindSparseInfo;
+
+typedef struct VkFenceCreateInfo {
+    VkStructureType       sType;
+    const void*           pNext;
+    VkFenceCreateFlags    flags;
+} VkFenceCreateInfo;
+
+typedef struct VkSemaphoreCreateInfo {
+    VkStructureType           sType;
+    const void*               pNext;
+    VkSemaphoreCreateFlags    flags;
+} VkSemaphoreCreateInfo;
+
+typedef struct VkEventCreateInfo {
+    VkStructureType       sType;
+    const void*           pNext;
+    VkEventCreateFlags    flags;
+} VkEventCreateInfo;
+
+typedef struct VkQueryPoolCreateInfo {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkQueryPoolCreateFlags           flags;
+    VkQueryType                      queryType;
+    uint32_t                         queryCount;
+    VkQueryPipelineStatisticFlags    pipelineStatistics;
+} VkQueryPoolCreateInfo;
+
+typedef struct VkBufferCreateInfo {
+    VkStructureType        sType;
+    const void*            pNext;
+    VkBufferCreateFlags    flags;
+    VkDeviceSize           size;
+    VkBufferUsageFlags     usage;
+    VkSharingMode          sharingMode;
+    uint32_t               queueFamilyIndexCount;
+    const uint32_t*        pQueueFamilyIndices;
+} VkBufferCreateInfo;
+
+typedef struct VkBufferViewCreateInfo {
+    VkStructureType            sType;
+    const void*                pNext;
+    VkBufferViewCreateFlags    flags;
+    VkBuffer                   buffer;
+    VkFormat                   format;
+    VkDeviceSize               offset;
+    VkDeviceSize               range;
+} VkBufferViewCreateInfo;
+
+typedef struct VkImageCreateInfo {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkImageCreateFlags       flags;
+    VkImageType              imageType;
+    VkFormat                 format;
+    VkExtent3D               extent;
+    uint32_t                 mipLevels;
+    uint32_t                 arrayLayers;
+    VkSampleCountFlagBits    samples;
+    VkImageTiling            tiling;
+    VkImageUsageFlags        usage;
+    VkSharingMode            sharingMode;
+    uint32_t                 queueFamilyIndexCount;
+    const uint32_t*          pQueueFamilyIndices;
+    VkImageLayout            initialLayout;
+} VkImageCreateInfo;
+
+typedef struct VkSubresourceLayout {
+    VkDeviceSize    offset;
+    VkDeviceSize    size;
+    VkDeviceSize    rowPitch;
+    VkDeviceSize    arrayPitch;
+    VkDeviceSize    depthPitch;
+} VkSubresourceLayout;
+
+typedef struct VkComponentMapping {
+    VkComponentSwizzle    r;
+    VkComponentSwizzle    g;
+    VkComponentSwizzle    b;
+    VkComponentSwizzle    a;
+} VkComponentMapping;
+
+typedef struct VkImageSubresourceRange {
+    VkImageAspectFlags    aspectMask;
+    uint32_t              baseMipLevel;
+    uint32_t              levelCount;
+    uint32_t              baseArrayLayer;
+    uint32_t              layerCount;
+} VkImageSubresourceRange;
+
+typedef struct VkImageViewCreateInfo {
+    VkStructureType            sType;
+    const void*                pNext;
+    VkImageViewCreateFlags     flags;
+    VkImage                    image;
+    VkImageViewType            viewType;
+    VkFormat                   format;
+    VkComponentMapping         components;
+    VkImageSubresourceRange    subresourceRange;
+} VkImageViewCreateInfo;
+
+typedef struct VkShaderModuleCreateInfo {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkShaderModuleCreateFlags    flags;
+    size_t                       codeSize;
+    const uint32_t*              pCode;
+} VkShaderModuleCreateInfo;
+
+typedef struct VkPipelineCacheCreateInfo {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkPipelineCacheCreateFlags    flags;
+    size_t                        initialDataSize;
+    const void*                   pInitialData;
+} VkPipelineCacheCreateInfo;
+
+typedef struct VkSpecializationMapEntry {
+    uint32_t    constantID;
+    uint32_t    offset;
+    size_t      size;
+} VkSpecializationMapEntry;
+
+typedef struct VkSpecializationInfo {
+    uint32_t                           mapEntryCount;
+    const VkSpecializationMapEntry*    pMapEntries;
+    size_t                             dataSize;
+    const void*                        pData;
+} VkSpecializationInfo;
+
+typedef struct VkPipelineShaderStageCreateInfo {
+    VkStructureType                     sType;
+    const void*                         pNext;
+    VkPipelineShaderStageCreateFlags    flags;
+    VkShaderStageFlagBits               stage;
+    VkShaderModule                      module;
+    const char*                         pName;
+    const VkSpecializationInfo*         pSpecializationInfo;
+} VkPipelineShaderStageCreateInfo;
+
+typedef struct VkVertexInputBindingDescription {
+    uint32_t             binding;
+    uint32_t             stride;
+    VkVertexInputRate    inputRate;
+} VkVertexInputBindingDescription;
+
+typedef struct VkVertexInputAttributeDescription {
+    uint32_t    location;
+    uint32_t    binding;
+    VkFormat    format;
+    uint32_t    offset;
+} VkVertexInputAttributeDescription;
+
+typedef struct VkPipelineVertexInputStateCreateInfo {
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    VkPipelineVertexInputStateCreateFlags       flags;
+    uint32_t                                    vertexBindingDescriptionCount;
+    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
+    uint32_t                                    vertexAttributeDescriptionCount;
+    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
+} VkPipelineVertexInputStateCreateInfo;
+
+typedef struct VkPipelineInputAssemblyStateCreateInfo {
+    VkStructureType                            sType;
+    const void*                                pNext;
+    VkPipelineInputAssemblyStateCreateFlags    flags;
+    VkPrimitiveTopology                        topology;
+    VkBool32                                   primitiveRestartEnable;
+} VkPipelineInputAssemblyStateCreateInfo;
+
+typedef struct VkPipelineTessellationStateCreateInfo {
+    VkStructureType                           sType;
+    const void*                               pNext;
+    VkPipelineTessellationStateCreateFlags    flags;
+    uint32_t                                  patchControlPoints;
+} VkPipelineTessellationStateCreateInfo;
+
+typedef struct VkViewport {
+    float    x;
+    float    y;
+    float    width;
+    float    height;
+    float    minDepth;
+    float    maxDepth;
+} VkViewport;
+
+typedef struct VkOffset2D {
+    int32_t    x;
+    int32_t    y;
+} VkOffset2D;
+
+typedef struct VkExtent2D {
+    uint32_t    width;
+    uint32_t    height;
+} VkExtent2D;
+
+typedef struct VkRect2D {
+    VkOffset2D    offset;
+    VkExtent2D    extent;
+} VkRect2D;
+
+typedef struct VkPipelineViewportStateCreateInfo {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkPipelineViewportStateCreateFlags    flags;
+    uint32_t                              viewportCount;
+    const VkViewport*                     pViewports;
+    uint32_t                              scissorCount;
+    const VkRect2D*                       pScissors;
+} VkPipelineViewportStateCreateInfo;
+
+typedef struct VkPipelineRasterizationStateCreateInfo {
+    VkStructureType                            sType;
+    const void*                                pNext;
+    VkPipelineRasterizationStateCreateFlags    flags;
+    VkBool32                                   depthClampEnable;
+    VkBool32                                   rasterizerDiscardEnable;
+    VkPolygonMode                              polygonMode;
+    VkCullModeFlags                            cullMode;
+    VkFrontFace                                frontFace;
+    VkBool32                                   depthBiasEnable;
+    float                                      depthBiasConstantFactor;
+    float                                      depthBiasClamp;
+    float                                      depthBiasSlopeFactor;
+    float                                      lineWidth;
+} VkPipelineRasterizationStateCreateInfo;
+
+typedef struct VkPipelineMultisampleStateCreateInfo {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkPipelineMultisampleStateCreateFlags    flags;
+    VkSampleCountFlagBits                    rasterizationSamples;
+    VkBool32                                 sampleShadingEnable;
+    float                                    minSampleShading;
+    const VkSampleMask*                      pSampleMask;
+    VkBool32                                 alphaToCoverageEnable;
+    VkBool32                                 alphaToOneEnable;
+} VkPipelineMultisampleStateCreateInfo;
+
+typedef struct VkStencilOpState {
+    VkStencilOp    failOp;
+    VkStencilOp    passOp;
+    VkStencilOp    depthFailOp;
+    VkCompareOp    compareOp;
+    uint32_t       compareMask;
+    uint32_t       writeMask;
+    uint32_t       reference;
+} VkStencilOpState;
+
+typedef struct VkPipelineDepthStencilStateCreateInfo {
+    VkStructureType                           sType;
+    const void*                               pNext;
+    VkPipelineDepthStencilStateCreateFlags    flags;
+    VkBool32                                  depthTestEnable;
+    VkBool32                                  depthWriteEnable;
+    VkCompareOp                               depthCompareOp;
+    VkBool32                                  depthBoundsTestEnable;
+    VkBool32                                  stencilTestEnable;
+    VkStencilOpState                          front;
+    VkStencilOpState                          back;
+    float                                     minDepthBounds;
+    float                                     maxDepthBounds;
+} VkPipelineDepthStencilStateCreateInfo;
+
+typedef struct VkPipelineColorBlendAttachmentState {
+    VkBool32                 blendEnable;
+    VkBlendFactor            srcColorBlendFactor;
+    VkBlendFactor            dstColorBlendFactor;
+    VkBlendOp                colorBlendOp;
+    VkBlendFactor            srcAlphaBlendFactor;
+    VkBlendFactor            dstAlphaBlendFactor;
+    VkBlendOp                alphaBlendOp;
+    VkColorComponentFlags    colorWriteMask;
+} VkPipelineColorBlendAttachmentState;
+
+typedef struct VkPipelineColorBlendStateCreateInfo {
+    VkStructureType                               sType;
+    const void*                                   pNext;
+    VkPipelineColorBlendStateCreateFlags          flags;
+    VkBool32                                      logicOpEnable;
+    VkLogicOp                                     logicOp;
+    uint32_t                                      attachmentCount;
+    const VkPipelineColorBlendAttachmentState*    pAttachments;
+    float                                         blendConstants[4];
+} VkPipelineColorBlendStateCreateInfo;
+
+typedef struct VkPipelineDynamicStateCreateInfo {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkPipelineDynamicStateCreateFlags    flags;
+    uint32_t                             dynamicStateCount;
+    const VkDynamicState*                pDynamicStates;
+} VkPipelineDynamicStateCreateInfo;
+
+typedef struct VkGraphicsPipelineCreateInfo {
+    VkStructureType                                  sType;
+    const void*                                      pNext;
+    VkPipelineCreateFlags                            flags;
+    uint32_t                                         stageCount;
+    const VkPipelineShaderStageCreateInfo*           pStages;
+    const VkPipelineVertexInputStateCreateInfo*      pVertexInputState;
+    const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState;
+    const VkPipelineTessellationStateCreateInfo*     pTessellationState;
+    const VkPipelineViewportStateCreateInfo*         pViewportState;
+    const VkPipelineRasterizationStateCreateInfo*    pRasterizationState;
+    const VkPipelineMultisampleStateCreateInfo*      pMultisampleState;
+    const VkPipelineDepthStencilStateCreateInfo*     pDepthStencilState;
+    const VkPipelineColorBlendStateCreateInfo*       pColorBlendState;
+    const VkPipelineDynamicStateCreateInfo*          pDynamicState;
+    VkPipelineLayout                                 layout;
+    VkRenderPass                                     renderPass;
+    uint32_t                                         subpass;
+    VkPipeline                                       basePipelineHandle;
+    int32_t                                          basePipelineIndex;
+} VkGraphicsPipelineCreateInfo;
+
+typedef struct VkComputePipelineCreateInfo {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkPipelineCreateFlags              flags;
+    VkPipelineShaderStageCreateInfo    stage;
+    VkPipelineLayout                   layout;
+    VkPipeline                         basePipelineHandle;
+    int32_t                            basePipelineIndex;
+} VkComputePipelineCreateInfo;
+
+typedef struct VkPushConstantRange {
+    VkShaderStageFlags    stageFlags;
+    uint32_t              offset;
+    uint32_t              size;
+} VkPushConstantRange;
+
+typedef struct VkPipelineLayoutCreateInfo {
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkPipelineLayoutCreateFlags     flags;
+    uint32_t                        setLayoutCount;
+    const VkDescriptorSetLayout*    pSetLayouts;
+    uint32_t                        pushConstantRangeCount;
+    const VkPushConstantRange*      pPushConstantRanges;
+} VkPipelineLayoutCreateInfo;
+
+typedef struct VkSamplerCreateInfo {
+    VkStructureType         sType;
+    const void*             pNext;
+    VkSamplerCreateFlags    flags;
+    VkFilter                magFilter;
+    VkFilter                minFilter;
+    VkSamplerMipmapMode     mipmapMode;
+    VkSamplerAddressMode    addressModeU;
+    VkSamplerAddressMode    addressModeV;
+    VkSamplerAddressMode    addressModeW;
+    float                   mipLodBias;
+    VkBool32                anisotropyEnable;
+    float                   maxAnisotropy;
+    VkBool32                compareEnable;
+    VkCompareOp             compareOp;
+    float                   minLod;
+    float                   maxLod;
+    VkBorderColor           borderColor;
+    VkBool32                unnormalizedCoordinates;
+} VkSamplerCreateInfo;
+
+typedef struct VkDescriptorSetLayoutBinding {
+    uint32_t              binding;
+    VkDescriptorType      descriptorType;
+    uint32_t              descriptorCount;
+    VkShaderStageFlags    stageFlags;
+    const VkSampler*      pImmutableSamplers;
+} VkDescriptorSetLayoutBinding;
+
+typedef struct VkDescriptorSetLayoutCreateInfo {
+    VkStructureType                        sType;
+    const void*                            pNext;
+    VkDescriptorSetLayoutCreateFlags       flags;
+    uint32_t                               bindingCount;
+    const VkDescriptorSetLayoutBinding*    pBindings;
+} VkDescriptorSetLayoutCreateInfo;
+
+typedef struct VkDescriptorPoolSize {
+    VkDescriptorType    type;
+    uint32_t            descriptorCount;
+} VkDescriptorPoolSize;
+
+typedef struct VkDescriptorPoolCreateInfo {
+    VkStructureType                sType;
+    const void*                    pNext;
+    VkDescriptorPoolCreateFlags    flags;
+    uint32_t                       maxSets;
+    uint32_t                       poolSizeCount;
+    const VkDescriptorPoolSize*    pPoolSizes;
+} VkDescriptorPoolCreateInfo;
+
+typedef struct VkDescriptorSetAllocateInfo {
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkDescriptorPool                descriptorPool;
+    uint32_t                        descriptorSetCount;
+    const VkDescriptorSetLayout*    pSetLayouts;
+} VkDescriptorSetAllocateInfo;
+
+typedef struct VkDescriptorImageInfo {
+    VkSampler        sampler;
+    VkImageView      imageView;
+    VkImageLayout    imageLayout;
+} VkDescriptorImageInfo;
+
+typedef struct VkDescriptorBufferInfo {
+    VkBuffer        buffer;
+    VkDeviceSize    offset;
+    VkDeviceSize    range;
+} VkDescriptorBufferInfo;
+
+typedef struct VkWriteDescriptorSet {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkDescriptorSet                  dstSet;
+    uint32_t                         dstBinding;
+    uint32_t                         dstArrayElement;
+    uint32_t                         descriptorCount;
+    VkDescriptorType                 descriptorType;
+    const VkDescriptorImageInfo*     pImageInfo;
+    const VkDescriptorBufferInfo*    pBufferInfo;
+    const VkBufferView*              pTexelBufferView;
+} VkWriteDescriptorSet;
+
+typedef struct VkCopyDescriptorSet {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkDescriptorSet    srcSet;
+    uint32_t           srcBinding;
+    uint32_t           srcArrayElement;
+    VkDescriptorSet    dstSet;
+    uint32_t           dstBinding;
+    uint32_t           dstArrayElement;
+    uint32_t           descriptorCount;
+} VkCopyDescriptorSet;
+
+typedef struct VkFramebufferCreateInfo {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkFramebufferCreateFlags    flags;
+    VkRenderPass                renderPass;
+    uint32_t                    attachmentCount;
+    const VkImageView*          pAttachments;
+    uint32_t                    width;
+    uint32_t                    height;
+    uint32_t                    layers;
+} VkFramebufferCreateInfo;
+
+typedef struct VkAttachmentDescription {
+    VkAttachmentDescriptionFlags    flags;
+    VkFormat                        format;
+    VkSampleCountFlagBits           samples;
+    VkAttachmentLoadOp              loadOp;
+    VkAttachmentStoreOp             storeOp;
+    VkAttachmentLoadOp              stencilLoadOp;
+    VkAttachmentStoreOp             stencilStoreOp;
+    VkImageLayout                   initialLayout;
+    VkImageLayout                   finalLayout;
+} VkAttachmentDescription;
+
+typedef struct VkAttachmentReference {
+    uint32_t         attachment;
+    VkImageLayout    layout;
+} VkAttachmentReference;
+
+typedef struct VkSubpassDescription {
+    VkSubpassDescriptionFlags       flags;
+    VkPipelineBindPoint             pipelineBindPoint;
+    uint32_t                        inputAttachmentCount;
+    const VkAttachmentReference*    pInputAttachments;
+    uint32_t                        colorAttachmentCount;
+    const VkAttachmentReference*    pColorAttachments;
+    const VkAttachmentReference*    pResolveAttachments;
+    const VkAttachmentReference*    pDepthStencilAttachment;
+    uint32_t                        preserveAttachmentCount;
+    const uint32_t*                 pPreserveAttachments;
+} VkSubpassDescription;
+
+typedef struct VkSubpassDependency {
+    uint32_t                srcSubpass;
+    uint32_t                dstSubpass;
+    VkPipelineStageFlags    srcStageMask;
+    VkPipelineStageFlags    dstStageMask;
+    VkAccessFlags           srcAccessMask;
+    VkAccessFlags           dstAccessMask;
+    VkDependencyFlags       dependencyFlags;
+} VkSubpassDependency;
+
+typedef struct VkRenderPassCreateInfo {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkRenderPassCreateFlags           flags;
+    uint32_t                          attachmentCount;
+    const VkAttachmentDescription*    pAttachments;
+    uint32_t                          subpassCount;
+    const VkSubpassDescription*       pSubpasses;
+    uint32_t                          dependencyCount;
+    const VkSubpassDependency*        pDependencies;
+} VkRenderPassCreateInfo;
+
+typedef struct VkCommandPoolCreateInfo {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkCommandPoolCreateFlags    flags;
+    uint32_t                    queueFamilyIndex;
+} VkCommandPoolCreateInfo;
+
+typedef struct VkCommandBufferAllocateInfo {
+    VkStructureType         sType;
+    const void*             pNext;
+    VkCommandPool           commandPool;
+    VkCommandBufferLevel    level;
+    uint32_t                commandBufferCount;
+} VkCommandBufferAllocateInfo;
+
+typedef struct VkCommandBufferInheritanceInfo {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkRenderPass                     renderPass;
+    uint32_t                         subpass;
+    VkFramebuffer                    framebuffer;
+    VkBool32                         occlusionQueryEnable;
+    VkQueryControlFlags              queryFlags;
+    VkQueryPipelineStatisticFlags    pipelineStatistics;
+} VkCommandBufferInheritanceInfo;
+
+typedef struct VkCommandBufferBeginInfo {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkCommandBufferUsageFlags                flags;
+    const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
+} VkCommandBufferBeginInfo;
+
+typedef struct VkBufferCopy {
+    VkDeviceSize    srcOffset;
+    VkDeviceSize    dstOffset;
+    VkDeviceSize    size;
+} VkBufferCopy;
+
+typedef struct VkImageSubresourceLayers {
+    VkImageAspectFlags    aspectMask;
+    uint32_t              mipLevel;
+    uint32_t              baseArrayLayer;
+    uint32_t              layerCount;
+} VkImageSubresourceLayers;
+
+typedef struct VkImageCopy {
+    VkImageSubresourceLayers    srcSubresource;
+    VkOffset3D                  srcOffset;
+    VkImageSubresourceLayers    dstSubresource;
+    VkOffset3D                  dstOffset;
+    VkExtent3D                  extent;
+} VkImageCopy;
+
+typedef struct VkImageBlit {
+    VkImageSubresourceLayers    srcSubresource;
+    VkOffset3D                  srcOffsets[2];
+    VkImageSubresourceLayers    dstSubresource;
+    VkOffset3D                  dstOffsets[2];
+} VkImageBlit;
+
+typedef struct VkBufferImageCopy {
+    VkDeviceSize                bufferOffset;
+    uint32_t                    bufferRowLength;
+    uint32_t                    bufferImageHeight;
+    VkImageSubresourceLayers    imageSubresource;
+    VkOffset3D                  imageOffset;
+    VkExtent3D                  imageExtent;
+} VkBufferImageCopy;
+
+typedef union VkClearColorValue {
+    float       float32[4];
+    int32_t     int32[4];
+    uint32_t    uint32[4];
+} VkClearColorValue;
+
+typedef struct VkClearDepthStencilValue {
+    float       depth;
+    uint32_t    stencil;
+} VkClearDepthStencilValue;
+
+typedef union VkClearValue {
+    VkClearColorValue           color;
+    VkClearDepthStencilValue    depthStencil;
+} VkClearValue;
+
+typedef struct VkClearAttachment {
+    VkImageAspectFlags    aspectMask;
+    uint32_t              colorAttachment;
+    VkClearValue          clearValue;
+} VkClearAttachment;
+
+typedef struct VkClearRect {
+    VkRect2D    rect;
+    uint32_t    baseArrayLayer;
+    uint32_t    layerCount;
+} VkClearRect;
+
+typedef struct VkImageResolve {
+    VkImageSubresourceLayers    srcSubresource;
+    VkOffset3D                  srcOffset;
+    VkImageSubresourceLayers    dstSubresource;
+    VkOffset3D                  dstOffset;
+    VkExtent3D                  extent;
+} VkImageResolve;
+
+typedef struct VkMemoryBarrier {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkAccessFlags      srcAccessMask;
+    VkAccessFlags      dstAccessMask;
+} VkMemoryBarrier;
+
+typedef struct VkBufferMemoryBarrier {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkAccessFlags      srcAccessMask;
+    VkAccessFlags      dstAccessMask;
+    uint32_t           srcQueueFamilyIndex;
+    uint32_t           dstQueueFamilyIndex;
+    VkBuffer           buffer;
+    VkDeviceSize       offset;
+    VkDeviceSize       size;
+} VkBufferMemoryBarrier;
+
+typedef struct VkImageMemoryBarrier {
+    VkStructureType            sType;
+    const void*                pNext;
+    VkAccessFlags              srcAccessMask;
+    VkAccessFlags              dstAccessMask;
+    VkImageLayout              oldLayout;
+    VkImageLayout              newLayout;
+    uint32_t                   srcQueueFamilyIndex;
+    uint32_t                   dstQueueFamilyIndex;
+    VkImage                    image;
+    VkImageSubresourceRange    subresourceRange;
+} VkImageMemoryBarrier;
+
+typedef struct VkRenderPassBeginInfo {
+    VkStructureType        sType;
+    const void*            pNext;
+    VkRenderPass           renderPass;
+    VkFramebuffer          framebuffer;
+    VkRect2D               renderArea;
+    uint32_t               clearValueCount;
+    const VkClearValue*    pClearValues;
+} VkRenderPassBeginInfo;
+
+typedef struct VkDispatchIndirectCommand {
+    uint32_t    x;
+    uint32_t    y;
+    uint32_t    z;
+} VkDispatchIndirectCommand;
+
+typedef struct VkDrawIndexedIndirectCommand {
+    uint32_t    indexCount;
+    uint32_t    instanceCount;
+    uint32_t    firstIndex;
+    int32_t     vertexOffset;
+    uint32_t    firstInstance;
+} VkDrawIndexedIndirectCommand;
+
+typedef struct VkDrawIndirectCommand {
+    uint32_t    vertexCount;
+    uint32_t    instanceCount;
+    uint32_t    firstVertex;
+    uint32_t    firstInstance;
+} VkDrawIndirectCommand;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
+typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties);
+typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName);
+typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
+typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
+typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue);
+typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device);
+typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory);
+typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData);
+typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory);
+typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);
+typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes);
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset);
+typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences);
+typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence);
+typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore);
+typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent);
+typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event);
+typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event);
+typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
+typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
+typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
+typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage);
+typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView);
+typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule);
+typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache);
+typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData);
+typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout);
+typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler);
+typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags);
+typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets);
+typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer);
+typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool);
+typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);
+typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
+typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer);
+typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);
+typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
+typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports);
+typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors);
+typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor);
+typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds);
+typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask);
+typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask);
+typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference);
+typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType);
+typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
+typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
+typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
+typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
+typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
+typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects);
+typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions);
+typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);
+typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags);
+typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query);
+typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags);
+typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);
+typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents);
+typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer);
+typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
+    const VkInstanceCreateInfo*                 pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkInstance*                                 pInstance);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(
+    VkInstance                                  instance,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
+    VkInstance                                  instance,
+    uint32_t*                                   pPhysicalDeviceCount,
+    VkPhysicalDevice*                           pPhysicalDevices);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures*                   pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties*                         pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    VkImageTiling                               tiling,
+    VkImageUsageFlags                           usage,
+    VkImageCreateFlags                          flags,
+    VkImageFormatProperties*                    pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties*                 pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties*                    pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties*           pMemoryProperties);
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(
+    VkInstance                                  instance,
+    const char*                                 pName);
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(
+    VkDevice                                    device,
+    const char*                                 pName);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(
+    VkPhysicalDevice                            physicalDevice,
+    const VkDeviceCreateInfo*                   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDevice*                                   pDevice);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(
+    VkDevice                                    device,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(
+    const char*                                 pLayerName,
+    uint32_t*                                   pPropertyCount,
+    VkExtensionProperties*                      pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const char*                                 pLayerName,
+    uint32_t*                                   pPropertyCount,
+    VkExtensionProperties*                      pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(
+    uint32_t*                                   pPropertyCount,
+    VkLayerProperties*                          pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pPropertyCount,
+    VkLayerProperties*                          pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
+    VkDevice                                    device,
+    uint32_t                                    queueFamilyIndex,
+    uint32_t                                    queueIndex,
+    VkQueue*                                    pQueue);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(
+    VkQueue                                     queue,
+    uint32_t                                    submitCount,
+    const VkSubmitInfo*                         pSubmits,
+    VkFence                                     fence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(
+    VkQueue                                     queue);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(
+    VkDevice                                    device);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(
+    VkDevice                                    device,
+    const VkMemoryAllocateInfo*                 pAllocateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDeviceMemory*                             pMemory);
+
+VKAPI_ATTR void VKAPI_CALL vkFreeMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              memory,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              memory,
+    VkDeviceSize                                offset,
+    VkDeviceSize                                size,
+    VkMemoryMapFlags                            flags,
+    void**                                      ppData);
+
+VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(
+    VkDevice                                    device,
+    VkDeviceMemory                              memory);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(
+    VkDevice                                    device,
+    uint32_t                                    memoryRangeCount,
+    const VkMappedMemoryRange*                  pMemoryRanges);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(
+    VkDevice                                    device,
+    uint32_t                                    memoryRangeCount,
+    const VkMappedMemoryRange*                  pMemoryRanges);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment(
+    VkDevice                                    device,
+    VkDeviceMemory                              memory,
+    VkDeviceSize*                               pCommittedMemoryInBytes);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(
+    VkDevice                                    device,
+    VkBuffer                                    buffer,
+    VkDeviceMemory                              memory,
+    VkDeviceSize                                memoryOffset);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkDeviceMemory                              memory,
+    VkDeviceSize                                memoryOffset);
+
+VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(
+    VkDevice                                    device,
+    VkBuffer                                    buffer,
+    VkMemoryRequirements*                       pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkMemoryRequirements*                       pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements(
+    VkDevice                                    device,
+    VkImage                                     image,
+    uint32_t*                                   pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements*            pSparseMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    VkSampleCountFlagBits                       samples,
+    VkImageUsageFlags                           usage,
+    VkImageTiling                               tiling,
+    uint32_t*                                   pPropertyCount,
+    VkSparseImageFormatProperties*              pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse(
+    VkQueue                                     queue,
+    uint32_t                                    bindInfoCount,
+    const VkBindSparseInfo*                     pBindInfo,
+    VkFence                                     fence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence(
+    VkDevice                                    device,
+    const VkFenceCreateInfo*                    pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFence*                                    pFence);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyFence(
+    VkDevice                                    device,
+    VkFence                                     fence,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(
+    VkDevice                                    device,
+    uint32_t                                    fenceCount,
+    const VkFence*                              pFences);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(
+    VkDevice                                    device,
+    VkFence                                     fence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(
+    VkDevice                                    device,
+    uint32_t                                    fenceCount,
+    const VkFence*                              pFences,
+    VkBool32                                    waitAll,
+    uint64_t                                    timeout);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(
+    VkDevice                                    device,
+    const VkSemaphoreCreateInfo*                pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSemaphore*                                pSemaphore);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(
+    VkDevice                                    device,
+    VkSemaphore                                 semaphore,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent(
+    VkDevice                                    device,
+    const VkEventCreateInfo*                    pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkEvent*                                    pEvent);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(
+    VkDevice                                    device,
+    VkEvent                                     event,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent(
+    VkDevice                                    device,
+    VkEvent                                     event);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(
+    VkDevice                                    device,
+    const VkQueryPoolCreateInfo*                pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkQueryPool*                                pQueryPool);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool(
+    VkDevice                                    device,
+    VkQueryPool                                 queryPool,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(
+    VkDevice                                    device,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    firstQuery,
+    uint32_t                                    queryCount,
+    size_t                                      dataSize,
+    void*                                       pData,
+    VkDeviceSize                                stride,
+    VkQueryResultFlags                          flags);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(
+    VkDevice                                    device,
+    const VkBufferCreateInfo*                   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkBuffer*                                   pBuffer);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(
+    VkDevice                                    device,
+    VkBuffer                                    buffer,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(
+    VkDevice                                    device,
+    const VkBufferViewCreateInfo*               pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkBufferView*                               pView);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(
+    VkDevice                                    device,
+    VkBufferView                                bufferView,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(
+    VkDevice                                    device,
+    const VkImageCreateInfo*                    pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkImage*                                    pImage);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyImage(
+    VkDevice                                    device,
+    VkImage                                     image,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout(
+    VkDevice                                    device,
+    VkImage                                     image,
+    const VkImageSubresource*                   pSubresource,
+    VkSubresourceLayout*                        pLayout);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(
+    VkDevice                                    device,
+    const VkImageViewCreateInfo*                pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkImageView*                                pView);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyImageView(
+    VkDevice                                    device,
+    VkImageView                                 imageView,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(
+    VkDevice                                    device,
+    const VkShaderModuleCreateInfo*             pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkShaderModule*                             pShaderModule);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule(
+    VkDevice                                    device,
+    VkShaderModule                              shaderModule,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(
+    VkDevice                                    device,
+    const VkPipelineCacheCreateInfo*            pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipelineCache*                            pPipelineCache);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    size_t*                                     pDataSize,
+    void*                                       pData);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches(
+    VkDevice                                    device,
+    VkPipelineCache                             dstCache,
+    uint32_t                                    srcCacheCount,
+    const VkPipelineCache*                      pSrcCaches);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    createInfoCount,
+    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipeline*                                 pPipelines);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    createInfoCount,
+    const VkComputePipelineCreateInfo*          pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipeline*                                 pPipelines);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(
+    VkDevice                                    device,
+    VkPipeline                                  pipeline,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(
+    VkDevice                                    device,
+    const VkPipelineLayoutCreateInfo*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkPipelineLayout*                           pPipelineLayout);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout(
+    VkDevice                                    device,
+    VkPipelineLayout                            pipelineLayout,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(
+    VkDevice                                    device,
+    const VkSamplerCreateInfo*                  pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSampler*                                  pSampler);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySampler(
+    VkDevice                                    device,
+    VkSampler                                   sampler,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(
+    VkDevice                                    device,
+    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDescriptorSetLayout*                      pSetLayout);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout(
+    VkDevice                                    device,
+    VkDescriptorSetLayout                       descriptorSetLayout,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool(
+    VkDevice                                    device,
+    const VkDescriptorPoolCreateInfo*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDescriptorPool*                           pDescriptorPool);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool,
+    VkDescriptorPoolResetFlags                  flags);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets(
+    VkDevice                                    device,
+    const VkDescriptorSetAllocateInfo*          pAllocateInfo,
+    VkDescriptorSet*                            pDescriptorSets);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets(
+    VkDevice                                    device,
+    VkDescriptorPool                            descriptorPool,
+    uint32_t                                    descriptorSetCount,
+    const VkDescriptorSet*                      pDescriptorSets);
+
+VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets(
+    VkDevice                                    device,
+    uint32_t                                    descriptorWriteCount,
+    const VkWriteDescriptorSet*                 pDescriptorWrites,
+    uint32_t                                    descriptorCopyCount,
+    const VkCopyDescriptorSet*                  pDescriptorCopies);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(
+    VkDevice                                    device,
+    const VkFramebufferCreateInfo*              pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFramebuffer*                              pFramebuffer);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer(
+    VkDevice                                    device,
+    VkFramebuffer                               framebuffer,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(
+    VkDevice                                    device,
+    const VkRenderPassCreateInfo*               pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkRenderPass*                               pRenderPass);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass(
+    VkDevice                                    device,
+    VkRenderPass                                renderPass,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity(
+    VkDevice                                    device,
+    VkRenderPass                                renderPass,
+    VkExtent2D*                                 pGranularity);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(
+    VkDevice                                    device,
+    const VkCommandPoolCreateInfo*              pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkCommandPool*                              pCommandPool);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    VkCommandPoolResetFlags                     flags);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(
+    VkDevice                                    device,
+    const VkCommandBufferAllocateInfo*          pAllocateInfo,
+    VkCommandBuffer*                            pCommandBuffers);
+
+VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    uint32_t                                    commandBufferCount,
+    const VkCommandBuffer*                      pCommandBuffers);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(
+    VkCommandBuffer                             commandBuffer,
+    const VkCommandBufferBeginInfo*             pBeginInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(
+    VkCommandBuffer                             commandBuffer);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkCommandBufferResetFlags                   flags);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineBindPoint                         pipelineBindPoint,
+    VkPipeline                                  pipeline);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstViewport,
+    uint32_t                                    viewportCount,
+    const VkViewport*                           pViewports);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstScissor,
+    uint32_t                                    scissorCount,
+    const VkRect2D*                             pScissors);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(
+    VkCommandBuffer                             commandBuffer,
+    float                                       lineWidth);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias(
+    VkCommandBuffer                             commandBuffer,
+    float                                       depthBiasConstantFactor,
+    float                                       depthBiasClamp,
+    float                                       depthBiasSlopeFactor);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(
+    VkCommandBuffer                             commandBuffer,
+    const float                                 blendConstants[4]);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds(
+    VkCommandBuffer                             commandBuffer,
+    float                                       minDepthBounds,
+    float                                       maxDepthBounds);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask(
+    VkCommandBuffer                             commandBuffer,
+    VkStencilFaceFlags                          faceMask,
+    uint32_t                                    compareMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask(
+    VkCommandBuffer                             commandBuffer,
+    VkStencilFaceFlags                          faceMask,
+    uint32_t                                    writeMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference(
+    VkCommandBuffer                             commandBuffer,
+    VkStencilFaceFlags                          faceMask,
+    uint32_t                                    reference);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineBindPoint                         pipelineBindPoint,
+    VkPipelineLayout                            layout,
+    uint32_t                                    firstSet,
+    uint32_t                                    descriptorSetCount,
+    const VkDescriptorSet*                      pDescriptorSets,
+    uint32_t                                    dynamicOffsetCount,
+    const uint32_t*                             pDynamicOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    VkIndexType                                 indexType);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstBinding,
+    uint32_t                                    bindingCount,
+    const VkBuffer*                             pBuffers,
+    const VkDeviceSize*                         pOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDraw(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    vertexCount,
+    uint32_t                                    instanceCount,
+    uint32_t                                    firstVertex,
+    uint32_t                                    firstInstance);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    indexCount,
+    uint32_t                                    instanceCount,
+    uint32_t                                    firstIndex,
+    int32_t                                     vertexOffset,
+    uint32_t                                    firstInstance);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    uint32_t                                    drawCount,
+    uint32_t                                    stride);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    uint32_t                                    drawCount,
+    uint32_t                                    stride);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    groupCountX,
+    uint32_t                                    groupCountY,
+    uint32_t                                    groupCountZ);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    srcBuffer,
+    VkBuffer                                    dstBuffer,
+    uint32_t                                    regionCount,
+    const VkBufferCopy*                         pRegions);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     dstImage,
+    VkImageLayout                               dstImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageCopy*                          pRegions);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     dstImage,
+    VkImageLayout                               dstImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageBlit*                          pRegions,
+    VkFilter                                    filter);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    srcBuffer,
+    VkImage                                     dstImage,
+    VkImageLayout                               dstImageLayout,
+    uint32_t                                    regionCount,
+    const VkBufferImageCopy*                    pRegions);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkBuffer                                    dstBuffer,
+    uint32_t                                    regionCount,
+    const VkBufferImageCopy*                    pRegions);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    dstBuffer,
+    VkDeviceSize                                dstOffset,
+    VkDeviceSize                                dataSize,
+    const void*                                 pData);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    dstBuffer,
+    VkDeviceSize                                dstOffset,
+    VkDeviceSize                                size,
+    uint32_t                                    data);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     image,
+    VkImageLayout                               imageLayout,
+    const VkClearColorValue*                    pColor,
+    uint32_t                                    rangeCount,
+    const VkImageSubresourceRange*              pRanges);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     image,
+    VkImageLayout                               imageLayout,
+    const VkClearDepthStencilValue*             pDepthStencil,
+    uint32_t                                    rangeCount,
+    const VkImageSubresourceRange*              pRanges);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    attachmentCount,
+    const VkClearAttachment*                    pAttachments,
+    uint32_t                                    rectCount,
+    const VkClearRect*                          pRects);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage(
+    VkCommandBuffer                             commandBuffer,
+    VkImage                                     srcImage,
+    VkImageLayout                               srcImageLayout,
+    VkImage                                     dstImage,
+    VkImageLayout                               dstImageLayout,
+    uint32_t                                    regionCount,
+    const VkImageResolve*                       pRegions);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent(
+    VkCommandBuffer                             commandBuffer,
+    VkEvent                                     event,
+    VkPipelineStageFlags                        stageMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent(
+    VkCommandBuffer                             commandBuffer,
+    VkEvent                                     event,
+    VkPipelineStageFlags                        stageMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdWaitEvents(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    eventCount,
+    const VkEvent*                              pEvents,
+    VkPipelineStageFlags                        srcStageMask,
+    VkPipelineStageFlags                        dstStageMask,
+    uint32_t                                    memoryBarrierCount,
+    const VkMemoryBarrier*                      pMemoryBarriers,
+    uint32_t                                    bufferMemoryBarrierCount,
+    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
+    uint32_t                                    imageMemoryBarrierCount,
+    const VkImageMemoryBarrier*                 pImageMemoryBarriers);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineStageFlags                        srcStageMask,
+    VkPipelineStageFlags                        dstStageMask,
+    VkDependencyFlags                           dependencyFlags,
+    uint32_t                                    memoryBarrierCount,
+    const VkMemoryBarrier*                      pMemoryBarriers,
+    uint32_t                                    bufferMemoryBarrierCount,
+    const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
+    uint32_t                                    imageMemoryBarrierCount,
+    const VkImageMemoryBarrier*                 pImageMemoryBarriers);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query,
+    VkQueryControlFlags                         flags);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    firstQuery,
+    uint32_t                                    queryCount);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineStageFlagBits                     pipelineStage,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    firstQuery,
+    uint32_t                                    queryCount,
+    VkBuffer                                    dstBuffer,
+    VkDeviceSize                                dstOffset,
+    VkDeviceSize                                stride,
+    VkQueryResultFlags                          flags);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineLayout                            layout,
+    VkShaderStageFlags                          stageFlags,
+    uint32_t                                    offset,
+    uint32_t                                    size,
+    const void*                                 pValues);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass(
+    VkCommandBuffer                             commandBuffer,
+    const VkRenderPassBeginInfo*                pRenderPassBegin,
+    VkSubpassContents                           contents);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(
+    VkCommandBuffer                             commandBuffer,
+    VkSubpassContents                           contents);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(
+    VkCommandBuffer                             commandBuffer);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    commandBufferCount,
+    const VkCommandBuffer*                      pCommandBuffers);
+#endif
+
+#define VK_VERSION_1_1 1
+// Vulkan 1.1 version number
+#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)// Patch version should always be set to 0
+
+
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate)
+
+#define VK_MAX_DEVICE_GROUP_SIZE          32
+#define VK_LUID_SIZE                      8
+#define VK_QUEUE_FAMILY_EXTERNAL          (~0U-1)
+
+
+typedef enum VkPointClippingBehavior {
+    VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
+    VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
+    VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
+    VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY,
+    VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
+    VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY,
+    VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1),
+    VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF
+} VkPointClippingBehavior;
+
+typedef enum VkTessellationDomainOrigin {
+    VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0,
+    VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1,
+    VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
+    VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
+    VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
+    VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
+    VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1),
+    VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF
+} VkTessellationDomainOrigin;
+
+typedef enum VkSamplerYcbcrModelConversion {
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1),
+    VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerYcbcrModelConversion;
+
+typedef enum VkSamplerYcbcrRange {
+    VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
+    VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
+    VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
+    VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
+    VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
+    VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
+    VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1),
+    VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF
+} VkSamplerYcbcrRange;
+
+typedef enum VkChromaLocation {
+    VK_CHROMA_LOCATION_COSITED_EVEN = 0,
+    VK_CHROMA_LOCATION_MIDPOINT = 1,
+    VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN,
+    VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT,
+    VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN,
+    VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT,
+    VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1),
+    VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF
+} VkChromaLocation;
+
+typedef enum VkDescriptorUpdateTemplateType {
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1),
+    VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorUpdateTemplateType;
+
+
+typedef enum VkSubgroupFeatureFlagBits {
+    VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001,
+    VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002,
+    VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004,
+    VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008,
+    VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010,
+    VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020,
+    VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040,
+    VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080,
+    VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSubgroupFeatureFlagBits;
+typedef VkFlags VkSubgroupFeatureFlags;
+
+typedef enum VkPeerMemoryFeatureFlagBits {
+    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001,
+    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002,
+    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004,
+    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008,
+    VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT,
+    VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT,
+    VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT,
+    VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT,
+    VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkPeerMemoryFeatureFlagBits;
+typedef VkFlags VkPeerMemoryFeatureFlags;
+
+typedef enum VkMemoryAllocateFlagBits {
+    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001,
+    VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT,
+    VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkMemoryAllocateFlagBits;
+typedef VkFlags VkMemoryAllocateFlags;
+typedef VkFlags VkCommandPoolTrimFlags;
+typedef VkFlags VkDescriptorUpdateTemplateCreateFlags;
+
+typedef enum VkExternalMemoryHandleTypeFlagBits {
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalMemoryHandleTypeFlagBits;
+typedef VkFlags VkExternalMemoryHandleTypeFlags;
+
+typedef enum VkExternalMemoryFeatureFlagBits {
+    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001,
+    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002,
+    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004,
+    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT,
+    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT,
+    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT,
+    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalMemoryFeatureFlagBits;
+typedef VkFlags VkExternalMemoryFeatureFlags;
+
+typedef enum VkExternalFenceHandleTypeFlagBits {
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT,
+    VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalFenceHandleTypeFlagBits;
+typedef VkFlags VkExternalFenceHandleTypeFlags;
+
+typedef enum VkExternalFenceFeatureFlagBits {
+    VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+    VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+    VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT,
+    VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT,
+    VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalFenceFeatureFlagBits;
+typedef VkFlags VkExternalFenceFeatureFlags;
+
+typedef enum VkFenceImportFlagBits {
+    VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001,
+    VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT,
+    VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkFenceImportFlagBits;
+typedef VkFlags VkFenceImportFlags;
+
+typedef enum VkSemaphoreImportFlagBits {
+    VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001,
+    VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
+    VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSemaphoreImportFlagBits;
+typedef VkFlags VkSemaphoreImportFlags;
+
+typedef enum VkExternalSemaphoreHandleTypeFlagBits {
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+    VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalSemaphoreHandleTypeFlagBits;
+typedef VkFlags VkExternalSemaphoreHandleTypeFlags;
+
+typedef enum VkExternalSemaphoreFeatureFlagBits {
+    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001,
+    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002,
+    VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT,
+    VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT,
+    VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkExternalSemaphoreFeatureFlagBits;
+typedef VkFlags VkExternalSemaphoreFeatureFlags;
+
+typedef struct VkPhysicalDeviceSubgroupProperties {
+    VkStructureType           sType;
+    void*                     pNext;
+    uint32_t                  subgroupSize;
+    VkShaderStageFlags        supportedStages;
+    VkSubgroupFeatureFlags    supportedOperations;
+    VkBool32                  quadOperationsInAllStages;
+} VkPhysicalDeviceSubgroupProperties;
+
+typedef struct VkBindBufferMemoryInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBuffer           buffer;
+    VkDeviceMemory     memory;
+    VkDeviceSize       memoryOffset;
+} VkBindBufferMemoryInfo;
+
+typedef struct VkBindImageMemoryInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkImage            image;
+    VkDeviceMemory     memory;
+    VkDeviceSize       memoryOffset;
+} VkBindImageMemoryInfo;
+
+typedef struct VkPhysicalDevice16BitStorageFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           storageBuffer16BitAccess;
+    VkBool32           uniformAndStorageBuffer16BitAccess;
+    VkBool32           storagePushConstant16;
+    VkBool32           storageInputOutput16;
+} VkPhysicalDevice16BitStorageFeatures;
+
+typedef struct VkMemoryDedicatedRequirements {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           prefersDedicatedAllocation;
+    VkBool32           requiresDedicatedAllocation;
+} VkMemoryDedicatedRequirements;
+
+typedef struct VkMemoryDedicatedAllocateInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkImage            image;
+    VkBuffer           buffer;
+} VkMemoryDedicatedAllocateInfo;
+
+typedef struct VkMemoryAllocateFlagsInfo {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkMemoryAllocateFlags    flags;
+    uint32_t                 deviceMask;
+} VkMemoryAllocateFlagsInfo;
+
+typedef struct VkDeviceGroupRenderPassBeginInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           deviceMask;
+    uint32_t           deviceRenderAreaCount;
+    const VkRect2D*    pDeviceRenderAreas;
+} VkDeviceGroupRenderPassBeginInfo;
+
+typedef struct VkDeviceGroupCommandBufferBeginInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           deviceMask;
+} VkDeviceGroupCommandBufferBeginInfo;
+
+typedef struct VkDeviceGroupSubmitInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           waitSemaphoreCount;
+    const uint32_t*    pWaitSemaphoreDeviceIndices;
+    uint32_t           commandBufferCount;
+    const uint32_t*    pCommandBufferDeviceMasks;
+    uint32_t           signalSemaphoreCount;
+    const uint32_t*    pSignalSemaphoreDeviceIndices;
+} VkDeviceGroupSubmitInfo;
+
+typedef struct VkDeviceGroupBindSparseInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           resourceDeviceIndex;
+    uint32_t           memoryDeviceIndex;
+} VkDeviceGroupBindSparseInfo;
+
+typedef struct VkBindBufferMemoryDeviceGroupInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           deviceIndexCount;
+    const uint32_t*    pDeviceIndices;
+} VkBindBufferMemoryDeviceGroupInfo;
+
+typedef struct VkBindImageMemoryDeviceGroupInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           deviceIndexCount;
+    const uint32_t*    pDeviceIndices;
+    uint32_t           splitInstanceBindRegionCount;
+    const VkRect2D*    pSplitInstanceBindRegions;
+} VkBindImageMemoryDeviceGroupInfo;
+
+typedef struct VkPhysicalDeviceGroupProperties {
+    VkStructureType     sType;
+    void*               pNext;
+    uint32_t            physicalDeviceCount;
+    VkPhysicalDevice    physicalDevices[VK_MAX_DEVICE_GROUP_SIZE];
+    VkBool32            subsetAllocation;
+} VkPhysicalDeviceGroupProperties;
+
+typedef struct VkDeviceGroupDeviceCreateInfo {
+    VkStructureType            sType;
+    const void*                pNext;
+    uint32_t                   physicalDeviceCount;
+    const VkPhysicalDevice*    pPhysicalDevices;
+} VkDeviceGroupDeviceCreateInfo;
+
+typedef struct VkBufferMemoryRequirementsInfo2 {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBuffer           buffer;
+} VkBufferMemoryRequirementsInfo2;
+
+typedef struct VkImageMemoryRequirementsInfo2 {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkImage            image;
+} VkImageMemoryRequirementsInfo2;
+
+typedef struct VkImageSparseMemoryRequirementsInfo2 {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkImage            image;
+} VkImageSparseMemoryRequirementsInfo2;
+
+typedef struct VkMemoryRequirements2 {
+    VkStructureType         sType;
+    void*                   pNext;
+    VkMemoryRequirements    memoryRequirements;
+} VkMemoryRequirements2;
+
+typedef struct VkSparseImageMemoryRequirements2 {
+    VkStructureType                    sType;
+    void*                              pNext;
+    VkSparseImageMemoryRequirements    memoryRequirements;
+} VkSparseImageMemoryRequirements2;
+
+typedef struct VkPhysicalDeviceFeatures2 {
+    VkStructureType             sType;
+    void*                       pNext;
+    VkPhysicalDeviceFeatures    features;
+} VkPhysicalDeviceFeatures2;
+
+typedef struct VkPhysicalDeviceProperties2 {
+    VkStructureType               sType;
+    void*                         pNext;
+    VkPhysicalDeviceProperties    properties;
+} VkPhysicalDeviceProperties2;
+
+typedef struct VkFormatProperties2 {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkFormatProperties    formatProperties;
+} VkFormatProperties2;
+
+typedef struct VkImageFormatProperties2 {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkImageFormatProperties    imageFormatProperties;
+} VkImageFormatProperties2;
+
+typedef struct VkPhysicalDeviceImageFormatInfo2 {
+    VkStructureType       sType;
+    const void*           pNext;
+    VkFormat              format;
+    VkImageType           type;
+    VkImageTiling         tiling;
+    VkImageUsageFlags     usage;
+    VkImageCreateFlags    flags;
+} VkPhysicalDeviceImageFormatInfo2;
+
+typedef struct VkQueueFamilyProperties2 {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkQueueFamilyProperties    queueFamilyProperties;
+} VkQueueFamilyProperties2;
+
+typedef struct VkPhysicalDeviceMemoryProperties2 {
+    VkStructureType                     sType;
+    void*                               pNext;
+    VkPhysicalDeviceMemoryProperties    memoryProperties;
+} VkPhysicalDeviceMemoryProperties2;
+
+typedef struct VkSparseImageFormatProperties2 {
+    VkStructureType                  sType;
+    void*                            pNext;
+    VkSparseImageFormatProperties    properties;
+} VkSparseImageFormatProperties2;
+
+typedef struct VkPhysicalDeviceSparseImageFormatInfo2 {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkFormat                 format;
+    VkImageType              type;
+    VkSampleCountFlagBits    samples;
+    VkImageUsageFlags        usage;
+    VkImageTiling            tiling;
+} VkPhysicalDeviceSparseImageFormatInfo2;
+
+typedef struct VkPhysicalDevicePointClippingProperties {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkPointClippingBehavior    pointClippingBehavior;
+} VkPhysicalDevicePointClippingProperties;
+
+typedef struct VkInputAttachmentAspectReference {
+    uint32_t              subpass;
+    uint32_t              inputAttachmentIndex;
+    VkImageAspectFlags    aspectMask;
+} VkInputAttachmentAspectReference;
+
+typedef struct VkRenderPassInputAttachmentAspectCreateInfo {
+    VkStructureType                            sType;
+    const void*                                pNext;
+    uint32_t                                   aspectReferenceCount;
+    const VkInputAttachmentAspectReference*    pAspectReferences;
+} VkRenderPassInputAttachmentAspectCreateInfo;
+
+typedef struct VkImageViewUsageCreateInfo {
+    VkStructureType      sType;
+    const void*          pNext;
+    VkImageUsageFlags    usage;
+} VkImageViewUsageCreateInfo;
+
+typedef struct VkPipelineTessellationDomainOriginStateCreateInfo {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkTessellationDomainOrigin    domainOrigin;
+} VkPipelineTessellationDomainOriginStateCreateInfo;
+
+typedef struct VkRenderPassMultiviewCreateInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           subpassCount;
+    const uint32_t*    pViewMasks;
+    uint32_t           dependencyCount;
+    const int32_t*     pViewOffsets;
+    uint32_t           correlationMaskCount;
+    const uint32_t*    pCorrelationMasks;
+} VkRenderPassMultiviewCreateInfo;
+
+typedef struct VkPhysicalDeviceMultiviewFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           multiview;
+    VkBool32           multiviewGeometryShader;
+    VkBool32           multiviewTessellationShader;
+} VkPhysicalDeviceMultiviewFeatures;
+
+typedef struct VkPhysicalDeviceMultiviewProperties {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxMultiviewViewCount;
+    uint32_t           maxMultiviewInstanceIndex;
+} VkPhysicalDeviceMultiviewProperties;
+
+typedef struct VkPhysicalDeviceVariablePointerFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           variablePointersStorageBuffer;
+    VkBool32           variablePointers;
+} VkPhysicalDeviceVariablePointerFeatures;
+
+typedef struct VkPhysicalDeviceProtectedMemoryFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           protectedMemory;
+} VkPhysicalDeviceProtectedMemoryFeatures;
+
+typedef struct VkPhysicalDeviceProtectedMemoryProperties {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           protectedNoFault;
+} VkPhysicalDeviceProtectedMemoryProperties;
+
+typedef struct VkDeviceQueueInfo2 {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkDeviceQueueCreateFlags    flags;
+    uint32_t                    queueFamilyIndex;
+    uint32_t                    queueIndex;
+} VkDeviceQueueInfo2;
+
+typedef struct VkProtectedSubmitInfo {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           protectedSubmit;
+} VkProtectedSubmitInfo;
+
+typedef struct VkSamplerYcbcrConversionCreateInfo {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkFormat                         format;
+    VkSamplerYcbcrModelConversion    ycbcrModel;
+    VkSamplerYcbcrRange              ycbcrRange;
+    VkComponentMapping               components;
+    VkChromaLocation                 xChromaOffset;
+    VkChromaLocation                 yChromaOffset;
+    VkFilter                         chromaFilter;
+    VkBool32                         forceExplicitReconstruction;
+} VkSamplerYcbcrConversionCreateInfo;
+
+typedef struct VkSamplerYcbcrConversionInfo {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkSamplerYcbcrConversion    conversion;
+} VkSamplerYcbcrConversionInfo;
+
+typedef struct VkBindImagePlaneMemoryInfo {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkImageAspectFlagBits    planeAspect;
+} VkBindImagePlaneMemoryInfo;
+
+typedef struct VkImagePlaneMemoryRequirementsInfo {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkImageAspectFlagBits    planeAspect;
+} VkImagePlaneMemoryRequirementsInfo;
+
+typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           samplerYcbcrConversion;
+} VkPhysicalDeviceSamplerYcbcrConversionFeatures;
+
+typedef struct VkSamplerYcbcrConversionImageFormatProperties {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           combinedImageSamplerDescriptorCount;
+} VkSamplerYcbcrConversionImageFormatProperties;
+
+typedef struct VkDescriptorUpdateTemplateEntry {
+    uint32_t            dstBinding;
+    uint32_t            dstArrayElement;
+    uint32_t            descriptorCount;
+    VkDescriptorType    descriptorType;
+    size_t              offset;
+    size_t              stride;
+} VkDescriptorUpdateTemplateEntry;
+
+typedef struct VkDescriptorUpdateTemplateCreateInfo {
+    VkStructureType                           sType;
+    void*                                     pNext;
+    VkDescriptorUpdateTemplateCreateFlags     flags;
+    uint32_t                                  descriptorUpdateEntryCount;
+    const VkDescriptorUpdateTemplateEntry*    pDescriptorUpdateEntries;
+    VkDescriptorUpdateTemplateType            templateType;
+    VkDescriptorSetLayout                     descriptorSetLayout;
+    VkPipelineBindPoint                       pipelineBindPoint;
+    VkPipelineLayout                          pipelineLayout;
+    uint32_t                                  set;
+} VkDescriptorUpdateTemplateCreateInfo;
+
+typedef struct VkExternalMemoryProperties {
+    VkExternalMemoryFeatureFlags       externalMemoryFeatures;
+    VkExternalMemoryHandleTypeFlags    exportFromImportedHandleTypes;
+    VkExternalMemoryHandleTypeFlags    compatibleHandleTypes;
+} VkExternalMemoryProperties;
+
+typedef struct VkPhysicalDeviceExternalImageFormatInfo {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+} VkPhysicalDeviceExternalImageFormatInfo;
+
+typedef struct VkExternalImageFormatProperties {
+    VkStructureType               sType;
+    void*                         pNext;
+    VkExternalMemoryProperties    externalMemoryProperties;
+} VkExternalImageFormatProperties;
+
+typedef struct VkPhysicalDeviceExternalBufferInfo {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkBufferCreateFlags                   flags;
+    VkBufferUsageFlags                    usage;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+} VkPhysicalDeviceExternalBufferInfo;
+
+typedef struct VkExternalBufferProperties {
+    VkStructureType               sType;
+    void*                         pNext;
+    VkExternalMemoryProperties    externalMemoryProperties;
+} VkExternalBufferProperties;
+
+typedef struct VkPhysicalDeviceIDProperties {
+    VkStructureType    sType;
+    void*              pNext;
+    uint8_t            deviceUUID[VK_UUID_SIZE];
+    uint8_t            driverUUID[VK_UUID_SIZE];
+    uint8_t            deviceLUID[VK_LUID_SIZE];
+    uint32_t           deviceNodeMask;
+    VkBool32           deviceLUIDValid;
+} VkPhysicalDeviceIDProperties;
+
+typedef struct VkExternalMemoryImageCreateInfo {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkExternalMemoryHandleTypeFlags    handleTypes;
+} VkExternalMemoryImageCreateInfo;
+
+typedef struct VkExternalMemoryBufferCreateInfo {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkExternalMemoryHandleTypeFlags    handleTypes;
+} VkExternalMemoryBufferCreateInfo;
+
+typedef struct VkExportMemoryAllocateInfo {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkExternalMemoryHandleTypeFlags    handleTypes;
+} VkExportMemoryAllocateInfo;
+
+typedef struct VkPhysicalDeviceExternalFenceInfo {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkExternalFenceHandleTypeFlagBits    handleType;
+} VkPhysicalDeviceExternalFenceInfo;
+
+typedef struct VkExternalFenceProperties {
+    VkStructureType                   sType;
+    void*                             pNext;
+    VkExternalFenceHandleTypeFlags    exportFromImportedHandleTypes;
+    VkExternalFenceHandleTypeFlags    compatibleHandleTypes;
+    VkExternalFenceFeatureFlags       externalFenceFeatures;
+} VkExternalFenceProperties;
+
+typedef struct VkExportFenceCreateInfo {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkExternalFenceHandleTypeFlags    handleTypes;
+} VkExportFenceCreateInfo;
+
+typedef struct VkExportSemaphoreCreateInfo {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalSemaphoreHandleTypeFlags    handleTypes;
+} VkExportSemaphoreCreateInfo;
+
+typedef struct VkPhysicalDeviceExternalSemaphoreInfo {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkExternalSemaphoreHandleTypeFlagBits    handleType;
+} VkPhysicalDeviceExternalSemaphoreInfo;
+
+typedef struct VkExternalSemaphoreProperties {
+    VkStructureType                       sType;
+    void*                                 pNext;
+    VkExternalSemaphoreHandleTypeFlags    exportFromImportedHandleTypes;
+    VkExternalSemaphoreHandleTypeFlags    compatibleHandleTypes;
+    VkExternalSemaphoreFeatureFlags       externalSemaphoreFeatures;
+} VkExternalSemaphoreProperties;
+
+typedef struct VkPhysicalDeviceMaintenance3Properties {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxPerSetDescriptors;
+    VkDeviceSize       maxMemoryAllocationSize;
+} VkPhysicalDeviceMaintenance3Properties;
+
+typedef struct VkDescriptorSetLayoutSupport {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           supported;
+} VkDescriptorSetLayoutSupport;
+
+typedef struct VkPhysicalDeviceShaderDrawParameterFeatures {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           shaderDrawParameters;
+} VkPhysicalDeviceShaderDrawParameterFeatures;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion);
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(
+    uint32_t*                                   pApiVersion);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(
+    VkDevice                                    device,
+    uint32_t                                    bindInfoCount,
+    const VkBindBufferMemoryInfo*               pBindInfos);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(
+    VkDevice                                    device,
+    uint32_t                                    bindInfoCount,
+    const VkBindImageMemoryInfo*                pBindInfos);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures(
+    VkDevice                                    device,
+    uint32_t                                    heapIndex,
+    uint32_t                                    localDeviceIndex,
+    uint32_t                                    remoteDeviceIndex,
+    VkPeerMemoryFeatureFlags*                   pPeerMemoryFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    deviceMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    baseGroupX,
+    uint32_t                                    baseGroupY,
+    uint32_t                                    baseGroupZ,
+    uint32_t                                    groupCountX,
+    uint32_t                                    groupCountY,
+    uint32_t                                    groupCountZ);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups(
+    VkInstance                                  instance,
+    uint32_t*                                   pPhysicalDeviceGroupCount,
+    VkPhysicalDeviceGroupProperties*            pPhysicalDeviceGroupProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2(
+    VkDevice                                    device,
+    const VkImageMemoryRequirementsInfo2*       pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2(
+    VkDevice                                    device,
+    const VkBufferMemoryRequirementsInfo2*      pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2(
+    VkDevice                                    device,
+    const VkImageSparseMemoryRequirementsInfo2* pInfo,
+    uint32_t*                                   pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2*           pSparseMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures2*                  pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties2*                pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties2*                        pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2*     pImageFormatInfo,
+    VkImageFormatProperties2*                   pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2*                   pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties2*          pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+    uint32_t*                                   pPropertyCount,
+    VkSparseImageFormatProperties2*             pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    VkCommandPoolTrimFlags                      flags);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2(
+    VkDevice                                    device,
+    const VkDeviceQueueInfo2*                   pQueueInfo,
+    VkQueue*                                    pQueue);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion(
+    VkDevice                                    device,
+    const VkSamplerYcbcrConversionCreateInfo*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSamplerYcbcrConversion*                   pYcbcrConversion);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion(
+    VkDevice                                    device,
+    VkSamplerYcbcrConversion                    ycbcrConversion,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate(
+    VkDevice                                    device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDescriptorUpdateTemplate*                 pDescriptorUpdateTemplate);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate(
+    VkDevice                                    device,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate(
+    VkDevice                                    device,
+    VkDescriptorSet                             descriptorSet,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+    const void*                                 pData);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalBufferInfo*   pExternalBufferInfo,
+    VkExternalBufferProperties*                 pExternalBufferProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
+    VkExternalFenceProperties*                  pExternalFenceProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+    VkExternalSemaphoreProperties*              pExternalSemaphoreProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport(
+    VkDevice                                    device,
+    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+    VkDescriptorSetLayoutSupport*               pSupport);
+#endif
+
+#define VK_KHR_surface 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
+
+#define VK_KHR_SURFACE_SPEC_VERSION       25
+#define VK_KHR_SURFACE_EXTENSION_NAME     "VK_KHR_surface"
+#define VK_COLORSPACE_SRGB_NONLINEAR_KHR  VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
+
+
+typedef enum VkColorSpaceKHR {
+    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
+    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
+    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
+    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,
+    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,
+    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,
+    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,
+    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,
+    VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,
+    VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,
+    VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,
+    VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
+    VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
+    VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
+    VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+    VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+    VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
+    VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkColorSpaceKHR;
+
+typedef enum VkPresentModeKHR {
+    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,
+    VK_PRESENT_MODE_MAILBOX_KHR = 1,
+    VK_PRESENT_MODE_FIFO_KHR = 2,
+    VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,
+    VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,
+    VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,
+    VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR,
+    VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+    VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1),
+    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkPresentModeKHR;
+
+
+typedef enum VkSurfaceTransformFlagBitsKHR {
+    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,
+    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002,
+    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004,
+    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008,
+    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010,
+    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020,
+    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040,
+    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080,
+    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,
+    VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkSurfaceTransformFlagBitsKHR;
+typedef VkFlags VkSurfaceTransformFlagsKHR;
+
+typedef enum VkCompositeAlphaFlagBitsKHR {
+    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
+    VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002,
+    VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004,
+    VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008,
+    VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkCompositeAlphaFlagBitsKHR;
+typedef VkFlags VkCompositeAlphaFlagsKHR;
+
+typedef struct VkSurfaceCapabilitiesKHR {
+    uint32_t                         minImageCount;
+    uint32_t                         maxImageCount;
+    VkExtent2D                       currentExtent;
+    VkExtent2D                       minImageExtent;
+    VkExtent2D                       maxImageExtent;
+    uint32_t                         maxImageArrayLayers;
+    VkSurfaceTransformFlagsKHR       supportedTransforms;
+    VkSurfaceTransformFlagBitsKHR    currentTransform;
+    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;
+    VkImageUsageFlags                supportedUsageFlags;
+} VkSurfaceCapabilitiesKHR;
+
+typedef struct VkSurfaceFormatKHR {
+    VkFormat           format;
+    VkColorSpaceKHR    colorSpace;
+} VkSurfaceFormatKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(
+    VkInstance                                  instance,
+    VkSurfaceKHR                                surface,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t                                    queueFamilyIndex,
+    VkSurfaceKHR                                surface,
+    VkBool32*                                   pSupported);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    VkSurfaceCapabilitiesKHR*                   pSurfaceCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    uint32_t*                                   pSurfaceFormatCount,
+    VkSurfaceFormatKHR*                         pSurfaceFormats);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    uint32_t*                                   pPresentModeCount,
+    VkPresentModeKHR*                           pPresentModes);
+#endif
+
+#define VK_KHR_swapchain 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR)
+
+#define VK_KHR_SWAPCHAIN_SPEC_VERSION     70
+#define VK_KHR_SWAPCHAIN_EXTENSION_NAME   "VK_KHR_swapchain"
+
+
+typedef enum VkSwapchainCreateFlagBitsKHR {
+    VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001,
+    VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002,
+    VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkSwapchainCreateFlagBitsKHR;
+typedef VkFlags VkSwapchainCreateFlagsKHR;
+
+typedef enum VkDeviceGroupPresentModeFlagBitsKHR {
+    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001,
+    VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002,
+    VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004,
+    VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008,
+    VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDeviceGroupPresentModeFlagBitsKHR;
+typedef VkFlags VkDeviceGroupPresentModeFlagsKHR;
+
+typedef struct VkSwapchainCreateInfoKHR {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkSwapchainCreateFlagsKHR        flags;
+    VkSurfaceKHR                     surface;
+    uint32_t                         minImageCount;
+    VkFormat                         imageFormat;
+    VkColorSpaceKHR                  imageColorSpace;
+    VkExtent2D                       imageExtent;
+    uint32_t                         imageArrayLayers;
+    VkImageUsageFlags                imageUsage;
+    VkSharingMode                    imageSharingMode;
+    uint32_t                         queueFamilyIndexCount;
+    const uint32_t*                  pQueueFamilyIndices;
+    VkSurfaceTransformFlagBitsKHR    preTransform;
+    VkCompositeAlphaFlagBitsKHR      compositeAlpha;
+    VkPresentModeKHR                 presentMode;
+    VkBool32                         clipped;
+    VkSwapchainKHR                   oldSwapchain;
+} VkSwapchainCreateInfoKHR;
+
+typedef struct VkPresentInfoKHR {
+    VkStructureType          sType;
+    const void*              pNext;
+    uint32_t                 waitSemaphoreCount;
+    const VkSemaphore*       pWaitSemaphores;
+    uint32_t                 swapchainCount;
+    const VkSwapchainKHR*    pSwapchains;
+    const uint32_t*          pImageIndices;
+    VkResult*                pResults;
+} VkPresentInfoKHR;
+
+typedef struct VkImageSwapchainCreateInfoKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkSwapchainKHR     swapchain;
+} VkImageSwapchainCreateInfoKHR;
+
+typedef struct VkBindImageMemorySwapchainInfoKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkSwapchainKHR     swapchain;
+    uint32_t           imageIndex;
+} VkBindImageMemorySwapchainInfoKHR;
+
+typedef struct VkAcquireNextImageInfoKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkSwapchainKHR     swapchain;
+    uint64_t           timeout;
+    VkSemaphore        semaphore;
+    VkFence            fence;
+    uint32_t           deviceMask;
+} VkAcquireNextImageInfoKHR;
+
+typedef struct VkDeviceGroupPresentCapabilitiesKHR {
+    VkStructureType                     sType;
+    const void*                         pNext;
+    uint32_t                            presentMask[VK_MAX_DEVICE_GROUP_SIZE];
+    VkDeviceGroupPresentModeFlagsKHR    modes;
+} VkDeviceGroupPresentCapabilitiesKHR;
+
+typedef struct VkDeviceGroupPresentInfoKHR {
+    VkStructureType                        sType;
+    const void*                            pNext;
+    uint32_t                               swapchainCount;
+    const uint32_t*                        pDeviceMasks;
+    VkDeviceGroupPresentModeFlagBitsKHR    mode;
+} VkDeviceGroupPresentInfoKHR;
+
+typedef struct VkDeviceGroupSwapchainCreateInfoKHR {
+    VkStructureType                     sType;
+    const void*                         pNext;
+    VkDeviceGroupPresentModeFlagsKHR    modes;
+} VkDeviceGroupSwapchainCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain);
+typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
+typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(
+    VkDevice                                    device,
+    const VkSwapchainCreateInfoKHR*             pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSwapchainKHR*                             pSwapchain);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    uint32_t*                                   pSwapchainImageCount,
+    VkImage*                                    pSwapchainImages);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    uint64_t                                    timeout,
+    VkSemaphore                                 semaphore,
+    VkFence                                     fence,
+    uint32_t*                                   pImageIndex);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
+    VkQueue                                     queue,
+    const VkPresentInfoKHR*                     pPresentInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR(
+    VkDevice                                    device,
+    VkDeviceGroupPresentCapabilitiesKHR*        pDeviceGroupPresentCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR(
+    VkDevice                                    device,
+    VkSurfaceKHR                                surface,
+    VkDeviceGroupPresentModeFlagsKHR*           pModes);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    uint32_t*                                   pRectCount,
+    VkRect2D*                                   pRects);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR(
+    VkDevice                                    device,
+    const VkAcquireNextImageInfoKHR*            pAcquireInfo,
+    uint32_t*                                   pImageIndex);
+#endif
+
+#define VK_KHR_display 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR)
+
+#define VK_KHR_DISPLAY_SPEC_VERSION       21
+#define VK_KHR_DISPLAY_EXTENSION_NAME     "VK_KHR_display"
+
+
+typedef enum VkDisplayPlaneAlphaFlagBitsKHR {
+    VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
+    VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002,
+    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004,
+    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008,
+    VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDisplayPlaneAlphaFlagBitsKHR;
+typedef VkFlags VkDisplayPlaneAlphaFlagsKHR;
+typedef VkFlags VkDisplayModeCreateFlagsKHR;
+typedef VkFlags VkDisplaySurfaceCreateFlagsKHR;
+
+typedef struct VkDisplayPropertiesKHR {
+    VkDisplayKHR                  display;
+    const char*                   displayName;
+    VkExtent2D                    physicalDimensions;
+    VkExtent2D                    physicalResolution;
+    VkSurfaceTransformFlagsKHR    supportedTransforms;
+    VkBool32                      planeReorderPossible;
+    VkBool32                      persistentContent;
+} VkDisplayPropertiesKHR;
+
+typedef struct VkDisplayModeParametersKHR {
+    VkExtent2D    visibleRegion;
+    uint32_t      refreshRate;
+} VkDisplayModeParametersKHR;
+
+typedef struct VkDisplayModePropertiesKHR {
+    VkDisplayModeKHR              displayMode;
+    VkDisplayModeParametersKHR    parameters;
+} VkDisplayModePropertiesKHR;
+
+typedef struct VkDisplayModeCreateInfoKHR {
+    VkStructureType                sType;
+    const void*                    pNext;
+    VkDisplayModeCreateFlagsKHR    flags;
+    VkDisplayModeParametersKHR     parameters;
+} VkDisplayModeCreateInfoKHR;
+
+typedef struct VkDisplayPlaneCapabilitiesKHR {
+    VkDisplayPlaneAlphaFlagsKHR    supportedAlpha;
+    VkOffset2D                     minSrcPosition;
+    VkOffset2D                     maxSrcPosition;
+    VkExtent2D                     minSrcExtent;
+    VkExtent2D                     maxSrcExtent;
+    VkOffset2D                     minDstPosition;
+    VkOffset2D                     maxDstPosition;
+    VkExtent2D                     minDstExtent;
+    VkExtent2D                     maxDstExtent;
+} VkDisplayPlaneCapabilitiesKHR;
+
+typedef struct VkDisplayPlanePropertiesKHR {
+    VkDisplayKHR    currentDisplay;
+    uint32_t        currentStackIndex;
+} VkDisplayPlanePropertiesKHR;
+
+typedef struct VkDisplaySurfaceCreateInfoKHR {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkDisplaySurfaceCreateFlagsKHR    flags;
+    VkDisplayModeKHR                  displayMode;
+    uint32_t                          planeIndex;
+    uint32_t                          planeStackIndex;
+    VkSurfaceTransformFlagBitsKHR     transform;
+    float                             globalAlpha;
+    VkDisplayPlaneAlphaFlagBitsKHR    alphaMode;
+    VkExtent2D                        imageExtent;
+} VkDisplaySurfaceCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pPropertyCount,
+    VkDisplayPropertiesKHR*                     pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pPropertyCount,
+    VkDisplayPlanePropertiesKHR*                pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t                                    planeIndex,
+    uint32_t*                                   pDisplayCount,
+    VkDisplayKHR*                               pDisplays);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkDisplayKHR                                display,
+    uint32_t*                                   pPropertyCount,
+    VkDisplayModePropertiesKHR*                 pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkDisplayKHR                                display,
+    const VkDisplayModeCreateInfoKHR*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDisplayModeKHR*                           pMode);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkDisplayModeKHR                            mode,
+    uint32_t                                    planeIndex,
+    VkDisplayPlaneCapabilitiesKHR*              pCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR(
+    VkInstance                                  instance,
+    const VkDisplaySurfaceCreateInfoKHR*        pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSurfaceKHR*                               pSurface);
+#endif
+
+#define VK_KHR_display_swapchain 1
+#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9
+#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain"
+
+typedef struct VkDisplayPresentInfoKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkRect2D           srcRect;
+    VkRect2D           dstRect;
+    VkBool32           persistent;
+} VkDisplayPresentInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR(
+    VkDevice                                    device,
+    uint32_t                                    swapchainCount,
+    const VkSwapchainCreateInfoKHR*             pCreateInfos,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSwapchainKHR*                             pSwapchains);
+#endif
+
+#define VK_KHR_sampler_mirror_clamp_to_edge 1
+#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
+#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
+
+
+#define VK_KHR_multiview 1
+#define VK_KHR_MULTIVIEW_SPEC_VERSION     1
+#define VK_KHR_MULTIVIEW_EXTENSION_NAME   "VK_KHR_multiview"
+
+typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR;
+
+typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR;
+
+typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR;
+
+
+
+#define VK_KHR_get_physical_device_properties2 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+
+typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR;
+
+typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR;
+
+typedef VkFormatProperties2 VkFormatProperties2KHR;
+
+typedef VkImageFormatProperties2 VkImageFormatProperties2KHR;
+
+typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR;
+
+typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR;
+
+typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR;
+
+typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR;
+
+typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceFeatures2*                  pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceProperties2*                pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkFormatProperties2*                        pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceImageFormatInfo2*     pImageFormatInfo,
+    VkImageFormatProperties2*                   pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pQueueFamilyPropertyCount,
+    VkQueueFamilyProperties2*                   pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    VkPhysicalDeviceMemoryProperties2*          pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+    uint32_t*                                   pPropertyCount,
+    VkSparseImageFormatProperties2*             pProperties);
+#endif
+
+#define VK_KHR_device_group 1
+#define VK_KHR_DEVICE_GROUP_SPEC_VERSION  3
+#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
+
+typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR;
+
+typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR;
+
+typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR;
+
+typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR;
+
+
+typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR;
+
+typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR;
+
+typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR;
+
+typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR;
+
+typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR;
+
+typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR;
+
+typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR(
+    VkDevice                                    device,
+    uint32_t                                    heapIndex,
+    uint32_t                                    localDeviceIndex,
+    uint32_t                                    remoteDeviceIndex,
+    VkPeerMemoryFeatureFlags*                   pPeerMemoryFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    deviceMask);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    baseGroupX,
+    uint32_t                                    baseGroupY,
+    uint32_t                                    baseGroupZ,
+    uint32_t                                    groupCountX,
+    uint32_t                                    groupCountY,
+    uint32_t                                    groupCountZ);
+#endif
+
+#define VK_KHR_shader_draw_parameters 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
+
+
+#define VK_KHR_maintenance1 1
+#define VK_KHR_MAINTENANCE1_SPEC_VERSION  1
+#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
+
+typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(
+    VkDevice                                    device,
+    VkCommandPool                               commandPool,
+    VkCommandPoolTrimFlags                      flags);
+#endif
+
+#define VK_KHR_device_group_creation 1
+#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
+#define VK_MAX_DEVICE_GROUP_SIZE_KHR      VK_MAX_DEVICE_GROUP_SIZE
+
+typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR;
+
+typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR(
+    VkInstance                                  instance,
+    uint32_t*                                   pPhysicalDeviceGroupCount,
+    VkPhysicalDeviceGroupProperties*            pPhysicalDeviceGroupProperties);
+#endif
+
+#define VK_KHR_external_memory_capabilities 1
+#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities"
+#define VK_LUID_SIZE_KHR                  VK_LUID_SIZE
+
+typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR;
+
+typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR;
+
+typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR;
+
+typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR;
+
+
+typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR;
+
+typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR;
+
+typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR;
+
+typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR;
+
+typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR;
+
+typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalBufferInfo*   pExternalBufferInfo,
+    VkExternalBufferProperties*                 pExternalBufferProperties);
+#endif
+
+#define VK_KHR_external_memory 1
+#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory"
+#define VK_QUEUE_FAMILY_EXTERNAL_KHR      VK_QUEUE_FAMILY_EXTERNAL
+
+typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR;
+
+typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR;
+
+typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR;
+
+
+
+#define VK_KHR_external_memory_fd 1
+#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd"
+
+typedef struct VkImportMemoryFdInfoKHR {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+    int                                   fd;
+} VkImportMemoryFdInfoKHR;
+
+typedef struct VkMemoryFdPropertiesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           memoryTypeBits;
+} VkMemoryFdPropertiesKHR;
+
+typedef struct VkMemoryGetFdInfoKHR {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkDeviceMemory                        memory;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+} VkMemoryGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR(
+    VkDevice                                    device,
+    const VkMemoryGetFdInfoKHR*                 pGetFdInfo,
+    int*                                        pFd);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR(
+    VkDevice                                    device,
+    VkExternalMemoryHandleTypeFlagBits          handleType,
+    int                                         fd,
+    VkMemoryFdPropertiesKHR*                    pMemoryFdProperties);
+#endif
+
+#define VK_KHR_external_semaphore_capabilities 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities"
+
+typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR;
+
+typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR;
+
+typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR;
+
+typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR;
+
+
+typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR;
+
+typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+    VkExternalSemaphoreProperties*              pExternalSemaphoreProperties);
+#endif
+
+#define VK_KHR_external_semaphore 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore"
+
+typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR;
+
+typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR;
+
+
+typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR;
+
+
+
+#define VK_KHR_external_semaphore_fd 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
+
+typedef struct VkImportSemaphoreFdInfoKHR {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkSemaphore                              semaphore;
+    VkSemaphoreImportFlags                   flags;
+    VkExternalSemaphoreHandleTypeFlagBits    handleType;
+    int                                      fd;
+} VkImportSemaphoreFdInfoKHR;
+
+typedef struct VkSemaphoreGetFdInfoKHR {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkSemaphore                              semaphore;
+    VkExternalSemaphoreHandleTypeFlagBits    handleType;
+} VkSemaphoreGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR(
+    VkDevice                                    device,
+    const VkImportSemaphoreFdInfoKHR*           pImportSemaphoreFdInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR(
+    VkDevice                                    device,
+    const VkSemaphoreGetFdInfoKHR*              pGetFdInfo,
+    int*                                        pFd);
+#endif
+
+#define VK_KHR_push_descriptor 1
+#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2
+#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
+
+typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxPushDescriptors;
+} VkPhysicalDevicePushDescriptorPropertiesKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites);
+typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(
+    VkCommandBuffer                             commandBuffer,
+    VkPipelineBindPoint                         pipelineBindPoint,
+    VkPipelineLayout                            layout,
+    uint32_t                                    set,
+    uint32_t                                    descriptorWriteCount,
+    const VkWriteDescriptorSet*                 pDescriptorWrites);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(
+    VkCommandBuffer                             commandBuffer,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+    VkPipelineLayout                            layout,
+    uint32_t                                    set,
+    const void*                                 pData);
+#endif
+
+#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"
+
+typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR;
+
+
+
+#define VK_KHR_incremental_present 1
+#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
+#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
+
+typedef struct VkRectLayerKHR {
+    VkOffset2D    offset;
+    VkExtent2D    extent;
+    uint32_t      layer;
+} VkRectLayerKHR;
+
+typedef struct VkPresentRegionKHR {
+    uint32_t                 rectangleCount;
+    const VkRectLayerKHR*    pRectangles;
+} VkPresentRegionKHR;
+
+typedef struct VkPresentRegionsKHR {
+    VkStructureType              sType;
+    const void*                  pNext;
+    uint32_t                     swapchainCount;
+    const VkPresentRegionKHR*    pRegions;
+} VkPresentRegionsKHR;
+
+
+
+#define VK_KHR_descriptor_update_template 1
+typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR;
+
+
+#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
+#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
+
+typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR;
+
+
+typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
+
+
+typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR;
+
+typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(
+    VkDevice                                    device,
+    const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDescriptorUpdateTemplate*                 pDescriptorUpdateTemplate);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(
+    VkDevice                                    device,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(
+    VkDevice                                    device,
+    VkDescriptorSet                             descriptorSet,
+    VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
+    const void*                                 pData);
+#endif
+
+#define VK_KHR_shared_presentable_image 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
+
+typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
+    VkStructureType      sType;
+    void*                pNext;
+    VkImageUsageFlags    sharedPresentSupportedUsageFlags;
+} VkSharedPresentSurfaceCapabilitiesKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain);
+#endif
+
+#define VK_KHR_external_fence_capabilities 1
+#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities"
+
+typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR;
+
+typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR;
+
+typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR;
+
+typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR;
+
+
+typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR;
+
+typedef VkExternalFenceProperties VkExternalFencePropertiesKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceExternalFenceInfo*    pExternalFenceInfo,
+    VkExternalFenceProperties*                  pExternalFenceProperties);
+#endif
+
+#define VK_KHR_external_fence 1
+#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence"
+
+typedef VkFenceImportFlags VkFenceImportFlagsKHR;
+
+typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR;
+
+
+typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR;
+
+
+
+#define VK_KHR_external_fence_fd 1
+#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
+#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
+
+typedef struct VkImportFenceFdInfoKHR {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkFence                              fence;
+    VkFenceImportFlags                   flags;
+    VkExternalFenceHandleTypeFlagBits    handleType;
+    int                                  fd;
+} VkImportFenceFdInfoKHR;
+
+typedef struct VkFenceGetFdInfoKHR {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkFence                              fence;
+    VkExternalFenceHandleTypeFlagBits    handleType;
+} VkFenceGetFdInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR(
+    VkDevice                                    device,
+    const VkImportFenceFdInfoKHR*               pImportFenceFdInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR(
+    VkDevice                                    device,
+    const VkFenceGetFdInfoKHR*                  pGetFdInfo,
+    int*                                        pFd);
+#endif
+
+#define VK_KHR_maintenance2 1
+#define VK_KHR_MAINTENANCE2_SPEC_VERSION  1
+#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2"
+
+typedef VkPointClippingBehavior VkPointClippingBehaviorKHR;
+
+typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR;
+
+
+typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR;
+
+typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR;
+
+typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR;
+
+typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR;
+
+typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR;
+
+
+
+#define VK_KHR_get_surface_capabilities2 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+
+typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkSurfaceKHR       surface;
+} VkPhysicalDeviceSurfaceInfo2KHR;
+
+typedef struct VkSurfaceCapabilities2KHR {
+    VkStructureType             sType;
+    void*                       pNext;
+    VkSurfaceCapabilitiesKHR    surfaceCapabilities;
+} VkSurfaceCapabilities2KHR;
+
+typedef struct VkSurfaceFormat2KHR {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkSurfaceFormatKHR    surfaceFormat;
+} VkSurfaceFormat2KHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    VkSurfaceCapabilities2KHR*                  pSurfaceCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    uint32_t*                                   pSurfaceFormatCount,
+    VkSurfaceFormat2KHR*                        pSurfaceFormats);
+#endif
+
+#define VK_KHR_variable_pointers 1
+#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1
+#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers"
+
+typedef VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerFeaturesKHR;
+
+
+
+#define VK_KHR_dedicated_allocation 1
+#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3
+#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
+
+typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR;
+
+typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR;
+
+
+
+#define VK_KHR_storage_buffer_storage_class 1
+#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1
+#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class"
+
+
+#define VK_KHR_relaxed_block_layout 1
+#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1
+#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout"
+
+
+#define VK_KHR_get_memory_requirements2 1
+#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1
+#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
+
+typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR;
+
+typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR;
+
+typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR;
+
+typedef VkMemoryRequirements2 VkMemoryRequirements2KHR;
+
+typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR(
+    VkDevice                                    device,
+    const VkImageMemoryRequirementsInfo2*       pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR(
+    VkDevice                                    device,
+    const VkBufferMemoryRequirementsInfo2*      pInfo,
+    VkMemoryRequirements2*                      pMemoryRequirements);
+
+VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR(
+    VkDevice                                    device,
+    const VkImageSparseMemoryRequirementsInfo2* pInfo,
+    uint32_t*                                   pSparseMemoryRequirementCount,
+    VkSparseImageMemoryRequirements2*           pSparseMemoryRequirements);
+#endif
+
+#define VK_KHR_image_format_list 1
+#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1
+#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list"
+
+typedef struct VkImageFormatListCreateInfoKHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           viewFormatCount;
+    const VkFormat*    pViewFormats;
+} VkImageFormatListCreateInfoKHR;
+
+
+
+#define VK_KHR_sampler_ycbcr_conversion 1
+typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR;
+
+
+#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1
+#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion"
+
+typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR;
+
+typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR;
+
+typedef VkChromaLocation VkChromaLocationKHR;
+
+
+typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR;
+
+typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR;
+
+typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR;
+
+typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR;
+
+typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR;
+
+typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR(
+    VkDevice                                    device,
+    const VkSamplerYcbcrConversionCreateInfo*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSamplerYcbcrConversion*                   pYcbcrConversion);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR(
+    VkDevice                                    device,
+    VkSamplerYcbcrConversion                    ycbcrConversion,
+    const VkAllocationCallbacks*                pAllocator);
+#endif
+
+#define VK_KHR_bind_memory2 1
+#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1
+#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2"
+
+typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR;
+
+typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR(
+    VkDevice                                    device,
+    uint32_t                                    bindInfoCount,
+    const VkBindBufferMemoryInfo*               pBindInfos);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR(
+    VkDevice                                    device,
+    uint32_t                                    bindInfoCount,
+    const VkBindImageMemoryInfo*                pBindInfos);
+#endif
+
+#define VK_KHR_maintenance3 1
+#define VK_KHR_MAINTENANCE3_SPEC_VERSION  1
+#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3"
+
+typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR;
+
+typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR(
+    VkDevice                                    device,
+    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
+    VkDescriptorSetLayoutSupport*               pSupport);
+#endif
+
+#define VK_EXT_debug_report 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
+
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  9
+#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
+#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
+#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT
+
+
+typedef enum VkDebugReportObjectTypeEXT {
+    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
+    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
+    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
+    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
+    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
+    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
+    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
+    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
+    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
+    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
+    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
+    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
+    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
+    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
+    VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
+    VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
+    VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDebugReportObjectTypeEXT;
+
+
+typedef enum VkDebugReportFlagBitsEXT {
+    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
+    VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
+    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
+    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
+    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
+    VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDebugReportFlagBitsEXT;
+typedef VkFlags VkDebugReportFlagsEXT;
+
+typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
+    VkDebugReportFlagsEXT                       flags,
+    VkDebugReportObjectTypeEXT                  objectType,
+    uint64_t                                    object,
+    size_t                                      location,
+    int32_t                                     messageCode,
+    const char*                                 pLayerPrefix,
+    const char*                                 pMessage,
+    void*                                       pUserData);
+
+typedef struct VkDebugReportCallbackCreateInfoEXT {
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkDebugReportFlagsEXT           flags;
+    PFN_vkDebugReportCallbackEXT    pfnCallback;
+    void*                           pUserData;
+} VkDebugReportCallbackCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
+typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
+    VkInstance                                  instance,
+    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDebugReportCallbackEXT*                   pCallback);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
+    VkInstance                                  instance,
+    VkDebugReportCallbackEXT                    callback,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
+    VkInstance                                  instance,
+    VkDebugReportFlagsEXT                       flags,
+    VkDebugReportObjectTypeEXT                  objectType,
+    uint64_t                                    object,
+    size_t                                      location,
+    int32_t                                     messageCode,
+    const char*                                 pLayerPrefix,
+    const char*                                 pMessage);
+#endif
+
+#define VK_NV_glsl_shader 1
+#define VK_NV_GLSL_SHADER_SPEC_VERSION    1
+#define VK_NV_GLSL_SHADER_EXTENSION_NAME  "VK_NV_glsl_shader"
+
+
+#define VK_EXT_depth_range_unrestricted 1
+#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1
+#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted"
+
+
+#define VK_IMG_filter_cubic 1
+#define VK_IMG_FILTER_CUBIC_SPEC_VERSION  1
+#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic"
+
+
+#define VK_AMD_rasterization_order 1
+#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
+#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order"
+
+
+typedef enum VkRasterizationOrderAMD {
+    VK_RASTERIZATION_ORDER_STRICT_AMD = 0,
+    VK_RASTERIZATION_ORDER_RELAXED_AMD = 1,
+    VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD,
+    VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD,
+    VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1),
+    VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF
+} VkRasterizationOrderAMD;
+
+typedef struct VkPipelineRasterizationStateRasterizationOrderAMD {
+    VkStructureType            sType;
+    const void*                pNext;
+    VkRasterizationOrderAMD    rasterizationOrder;
+} VkPipelineRasterizationStateRasterizationOrderAMD;
+
+
+
+#define VK_AMD_shader_trinary_minmax 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+
+
+#define VK_AMD_shader_explicit_vertex_parameter 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+
+
+#define VK_EXT_debug_marker 1
+#define VK_EXT_DEBUG_MARKER_SPEC_VERSION  4
+#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker"
+
+typedef struct VkDebugMarkerObjectNameInfoEXT {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkDebugReportObjectTypeEXT    objectType;
+    uint64_t                      object;
+    const char*                   pObjectName;
+} VkDebugMarkerObjectNameInfoEXT;
+
+typedef struct VkDebugMarkerObjectTagInfoEXT {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkDebugReportObjectTypeEXT    objectType;
+    uint64_t                      object;
+    uint64_t                      tagName;
+    size_t                        tagSize;
+    const void*                   pTag;
+} VkDebugMarkerObjectTagInfoEXT;
+
+typedef struct VkDebugMarkerMarkerInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    const char*        pMarkerName;
+    float              color[4];
+} VkDebugMarkerMarkerInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer);
+typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT(
+    VkDevice                                    device,
+    const VkDebugMarkerObjectTagInfoEXT*        pTagInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT(
+    VkDevice                                    device,
+    const VkDebugMarkerObjectNameInfoEXT*       pNameInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT(
+    VkCommandBuffer                             commandBuffer,
+    const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT(
+    VkCommandBuffer                             commandBuffer);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT(
+    VkCommandBuffer                             commandBuffer,
+    const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo);
+#endif
+
+#define VK_AMD_gcn_shader 1
+#define VK_AMD_GCN_SHADER_SPEC_VERSION    1
+#define VK_AMD_GCN_SHADER_EXTENSION_NAME  "VK_AMD_gcn_shader"
+
+
+#define VK_NV_dedicated_allocation 1
+#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
+#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
+
+typedef struct VkDedicatedAllocationImageCreateInfoNV {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           dedicatedAllocation;
+} VkDedicatedAllocationImageCreateInfoNV;
+
+typedef struct VkDedicatedAllocationBufferCreateInfoNV {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           dedicatedAllocation;
+} VkDedicatedAllocationBufferCreateInfoNV;
+
+typedef struct VkDedicatedAllocationMemoryAllocateInfoNV {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkImage            image;
+    VkBuffer           buffer;
+} VkDedicatedAllocationMemoryAllocateInfoNV;
+
+
+
+#define VK_AMD_draw_indirect_count 1
+#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
+#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
+
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    VkBuffer                                    countBuffer,
+    VkDeviceSize                                countBufferOffset,
+    uint32_t                                    maxDrawCount,
+    uint32_t                                    stride);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    VkBuffer                                    countBuffer,
+    VkDeviceSize                                countBufferOffset,
+    uint32_t                                    maxDrawCount,
+    uint32_t                                    stride);
+#endif
+
+#define VK_AMD_negative_viewport_height 1
+#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
+#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
+
+
+#define VK_AMD_gpu_shader_half_float 1
+#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
+#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
+
+
+#define VK_AMD_shader_ballot 1
+#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
+#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
+
+
+#define VK_AMD_texture_gather_bias_lod 1
+#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
+#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
+
+typedef struct VkTextureLODGatherFormatPropertiesAMD {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           supportsTextureGatherLODBiasAMD;
+} VkTextureLODGatherFormatPropertiesAMD;
+
+
+
+#define VK_AMD_shader_info 1
+#define VK_AMD_SHADER_INFO_SPEC_VERSION   1
+#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info"
+
+
+typedef enum VkShaderInfoTypeAMD {
+    VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0,
+    VK_SHADER_INFO_TYPE_BINARY_AMD = 1,
+    VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2,
+    VK_SHADER_INFO_TYPE_BEGIN_RANGE_AMD = VK_SHADER_INFO_TYPE_STATISTICS_AMD,
+    VK_SHADER_INFO_TYPE_END_RANGE_AMD = VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD,
+    VK_SHADER_INFO_TYPE_RANGE_SIZE_AMD = (VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD - VK_SHADER_INFO_TYPE_STATISTICS_AMD + 1),
+    VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF
+} VkShaderInfoTypeAMD;
+
+typedef struct VkShaderResourceUsageAMD {
+    uint32_t    numUsedVgprs;
+    uint32_t    numUsedSgprs;
+    uint32_t    ldsSizePerLocalWorkGroup;
+    size_t      ldsUsageSizeInBytes;
+    size_t      scratchMemUsageInBytes;
+} VkShaderResourceUsageAMD;
+
+typedef struct VkShaderStatisticsInfoAMD {
+    VkShaderStageFlags          shaderStageMask;
+    VkShaderResourceUsageAMD    resourceUsage;
+    uint32_t                    numPhysicalVgprs;
+    uint32_t                    numPhysicalSgprs;
+    uint32_t                    numAvailableVgprs;
+    uint32_t                    numAvailableSgprs;
+    uint32_t                    computeWorkGroupSize[3];
+} VkShaderStatisticsInfoAMD;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD(
+    VkDevice                                    device,
+    VkPipeline                                  pipeline,
+    VkShaderStageFlagBits                       shaderStage,
+    VkShaderInfoTypeAMD                         infoType,
+    size_t*                                     pInfoSize,
+    void*                                       pInfo);
+#endif
+
+#define VK_AMD_shader_image_load_store_lod 1
+#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1
+#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod"
+
+
+#define VK_IMG_format_pvrtc 1
+#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION  1
+#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
+
+
+#define VK_NV_external_memory_capabilities 1
+#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
+
+
+typedef enum VkExternalMemoryHandleTypeFlagBitsNV {
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
+    VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkExternalMemoryHandleTypeFlagBitsNV;
+typedef VkFlags VkExternalMemoryHandleTypeFlagsNV;
+
+typedef enum VkExternalMemoryFeatureFlagBitsNV {
+    VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
+    VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
+    VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
+    VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkExternalMemoryFeatureFlagBitsNV;
+typedef VkFlags VkExternalMemoryFeatureFlagsNV;
+
+typedef struct VkExternalImageFormatPropertiesNV {
+    VkImageFormatProperties              imageFormatProperties;
+    VkExternalMemoryFeatureFlagsNV       externalMemoryFeatures;
+    VkExternalMemoryHandleTypeFlagsNV    exportFromImportedHandleTypes;
+    VkExternalMemoryHandleTypeFlagsNV    compatibleHandleTypes;
+} VkExternalImageFormatPropertiesNV;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
+    VkPhysicalDevice                            physicalDevice,
+    VkFormat                                    format,
+    VkImageType                                 type,
+    VkImageTiling                               tiling,
+    VkImageUsageFlags                           usage,
+    VkImageCreateFlags                          flags,
+    VkExternalMemoryHandleTypeFlagsNV           externalHandleType,
+    VkExternalImageFormatPropertiesNV*          pExternalImageFormatProperties);
+#endif
+
+#define VK_NV_external_memory 1
+#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
+
+typedef struct VkExternalMemoryImageCreateInfoNV {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkExternalMemoryHandleTypeFlagsNV    handleTypes;
+} VkExternalMemoryImageCreateInfoNV;
+
+typedef struct VkExportMemoryAllocateInfoNV {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkExternalMemoryHandleTypeFlagsNV    handleTypes;
+} VkExportMemoryAllocateInfoNV;
+
+
+
+#define VK_EXT_validation_flags 1
+#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
+#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
+
+
+typedef enum VkValidationCheckEXT {
+    VK_VALIDATION_CHECK_ALL_EXT = 0,
+    VK_VALIDATION_CHECK_SHADERS_EXT = 1,
+    VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
+    VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT,
+    VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),
+    VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkValidationCheckEXT;
+
+typedef struct VkValidationFlagsEXT {
+    VkStructureType          sType;
+    const void*              pNext;
+    uint32_t                 disabledValidationCheckCount;
+    VkValidationCheckEXT*    pDisabledValidationChecks;
+} VkValidationFlagsEXT;
+
+
+
+#define VK_EXT_shader_subgroup_ballot 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
+
+
+#define VK_EXT_shader_subgroup_vote 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
+
+
+#define VK_NVX_device_generated_commands 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
+
+#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3
+#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
+
+
+typedef enum VkIndirectCommandsTokenTypeNVX {
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1),
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkIndirectCommandsTokenTypeNVX;
+
+typedef enum VkObjectEntryTypeNVX {
+    VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
+    VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
+    VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
+    VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
+    VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
+    VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX,
+    VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX,
+    VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1),
+    VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkObjectEntryTypeNVX;
+
+
+typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX {
+    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
+    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
+    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
+    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
+    VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkIndirectCommandsLayoutUsageFlagBitsNVX;
+typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX;
+
+typedef enum VkObjectEntryUsageFlagBitsNVX {
+    VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
+    VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
+    VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkObjectEntryUsageFlagBitsNVX;
+typedef VkFlags VkObjectEntryUsageFlagsNVX;
+
+typedef struct VkDeviceGeneratedCommandsFeaturesNVX {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           computeBindingPointSupport;
+} VkDeviceGeneratedCommandsFeaturesNVX;
+
+typedef struct VkDeviceGeneratedCommandsLimitsNVX {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           maxIndirectCommandsLayoutTokenCount;
+    uint32_t           maxObjectEntryCounts;
+    uint32_t           minSequenceCountBufferOffsetAlignment;
+    uint32_t           minSequenceIndexBufferOffsetAlignment;
+    uint32_t           minCommandsTokenBufferOffsetAlignment;
+} VkDeviceGeneratedCommandsLimitsNVX;
+
+typedef struct VkIndirectCommandsTokenNVX {
+    VkIndirectCommandsTokenTypeNVX    tokenType;
+    VkBuffer                          buffer;
+    VkDeviceSize                      offset;
+} VkIndirectCommandsTokenNVX;
+
+typedef struct VkIndirectCommandsLayoutTokenNVX {
+    VkIndirectCommandsTokenTypeNVX    tokenType;
+    uint32_t                          bindingUnit;
+    uint32_t                          dynamicCount;
+    uint32_t                          divisor;
+} VkIndirectCommandsLayoutTokenNVX;
+
+typedef struct VkIndirectCommandsLayoutCreateInfoNVX {
+    VkStructureType                            sType;
+    const void*                                pNext;
+    VkPipelineBindPoint                        pipelineBindPoint;
+    VkIndirectCommandsLayoutUsageFlagsNVX      flags;
+    uint32_t                                   tokenCount;
+    const VkIndirectCommandsLayoutTokenNVX*    pTokens;
+} VkIndirectCommandsLayoutCreateInfoNVX;
+
+typedef struct VkCmdProcessCommandsInfoNVX {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkObjectTableNVX                     objectTable;
+    VkIndirectCommandsLayoutNVX          indirectCommandsLayout;
+    uint32_t                             indirectCommandsTokenCount;
+    const VkIndirectCommandsTokenNVX*    pIndirectCommandsTokens;
+    uint32_t                             maxSequencesCount;
+    VkCommandBuffer                      targetCommandBuffer;
+    VkBuffer                             sequencesCountBuffer;
+    VkDeviceSize                         sequencesCountOffset;
+    VkBuffer                             sequencesIndexBuffer;
+    VkDeviceSize                         sequencesIndexOffset;
+} VkCmdProcessCommandsInfoNVX;
+
+typedef struct VkCmdReserveSpaceForCommandsInfoNVX {
+    VkStructureType                sType;
+    const void*                    pNext;
+    VkObjectTableNVX               objectTable;
+    VkIndirectCommandsLayoutNVX    indirectCommandsLayout;
+    uint32_t                       maxSequencesCount;
+} VkCmdReserveSpaceForCommandsInfoNVX;
+
+typedef struct VkObjectTableCreateInfoNVX {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    uint32_t                             objectCount;
+    const VkObjectEntryTypeNVX*          pObjectEntryTypes;
+    const uint32_t*                      pObjectEntryCounts;
+    const VkObjectEntryUsageFlagsNVX*    pObjectEntryUsageFlags;
+    uint32_t                             maxUniformBuffersPerDescriptor;
+    uint32_t                             maxStorageBuffersPerDescriptor;
+    uint32_t                             maxStorageImagesPerDescriptor;
+    uint32_t                             maxSampledImagesPerDescriptor;
+    uint32_t                             maxPipelineLayouts;
+} VkObjectTableCreateInfoNVX;
+
+typedef struct VkObjectTableEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+} VkObjectTableEntryNVX;
+
+typedef struct VkObjectTablePipelineEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+    VkPipeline                    pipeline;
+} VkObjectTablePipelineEntryNVX;
+
+typedef struct VkObjectTableDescriptorSetEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+    VkPipelineLayout              pipelineLayout;
+    VkDescriptorSet               descriptorSet;
+} VkObjectTableDescriptorSetEntryNVX;
+
+typedef struct VkObjectTableVertexBufferEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+    VkBuffer                      buffer;
+} VkObjectTableVertexBufferEntryNVX;
+
+typedef struct VkObjectTableIndexBufferEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+    VkBuffer                      buffer;
+    VkIndexType                   indexType;
+} VkObjectTableIndexBufferEntryNVX;
+
+typedef struct VkObjectTablePushConstantEntryNVX {
+    VkObjectEntryTypeNVX          type;
+    VkObjectEntryUsageFlagsNVX    flags;
+    VkPipelineLayout              pipelineLayout;
+    VkShaderStageFlags            stageFlags;
+} VkObjectTablePushConstantEntryNVX;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);
+typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable);
+typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const*    ppObjectTableEntries, const uint32_t* pObjectIndices);
+typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX(
+    VkCommandBuffer                             commandBuffer,
+    const VkCmdProcessCommandsInfoNVX*          pProcessCommandsInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX(
+    VkCommandBuffer                             commandBuffer,
+    const VkCmdReserveSpaceForCommandsInfoNVX*  pReserveSpaceInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX(
+    VkDevice                                    device,
+    const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkIndirectCommandsLayoutNVX*                pIndirectCommandsLayout);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX(
+    VkDevice                                    device,
+    VkIndirectCommandsLayoutNVX                 indirectCommandsLayout,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX(
+    VkDevice                                    device,
+    const VkObjectTableCreateInfoNVX*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkObjectTableNVX*                           pObjectTable);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX(
+    VkDevice                                    device,
+    VkObjectTableNVX                            objectTable,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX(
+    VkDevice                                    device,
+    VkObjectTableNVX                            objectTable,
+    uint32_t                                    objectCount,
+    const VkObjectTableEntryNVX* const*         ppObjectTableEntries,
+    const uint32_t*                             pObjectIndices);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX(
+    VkDevice                                    device,
+    VkObjectTableNVX                            objectTable,
+    uint32_t                                    objectCount,
+    const VkObjectEntryTypeNVX*                 pObjectEntryTypes,
+    const uint32_t*                             pObjectIndices);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
+    VkPhysicalDevice                            physicalDevice,
+    VkDeviceGeneratedCommandsFeaturesNVX*       pFeatures,
+    VkDeviceGeneratedCommandsLimitsNVX*         pLimits);
+#endif
+
+#define VK_NV_clip_space_w_scaling 1
+#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1
+#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling"
+
+typedef struct VkViewportWScalingNV {
+    float    xcoeff;
+    float    ycoeff;
+} VkViewportWScalingNV;
+
+typedef struct VkPipelineViewportWScalingStateCreateInfoNV {
+    VkStructureType                sType;
+    const void*                    pNext;
+    VkBool32                       viewportWScalingEnable;
+    uint32_t                       viewportCount;
+    const VkViewportWScalingNV*    pViewportWScalings;
+} VkPipelineViewportWScalingStateCreateInfoNV;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstViewport,
+    uint32_t                                    viewportCount,
+    const VkViewportWScalingNV*                 pViewportWScalings);
+#endif
+
+#define VK_EXT_direct_mode_display 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
+
+typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT(
+    VkPhysicalDevice                            physicalDevice,
+    VkDisplayKHR                                display);
+#endif
+
+#define VK_EXT_display_surface_counter 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
+#define VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT
+
+
+typedef enum VkSurfaceCounterFlagBitsEXT {
+    VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
+    VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSurfaceCounterFlagBitsEXT;
+typedef VkFlags VkSurfaceCounterFlagsEXT;
+
+typedef struct VkSurfaceCapabilities2EXT {
+    VkStructureType                  sType;
+    void*                            pNext;
+    uint32_t                         minImageCount;
+    uint32_t                         maxImageCount;
+    VkExtent2D                       currentExtent;
+    VkExtent2D                       minImageExtent;
+    VkExtent2D                       maxImageExtent;
+    uint32_t                         maxImageArrayLayers;
+    VkSurfaceTransformFlagsKHR       supportedTransforms;
+    VkSurfaceTransformFlagBitsKHR    currentTransform;
+    VkCompositeAlphaFlagsKHR         supportedCompositeAlpha;
+    VkImageUsageFlags                supportedUsageFlags;
+    VkSurfaceCounterFlagsEXT         supportedSurfaceCounters;
+} VkSurfaceCapabilities2EXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+    VkPhysicalDevice                            physicalDevice,
+    VkSurfaceKHR                                surface,
+    VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities);
+#endif
+
+#define VK_EXT_display_control 1
+#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control"
+
+
+typedef enum VkDisplayPowerStateEXT {
+    VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
+    VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
+    VK_DISPLAY_POWER_STATE_ON_EXT = 2,
+    VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT,
+    VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT,
+    VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1),
+    VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayPowerStateEXT;
+
+typedef enum VkDeviceEventTypeEXT {
+    VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
+    VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+    VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+    VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1),
+    VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDeviceEventTypeEXT;
+
+typedef enum VkDisplayEventTypeEXT {
+    VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
+    VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+    VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+    VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1),
+    VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayEventTypeEXT;
+
+typedef struct VkDisplayPowerInfoEXT {
+    VkStructureType           sType;
+    const void*               pNext;
+    VkDisplayPowerStateEXT    powerState;
+} VkDisplayPowerInfoEXT;
+
+typedef struct VkDeviceEventInfoEXT {
+    VkStructureType         sType;
+    const void*             pNext;
+    VkDeviceEventTypeEXT    deviceEvent;
+} VkDeviceEventInfoEXT;
+
+typedef struct VkDisplayEventInfoEXT {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkDisplayEventTypeEXT    displayEvent;
+} VkDisplayEventInfoEXT;
+
+typedef struct VkSwapchainCounterCreateInfoEXT {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkSurfaceCounterFlagsEXT    surfaceCounters;
+} VkSwapchainCounterCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT(
+    VkDevice                                    device,
+    VkDisplayKHR                                display,
+    const VkDisplayPowerInfoEXT*                pDisplayPowerInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT(
+    VkDevice                                    device,
+    const VkDeviceEventInfoEXT*                 pDeviceEventInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFence*                                    pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT(
+    VkDevice                                    device,
+    VkDisplayKHR                                display,
+    const VkDisplayEventInfoEXT*                pDisplayEventInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkFence*                                    pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    VkSurfaceCounterFlagBitsEXT                 counter,
+    uint64_t*                                   pCounterValue);
+#endif
+
+#define VK_GOOGLE_display_timing 1
+#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
+#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
+
+typedef struct VkRefreshCycleDurationGOOGLE {
+    uint64_t    refreshDuration;
+} VkRefreshCycleDurationGOOGLE;
+
+typedef struct VkPastPresentationTimingGOOGLE {
+    uint32_t    presentID;
+    uint64_t    desiredPresentTime;
+    uint64_t    actualPresentTime;
+    uint64_t    earliestPresentTime;
+    uint64_t    presentMargin;
+} VkPastPresentationTimingGOOGLE;
+
+typedef struct VkPresentTimeGOOGLE {
+    uint32_t    presentID;
+    uint64_t    desiredPresentTime;
+} VkPresentTimeGOOGLE;
+
+typedef struct VkPresentTimesInfoGOOGLE {
+    VkStructureType               sType;
+    const void*                   pNext;
+    uint32_t                      swapchainCount;
+    const VkPresentTimeGOOGLE*    pTimes;
+} VkPresentTimesInfoGOOGLE;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    VkRefreshCycleDurationGOOGLE*               pDisplayTimingProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain,
+    uint32_t*                                   pPresentationTimingCount,
+    VkPastPresentationTimingGOOGLE*             pPresentationTimings);
+#endif
+
+#define VK_NV_sample_mask_override_coverage 1
+#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1
+#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage"
+
+
+#define VK_NV_geometry_shader_passthrough 1
+#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1
+#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough"
+
+
+#define VK_NV_viewport_array2 1
+#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1
+#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2"
+
+
+#define VK_NVX_multiview_per_view_attributes 1
+#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1
+#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes"
+
+typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           perViewPositionAllComponents;
+} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX;
+
+
+
+#define VK_NV_viewport_swizzle 1
+#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1
+#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle"
+
+
+typedef enum VkViewportCoordinateSwizzleNV {
+    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV,
+    VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1),
+    VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkViewportCoordinateSwizzleNV;
+
+typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;
+
+typedef struct VkViewportSwizzleNV {
+    VkViewportCoordinateSwizzleNV    x;
+    VkViewportCoordinateSwizzleNV    y;
+    VkViewportCoordinateSwizzleNV    z;
+    VkViewportCoordinateSwizzleNV    w;
+} VkViewportSwizzleNV;
+
+typedef struct VkPipelineViewportSwizzleStateCreateInfoNV {
+    VkStructureType                                sType;
+    const void*                                    pNext;
+    VkPipelineViewportSwizzleStateCreateFlagsNV    flags;
+    uint32_t                                       viewportCount;
+    const VkViewportSwizzleNV*                     pViewportSwizzles;
+} VkPipelineViewportSwizzleStateCreateInfoNV;
+
+
+
+#define VK_EXT_discard_rectangles 1
+#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
+#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
+
+
+typedef enum VkDiscardRectangleModeEXT {
+    VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,
+    VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
+    VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT,
+    VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT,
+    VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1),
+    VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDiscardRectangleModeEXT;
+
+typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxDiscardRectangles;
+} VkPhysicalDeviceDiscardRectanglePropertiesEXT;
+
+typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT {
+    VkStructureType                                  sType;
+    const void*                                      pNext;
+    VkPipelineDiscardRectangleStateCreateFlagsEXT    flags;
+    VkDiscardRectangleModeEXT                        discardRectangleMode;
+    uint32_t                                         discardRectangleCount;
+    const VkRect2D*                                  pDiscardRectangles;
+} VkPipelineDiscardRectangleStateCreateInfoEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstDiscardRectangle,
+    uint32_t                                    discardRectangleCount,
+    const VkRect2D*                             pDiscardRectangles);
+#endif
+
+#define VK_EXT_conservative_rasterization 1
+#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1
+#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization"
+
+
+typedef enum VkConservativeRasterizationModeEXT {
+    VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_BEGIN_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_END_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT,
+    VK_CONSERVATIVE_RASTERIZATION_MODE_RANGE_SIZE_EXT = (VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT + 1),
+    VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkConservativeRasterizationModeEXT;
+
+typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    float              primitiveOverestimationSize;
+    float              maxExtraPrimitiveOverestimationSize;
+    float              extraPrimitiveOverestimationSizeGranularity;
+    VkBool32           primitiveUnderestimation;
+    VkBool32           conservativePointAndLineRasterization;
+    VkBool32           degenerateTrianglesRasterized;
+    VkBool32           degenerateLinesRasterized;
+    VkBool32           fullyCoveredFragmentShaderInputVariable;
+    VkBool32           conservativeRasterizationPostDepthCoverage;
+} VkPhysicalDeviceConservativeRasterizationPropertiesEXT;
+
+typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT {
+    VkStructureType                                           sType;
+    const void*                                               pNext;
+    VkPipelineRasterizationConservativeStateCreateFlagsEXT    flags;
+    VkConservativeRasterizationModeEXT                        conservativeRasterizationMode;
+    float                                                     extraPrimitiveOverestimationSize;
+} VkPipelineRasterizationConservativeStateCreateInfoEXT;
+
+
+
+#define VK_EXT_swapchain_colorspace 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
+
+#define VK_EXT_hdr_metadata 1
+#define VK_EXT_HDR_METADATA_SPEC_VERSION  1
+#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
+
+typedef struct VkXYColorEXT {
+    float    x;
+    float    y;
+} VkXYColorEXT;
+
+typedef struct VkHdrMetadataEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkXYColorEXT       displayPrimaryRed;
+    VkXYColorEXT       displayPrimaryGreen;
+    VkXYColorEXT       displayPrimaryBlue;
+    VkXYColorEXT       whitePoint;
+    float              maxLuminance;
+    float              minLuminance;
+    float              maxContentLightLevel;
+    float              maxFrameAverageLightLevel;
+} VkHdrMetadataEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT(
+    VkDevice                                    device,
+    uint32_t                                    swapchainCount,
+    const VkSwapchainKHR*                       pSwapchains,
+    const VkHdrMetadataEXT*                     pMetadata);
+#endif
+
+#define VK_EXT_external_memory_dma_buf 1
+#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1
+#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf"
+
+
+#define VK_EXT_queue_family_foreign 1
+#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1
+#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign"
+#define VK_QUEUE_FAMILY_FOREIGN_EXT       (~0U-2)
+
+
+#define VK_EXT_debug_utils 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT)
+
+#define VK_EXT_DEBUG_UTILS_SPEC_VERSION   1
+#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils"
+
+typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT;
+typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT;
+
+typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT {
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000,
+    VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDebugUtilsMessageSeverityFlagBitsEXT;
+typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT;
+
+typedef enum VkDebugUtilsMessageTypeFlagBitsEXT {
+    VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001,
+    VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002,
+    VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004,
+    VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDebugUtilsMessageTypeFlagBitsEXT;
+typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT;
+
+typedef struct VkDebugUtilsObjectNameInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkObjectType       objectType;
+    uint64_t           objectHandle;
+    const char*        pObjectName;
+} VkDebugUtilsObjectNameInfoEXT;
+
+typedef struct VkDebugUtilsObjectTagInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkObjectType       objectType;
+    uint64_t           objectHandle;
+    uint64_t           tagName;
+    size_t             tagSize;
+    const void*        pTag;
+} VkDebugUtilsObjectTagInfoEXT;
+
+typedef struct VkDebugUtilsLabelEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    const char*        pLabelName;
+    float              color[4];
+} VkDebugUtilsLabelEXT;
+
+typedef struct VkDebugUtilsMessengerCallbackDataEXT {
+    VkStructureType                              sType;
+    const void*                                  pNext;
+    VkDebugUtilsMessengerCallbackDataFlagsEXT    flags;
+    const char*                                  pMessageIdName;
+    int32_t                                      messageIdNumber;
+    const char*                                  pMessage;
+    uint32_t                                     queueLabelCount;
+    VkDebugUtilsLabelEXT*                        pQueueLabels;
+    uint32_t                                     cmdBufLabelCount;
+    VkDebugUtilsLabelEXT*                        pCmdBufLabels;
+    uint32_t                                     objectCount;
+    VkDebugUtilsObjectNameInfoEXT*               pObjects;
+} VkDebugUtilsMessengerCallbackDataEXT;
+
+typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)(
+    VkDebugUtilsMessageSeverityFlagBitsEXT           messageSeverity,
+    VkDebugUtilsMessageTypeFlagsEXT                  messageType,
+    const VkDebugUtilsMessengerCallbackDataEXT*      pCallbackData,
+    void*                                            pUserData);
+
+typedef struct VkDebugUtilsMessengerCreateInfoEXT {
+    VkStructureType                         sType;
+    const void*                             pNext;
+    VkDebugUtilsMessengerCreateFlagsEXT     flags;
+    VkDebugUtilsMessageSeverityFlagsEXT     messageSeverity;
+    VkDebugUtilsMessageTypeFlagsEXT         messageType;
+    PFN_vkDebugUtilsMessengerCallbackEXT    pfnUserCallback;
+    void*                                   pUserData;
+} VkDebugUtilsMessengerCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo);
+typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo);
+typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue);
+typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer);
+typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger);
+typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT(
+    VkDevice                                    device,
+    const VkDebugUtilsObjectNameInfoEXT*        pNameInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT(
+    VkDevice                                    device,
+    const VkDebugUtilsObjectTagInfoEXT*         pTagInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT(
+    VkQueue                                     queue,
+    const VkDebugUtilsLabelEXT*                 pLabelInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT(
+    VkQueue                                     queue);
+
+VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT(
+    VkQueue                                     queue,
+    const VkDebugUtilsLabelEXT*                 pLabelInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT(
+    VkCommandBuffer                             commandBuffer,
+    const VkDebugUtilsLabelEXT*                 pLabelInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT(
+    VkCommandBuffer                             commandBuffer);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT(
+    VkCommandBuffer                             commandBuffer,
+    const VkDebugUtilsLabelEXT*                 pLabelInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(
+    VkInstance                                  instance,
+    const VkDebugUtilsMessengerCreateInfoEXT*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDebugUtilsMessengerEXT*                   pMessenger);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(
+    VkInstance                                  instance,
+    VkDebugUtilsMessengerEXT                    messenger,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(
+    VkInstance                                  instance,
+    VkDebugUtilsMessageSeverityFlagBitsEXT      messageSeverity,
+    VkDebugUtilsMessageTypeFlagsEXT             messageTypes,
+    const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData);
+#endif
+
+#define VK_EXT_sampler_filter_minmax 1
+#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
+#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
+
+
+typedef enum VkSamplerReductionModeEXT {
+    VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0,
+    VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1,
+    VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2,
+    VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT,
+    VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT,
+    VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1),
+    VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSamplerReductionModeEXT;
+
+typedef struct VkSamplerReductionModeCreateInfoEXT {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkSamplerReductionModeEXT    reductionMode;
+} VkSamplerReductionModeCreateInfoEXT;
+
+typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           filterMinmaxSingleComponentFormats;
+    VkBool32           filterMinmaxImageComponentMapping;
+} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT;
+
+
+
+#define VK_AMD_gpu_shader_int16 1
+#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
+#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
+
+
+#define VK_AMD_mixed_attachment_samples 1
+#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1
+#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples"
+
+
+#define VK_AMD_shader_fragment_mask 1
+#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
+#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
+
+
+#define VK_EXT_shader_stencil_export 1
+#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
+#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
+
+
+#define VK_EXT_sample_locations 1
+#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1
+#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations"
+
+typedef struct VkSampleLocationEXT {
+    float    x;
+    float    y;
+} VkSampleLocationEXT;
+
+typedef struct VkSampleLocationsInfoEXT {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkSampleCountFlagBits         sampleLocationsPerPixel;
+    VkExtent2D                    sampleLocationGridSize;
+    uint32_t                      sampleLocationsCount;
+    const VkSampleLocationEXT*    pSampleLocations;
+} VkSampleLocationsInfoEXT;
+
+typedef struct VkAttachmentSampleLocationsEXT {
+    uint32_t                    attachmentIndex;
+    VkSampleLocationsInfoEXT    sampleLocationsInfo;
+} VkAttachmentSampleLocationsEXT;
+
+typedef struct VkSubpassSampleLocationsEXT {
+    uint32_t                    subpassIndex;
+    VkSampleLocationsInfoEXT    sampleLocationsInfo;
+} VkSubpassSampleLocationsEXT;
+
+typedef struct VkRenderPassSampleLocationsBeginInfoEXT {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    uint32_t                                 attachmentInitialSampleLocationsCount;
+    const VkAttachmentSampleLocationsEXT*    pAttachmentInitialSampleLocations;
+    uint32_t                                 postSubpassSampleLocationsCount;
+    const VkSubpassSampleLocationsEXT*       pPostSubpassSampleLocations;
+} VkRenderPassSampleLocationsBeginInfoEXT;
+
+typedef struct VkPipelineSampleLocationsStateCreateInfoEXT {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkBool32                    sampleLocationsEnable;
+    VkSampleLocationsInfoEXT    sampleLocationsInfo;
+} VkPipelineSampleLocationsStateCreateInfoEXT;
+
+typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkSampleCountFlags    sampleLocationSampleCounts;
+    VkExtent2D            maxSampleLocationGridSize;
+    float                 sampleLocationCoordinateRange[2];
+    uint32_t              sampleLocationSubPixelBits;
+    VkBool32              variableSampleLocations;
+} VkPhysicalDeviceSampleLocationsPropertiesEXT;
+
+typedef struct VkMultisamplePropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkExtent2D         maxSampleLocationGridSize;
+} VkMultisamplePropertiesEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT(
+    VkCommandBuffer                             commandBuffer,
+    const VkSampleLocationsInfoEXT*             pSampleLocationsInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT(
+    VkPhysicalDevice                            physicalDevice,
+    VkSampleCountFlagBits                       samples,
+    VkMultisamplePropertiesEXT*                 pMultisampleProperties);
+#endif
+
+#define VK_EXT_blend_operation_advanced 1
+#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
+#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
+
+
+typedef enum VkBlendOverlapEXT {
+    VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0,
+    VK_BLEND_OVERLAP_DISJOINT_EXT = 1,
+    VK_BLEND_OVERLAP_CONJOINT_EXT = 2,
+    VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT,
+    VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT,
+    VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1),
+    VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkBlendOverlapEXT;
+
+typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           advancedBlendCoherentOperations;
+} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT;
+
+typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           advancedBlendMaxColorAttachments;
+    VkBool32           advancedBlendIndependentBlend;
+    VkBool32           advancedBlendNonPremultipliedSrcColor;
+    VkBool32           advancedBlendNonPremultipliedDstColor;
+    VkBool32           advancedBlendCorrelatedOverlap;
+    VkBool32           advancedBlendAllOperations;
+} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT;
+
+typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT {
+    VkStructureType      sType;
+    const void*          pNext;
+    VkBool32             srcPremultiplied;
+    VkBool32             dstPremultiplied;
+    VkBlendOverlapEXT    blendOverlap;
+} VkPipelineColorBlendAdvancedStateCreateInfoEXT;
+
+
+
+#define VK_NV_fragment_coverage_to_color 1
+#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1
+#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color"
+
+typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV;
+
+typedef struct VkPipelineCoverageToColorStateCreateInfoNV {
+    VkStructureType                                sType;
+    const void*                                    pNext;
+    VkPipelineCoverageToColorStateCreateFlagsNV    flags;
+    VkBool32                                       coverageToColorEnable;
+    uint32_t                                       coverageToColorLocation;
+} VkPipelineCoverageToColorStateCreateInfoNV;
+
+
+
+#define VK_NV_framebuffer_mixed_samples 1
+#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1
+#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples"
+
+
+typedef enum VkCoverageModulationModeNV {
+    VK_COVERAGE_MODULATION_MODE_NONE_NV = 0,
+    VK_COVERAGE_MODULATION_MODE_RGB_NV = 1,
+    VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2,
+    VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3,
+    VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV,
+    VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV,
+    VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1),
+    VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkCoverageModulationModeNV;
+
+typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV;
+
+typedef struct VkPipelineCoverageModulationStateCreateInfoNV {
+    VkStructureType                                   sType;
+    const void*                                       pNext;
+    VkPipelineCoverageModulationStateCreateFlagsNV    flags;
+    VkCoverageModulationModeNV                        coverageModulationMode;
+    VkBool32                                          coverageModulationTableEnable;
+    uint32_t                                          coverageModulationTableCount;
+    const float*                                      pCoverageModulationTable;
+} VkPipelineCoverageModulationStateCreateInfoNV;
+
+
+
+#define VK_NV_fill_rectangle 1
+#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
+#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
+
+
+#define VK_EXT_post_depth_coverage 1
+#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1
+#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
+
+
+#define VK_EXT_validation_cache 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT)
+
+#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
+#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
+#define VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT
+
+
+typedef enum VkValidationCacheHeaderVersionEXT {
+    VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1,
+    VK_VALIDATION_CACHE_HEADER_VERSION_BEGIN_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT,
+    VK_VALIDATION_CACHE_HEADER_VERSION_END_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT,
+    VK_VALIDATION_CACHE_HEADER_VERSION_RANGE_SIZE_EXT = (VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT + 1),
+    VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkValidationCacheHeaderVersionEXT;
+
+typedef VkFlags VkValidationCacheCreateFlagsEXT;
+
+typedef struct VkValidationCacheCreateInfoEXT {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkValidationCacheCreateFlagsEXT    flags;
+    size_t                             initialDataSize;
+    const void*                        pInitialData;
+} VkValidationCacheCreateInfoEXT;
+
+typedef struct VkShaderModuleValidationCacheCreateInfoEXT {
+    VkStructureType         sType;
+    const void*             pNext;
+    VkValidationCacheEXT    validationCache;
+} VkShaderModuleValidationCacheCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache);
+typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches);
+typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT(
+    VkDevice                                    device,
+    const VkValidationCacheCreateInfoEXT*       pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkValidationCacheEXT*                       pValidationCache);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        validationCache,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        dstCache,
+    uint32_t                                    srcCacheCount,
+    const VkValidationCacheEXT*                 pSrcCaches);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT(
+    VkDevice                                    device,
+    VkValidationCacheEXT                        validationCache,
+    size_t*                                     pDataSize,
+    void*                                       pData);
+#endif
+
+#define VK_EXT_shader_viewport_index_layer 1
+#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1
+#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer"
+
+
+#define VK_EXT_global_priority 1
+#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2
+#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority"
+
+
+typedef enum VkQueueGlobalPriorityEXT {
+    VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128,
+    VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256,
+    VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512,
+    VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024,
+    VK_QUEUE_GLOBAL_PRIORITY_BEGIN_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT,
+    VK_QUEUE_GLOBAL_PRIORITY_END_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT,
+    VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE_EXT = (VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT + 1),
+    VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkQueueGlobalPriorityEXT;
+
+typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT {
+    VkStructureType             sType;
+    const void*                 pNext;
+    VkQueueGlobalPriorityEXT    globalPriority;
+} VkDeviceQueueGlobalPriorityCreateInfoEXT;
+
+
+
+#define VK_EXT_external_memory_host 1
+#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1
+#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host"
+
+typedef struct VkImportMemoryHostPointerInfoEXT {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkExternalMemoryHandleTypeFlagBits    handleType;
+    void*                                 pHostPointer;
+} VkImportMemoryHostPointerInfoEXT;
+
+typedef struct VkMemoryHostPointerPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           memoryTypeBits;
+} VkMemoryHostPointerPropertiesEXT;
+
+typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkDeviceSize       minImportedHostPointerAlignment;
+} VkPhysicalDeviceExternalMemoryHostPropertiesEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(
+    VkDevice                                    device,
+    VkExternalMemoryHandleTypeFlagBits          handleType,
+    const void*                                 pHostPointer,
+    VkMemoryHostPointerPropertiesEXT*           pMemoryHostPointerProperties);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/vulkan/include/vulkan/vulkan_loader_data.h b/vulkan/include/vulkan/vulkan_loader_data.h
deleted file mode 100644
index 8ea4666..0000000
--- a/vulkan/include/vulkan/vulkan_loader_data.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2015 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 VULKAN_VULKAN_LOADER_DATA_H
-#define VULKAN_VULKAN_LOADER_DATA_H
-
-#include <string>
-
-struct android_namespace_t;
-
-namespace vulkan {
-    struct LoaderData {
-        std::string layer_path;
-        android_namespace_t* app_namespace;
-
-        __attribute__((visibility("default"))) static LoaderData& GetInstance();
-    };
-}
-
-#endif
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 5f9b357..7f4f2c4 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -61,7 +61,6 @@
         "layers_extensions.cpp",
         "stubhal.cpp",
         "swapchain.cpp",
-        "vulkan_loader_data.cpp",
     ],
 
     export_header_lib_headers: ["vulkan_headers"],
@@ -69,10 +68,14 @@
         "vulkan_headers",
     ],
     shared_libs: [
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
         "libziparchive",
         "libhardware",
         "libsync",
         "libbase",
+        "libhidlbase",
+        "libhidltransport",
         "liblog",
         "libui",
         "libgraphicsenv",
@@ -80,6 +83,7 @@
         "libcutils",
         "libz",
         "libnativewindow",
+        "android.hardware.graphics.common@1.0",
     ],
     static_libs: ["libgrallocusage"],
 }
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index e05ca5a..673a066 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -29,14 +29,17 @@
 #include <new>
 #include <utility>
 
+#include <android-base/strings.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 
 #include <vulkan/vk_layer_interface.h>
+#include <graphicsenv/GraphicsEnv.h>
 #include "api.h"
 #include "driver.h"
 #include "layers_extensions.h"
 
+
 namespace vulkan {
 namespace api {
 
@@ -121,15 +124,33 @@
         if (!is_instance_ || !driver::Debuggable())
             return;
 
-        ParseDebugVulkanLayers();
-        property_list(ParseDebugVulkanLayer, this);
+        GetLayersFromSettings();
 
-        // sort by priorities
-        auto& arr = implicit_layers_;
-        std::sort(arr.elements, arr.elements + arr.count,
-                  [](const ImplicitLayer& a, const ImplicitLayer& b) {
-                      return (a.priority < b.priority);
-                  });
+        // If no layers specified via Settings, check legacy properties
+        if (implicit_layers_.count <= 0) {
+            ParseDebugVulkanLayers();
+            property_list(ParseDebugVulkanLayer, this);
+
+            // sort by priorities
+            auto& arr = implicit_layers_;
+            std::sort(arr.elements, arr.elements + arr.count,
+                      [](const ImplicitLayer& a, const ImplicitLayer& b) {
+                          return (a.priority < b.priority);
+                      });
+        }
+    }
+
+    void GetLayersFromSettings() {
+        // These will only be available if conditions are met in GraphicsEnvironemnt
+        // gpu_debug_layers = layer1:layer2:layerN
+        const std::string layers = android::GraphicsEnv::getInstance().getDebugLayers();
+        if (!layers.empty()) {
+            ALOGV("Debug layer list: %s", layers.c_str());
+            std::vector<std::string> paths = android::base::Split(layers, ":");
+            for (uint32_t i = 0; i < paths.size(); i++) {
+                AddImplicitLayer(int(i), paths[i].c_str(), paths[i].length());
+            }
+        }
     }
 
     void ParseDebugVulkanLayers() {
@@ -1280,5 +1301,10 @@
         physicalDevice, nullptr, pPropertyCount, pProperties);
 }
 
+VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+    *pApiVersion = VK_API_VERSION_1_1;
+    return VK_SUCCESS;
+}
+
 }  // namespace api
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/api.h b/vulkan/libvulkan/api.h
index ded7d17..416cba0 100644
--- a/vulkan/libvulkan/api.h
+++ b/vulkan/libvulkan/api.h
@@ -33,6 +33,7 @@
 VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
 VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);
 VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
 // clang-format on
 
 inline InstanceData& GetData(VkInstance instance) {
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 001eaf1..7650e0c 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -103,11 +103,41 @@
     return VK_SUCCESS;
 }
 
+VKAPI_ATTR VkResult disabledGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR*) {
+    driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupPresentCapabilitiesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR*) {
+    driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkGetDeviceGroupSurfacePresentModesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) {
+    driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR*, uint32_t*) {
+    driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImage2KHR not executed.");
+    return VK_SUCCESS;
+}
+
 VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
     driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed.");
     return VK_SUCCESS;
 }
 
+VKAPI_ATTR VkResult disabledGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer*, VkAndroidHardwareBufferPropertiesANDROID*) {
+    driver::Logger(device).Err(device, "VK_ANDROID_external_memory_android_hardware_buffer not enabled. Exported vkGetAndroidHardwareBufferPropertiesANDROID not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID*, struct AHardwareBuffer**) {
+    driver::Logger(device).Err(device, "VK_ANDROID_external_memory_android_hardware_buffer not enabled. Exported vkGetMemoryAndroidHardwareBufferANDROID not executed.");
+    return VK_SUCCESS;
+}
+
 // clang-format on
 
 }  // namespace
@@ -132,11 +162,23 @@
     INIT_PROC(true, instance, CreateDevice);
     INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
     INIT_PROC(true, instance, GetPhysicalDeviceSparseImageFormatProperties);
+    INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+    INIT_PROC(false, instance, GetPhysicalDeviceFeatures2);
+    INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceImageFormatProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceQueueFamilyProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2);
+    INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties);
+    INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
+    INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties);
     INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR);
     INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR);
     INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
     INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR);
     INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR);
+    INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR);
     INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR);
     // clang-format on
 
@@ -272,11 +314,32 @@
     INIT_PROC(true, dev, CmdNextSubpass);
     INIT_PROC(true, dev, CmdEndRenderPass);
     INIT_PROC(true, dev, CmdExecuteCommands);
+    INIT_PROC(false, dev, BindBufferMemory2);
+    INIT_PROC(false, dev, BindImageMemory2);
+    INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures);
+    INIT_PROC(false, dev, CmdSetDeviceMask);
+    INIT_PROC(false, dev, CmdDispatchBase);
+    INIT_PROC(false, dev, GetImageMemoryRequirements2);
+    INIT_PROC(false, dev, GetBufferMemoryRequirements2);
+    INIT_PROC(false, dev, GetImageSparseMemoryRequirements2);
+    INIT_PROC(false, dev, TrimCommandPool);
+    INIT_PROC(false, dev, GetDeviceQueue2);
+    INIT_PROC(false, dev, CreateSamplerYcbcrConversion);
+    INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
+    INIT_PROC(false, dev, CreateDescriptorUpdateTemplate);
+    INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate);
+    INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate);
+    INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
     INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR);
     INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR);
     INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR);
     INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR);
     INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR);
+    INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR);
+    INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR);
+    INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR);
+    INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetAndroidHardwareBufferPropertiesANDROID);
+    INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetMemoryAndroidHardwareBufferANDROID);
     // clang-format on
 
     return success;
@@ -416,6 +479,33 @@
 VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
 VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
 VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
 VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);
 VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
@@ -426,7 +516,13 @@
 VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
 VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
 VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
 VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
+VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
 
 VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
     return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -441,38 +537,53 @@
     static const char* const known_non_device_names[] = {
         "vkCreateAndroidSurfaceKHR",
         "vkCreateDebugReportCallbackEXT",
+        "vkCreateDebugUtilsMessengerEXT",
         "vkCreateDevice",
         "vkCreateInstance",
         "vkDebugReportMessageEXT",
         "vkDestroyDebugReportCallbackEXT",
+        "vkDestroyDebugUtilsMessengerEXT",
         "vkDestroyInstance",
         "vkDestroySurfaceKHR",
         "vkEnumerateDeviceExtensionProperties",
         "vkEnumerateDeviceLayerProperties",
         "vkEnumerateInstanceExtensionProperties",
         "vkEnumerateInstanceLayerProperties",
-        "vkEnumeratePhysicalDeviceGroupsKHX",
+        "vkEnumerateInstanceVersion",
+        "vkEnumeratePhysicalDeviceGroups",
+        "vkEnumeratePhysicalDeviceGroupsKHR",
         "vkEnumeratePhysicalDevices",
         "vkGetInstanceProcAddr",
+        "vkGetPhysicalDeviceExternalBufferProperties",
         "vkGetPhysicalDeviceExternalBufferPropertiesKHR",
+        "vkGetPhysicalDeviceExternalFenceProperties",
         "vkGetPhysicalDeviceExternalFencePropertiesKHR",
         "vkGetPhysicalDeviceExternalImageFormatPropertiesNV",
+        "vkGetPhysicalDeviceExternalSemaphoreProperties",
         "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
         "vkGetPhysicalDeviceFeatures",
+        "vkGetPhysicalDeviceFeatures2",
         "vkGetPhysicalDeviceFeatures2KHR",
         "vkGetPhysicalDeviceFormatProperties",
+        "vkGetPhysicalDeviceFormatProperties2",
         "vkGetPhysicalDeviceFormatProperties2KHR",
         "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
         "vkGetPhysicalDeviceImageFormatProperties",
+        "vkGetPhysicalDeviceImageFormatProperties2",
         "vkGetPhysicalDeviceImageFormatProperties2KHR",
         "vkGetPhysicalDeviceMemoryProperties",
+        "vkGetPhysicalDeviceMemoryProperties2",
         "vkGetPhysicalDeviceMemoryProperties2KHR",
-        "vkGetPhysicalDevicePresentRectanglesKHX",
+        "vkGetPhysicalDeviceMultisamplePropertiesEXT",
+        "vkGetPhysicalDevicePresentRectanglesKHR",
         "vkGetPhysicalDeviceProperties",
+        "vkGetPhysicalDeviceProperties2",
         "vkGetPhysicalDeviceProperties2KHR",
         "vkGetPhysicalDeviceQueueFamilyProperties",
+        "vkGetPhysicalDeviceQueueFamilyProperties2",
         "vkGetPhysicalDeviceQueueFamilyProperties2KHR",
         "vkGetPhysicalDeviceSparseImageFormatProperties",
+        "vkGetPhysicalDeviceSparseImageFormatProperties2",
         "vkGetPhysicalDeviceSparseImageFormatProperties2KHR",
         "vkGetPhysicalDeviceSurfaceCapabilities2KHR",
         "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
@@ -480,6 +591,7 @@
         "vkGetPhysicalDeviceSurfaceFormatsKHR",
         "vkGetPhysicalDeviceSurfacePresentModesKHR",
         "vkGetPhysicalDeviceSurfaceSupportKHR",
+        "vkSubmitDebugUtilsMessageEXT",
     };
     // clang-format on
     constexpr size_t count =
@@ -507,6 +619,7 @@
         if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
         if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties);
         if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties);
+        if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
 
         ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName);
         return nullptr;
@@ -516,13 +629,16 @@
         const char* name;
         PFN_vkVoidFunction proc;
     } hooks[] = {
+        { "vkAcquireNextImage2KHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR) },
         { "vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR) },
         { "vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers) },
         { "vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(AllocateDescriptorSets) },
         { "vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(AllocateMemory) },
         { "vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(BeginCommandBuffer) },
         { "vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory) },
+        { "vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindBufferMemory2) },
         { "vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory) },
+        { "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
         { "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
         { "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
         { "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
@@ -539,6 +655,7 @@
         { "vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyImageToBuffer) },
         { "vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(CmdCopyQueryPoolResults) },
         { "vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatch) },
+        { "vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchBase) },
         { "vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDispatchIndirect) },
         { "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
         { "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
@@ -557,6 +674,7 @@
         { "vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdSetBlendConstants) },
         { "vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBias) },
         { "vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDepthBounds) },
+        { "vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(CmdSetDeviceMask) },
         { "vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdSetEvent) },
         { "vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(CmdSetLineWidth) },
         { "vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(CmdSetScissor) },
@@ -573,6 +691,7 @@
         { "vkCreateComputePipelines", reinterpret_cast<PFN_vkVoidFunction>(CreateComputePipelines) },
         { "vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorPool) },
         { "vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorSetLayout) },
+        { "vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(CreateDescriptorUpdateTemplate) },
         { "vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(CreateDevice) },
         { "vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(CreateEvent) },
         { "vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(CreateFence) },
@@ -586,6 +705,7 @@
         { "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
         { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
         { "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
+        { "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
         { "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
         { "vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(CreateShaderModule) },
         { "vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR) },
@@ -594,6 +714,7 @@
         { "vkDestroyCommandPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyCommandPool) },
         { "vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorPool) },
         { "vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorSetLayout) },
+        { "vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(DestroyDescriptorUpdateTemplate) },
         { "vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice) },
         { "vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(DestroyEvent) },
         { "vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(DestroyFence) },
@@ -607,6 +728,7 @@
         { "vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(DestroyQueryPool) },
         { "vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(DestroyRenderPass) },
         { "vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(DestroySampler) },
+        { "vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(DestroySamplerYcbcrConversion) },
         { "vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(DestroySemaphore) },
         { "vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(DestroyShaderModule) },
         { "vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR) },
@@ -616,20 +738,31 @@
         { "vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceLayerProperties) },
         { "vkEnumerateInstanceExtensionProperties", nullptr },
         { "vkEnumerateInstanceLayerProperties", nullptr },
+        { "vkEnumerateInstanceVersion", nullptr },
         { "vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(FlushMappedMemoryRanges) },
         { "vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(FreeCommandBuffers) },
         { "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
         { "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
+        { "vkGetAndroidHardwareBufferPropertiesANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetAndroidHardwareBufferPropertiesANDROID) },
         { "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
+        { "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+        { "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
+        { "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
+        { "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
+        { "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
         { "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
         { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
+        { "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
         { "vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(GetEventStatus) },
         { "vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(GetFenceStatus) },
         { "vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements) },
+        { "vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageMemoryRequirements2) },
         { "vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements) },
+        { "vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetImageSparseMemoryRequirements2) },
         { "vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(GetImageSubresourceLayout) },
         { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
+        { "vkGetMemoryAndroidHardwareBufferANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetMemoryAndroidHardwareBufferANDROID) },
         { "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
         { "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
         { "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
@@ -647,7 +780,9 @@
         { "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
         { "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
         { "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+        { "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
         { "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
+        { "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
         { "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
         { "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
     };
@@ -1173,6 +1308,114 @@
     GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
 }
 
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+    return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+    return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+    GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+    GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+    GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+    return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+    GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+    GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+    GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+    return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+    GetData(device).dispatch.TrimCommandPool(device, commandPool, flags);
+}
+
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+    GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+    return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+    GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+    return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+    GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+    GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+    GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+    GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+}
+
 VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) {
     GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator);
 }
@@ -1213,10 +1456,34 @@
     return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo);
 }
 
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+    return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+}
+
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+    return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+    return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+}
+
 VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
     return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
 }
 
+VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
+    return GetData(device).dispatch.GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
+}
+
+VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer) {
+    return GetData(device).dispatch.GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
+}
+
 
 }  // anonymous namespace
 
@@ -1913,6 +2180,146 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
+    return vulkan::api::EnumerateInstanceVersion(pApiVersion);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+    return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+    return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+    vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+    vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+    vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+    return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+    vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+    vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+    vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+    vulkan::api::GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+    vulkan::api::GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+    vulkan::api::GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+    return vulkan::api::GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+    vulkan::api::GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+    vulkan::api::GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+    vulkan::api::GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+    vulkan::api::TrimCommandPool(device, commandPool, flags);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+    vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+    return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+    vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+    return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+    vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+    vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+    vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+    vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+    vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+    vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) {
     vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator);
 }
@@ -1963,8 +2370,38 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+    return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    return vulkan::api::GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+    return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+    return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
     return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
 }
 
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
+    return vulkan::api::GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer) {
+    return vulkan::api::GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
+}
+
 // clang-format on
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 3e50fda..4bedbeb 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -40,11 +40,23 @@
     PFN_vkCreateDevice CreateDevice;
     PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
     PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
+    PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+    PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2;
+    PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
+    PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2;
+    PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2;
+    PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2;
+    PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2;
+    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2;
+    PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties;
+    PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties;
+    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties;
     PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
     PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
+    PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR;
     PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
     // clang-format on
 };
@@ -172,11 +184,32 @@
     PFN_vkCmdNextSubpass CmdNextSubpass;
     PFN_vkCmdEndRenderPass CmdEndRenderPass;
     PFN_vkCmdExecuteCommands CmdExecuteCommands;
+    PFN_vkBindBufferMemory2 BindBufferMemory2;
+    PFN_vkBindImageMemory2 BindImageMemory2;
+    PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures;
+    PFN_vkCmdSetDeviceMask CmdSetDeviceMask;
+    PFN_vkCmdDispatchBase CmdDispatchBase;
+    PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2;
+    PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2;
+    PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2;
+    PFN_vkTrimCommandPool TrimCommandPool;
+    PFN_vkGetDeviceQueue2 GetDeviceQueue2;
+    PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion;
+    PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
+    PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate;
+    PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate;
+    PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate;
+    PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
     PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
     PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
     PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
     PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
     PFN_vkQueuePresentKHR QueuePresentKHR;
+    PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR;
+    PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR;
+    PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR;
+    PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
+    PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
     // clang-format on
 };
 
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index cb2d26a..1f4df1e 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -419,7 +419,7 @@
     INIT_PROC(§
   {{end}}
 
-  {{if GetAnnotation $ "optional"}}false{{else}}true{{end}}, §
+  {{if GetAnnotation $ "optional"}}false{{else if GetAnnotation $ "vulkan1_1"}}false{{else}}true{{end}}, §
 
   {{if (Macro "IsInstanceDispatched" $)}}
     instance, §
@@ -702,6 +702,7 @@
 {{define "driver.KnownExtensions"}}
 {{Macro "driver.InterceptedExtensions"}}
 VK_KHR_get_physical_device_properties2
+VK_ANDROID_external_memory_android_hardware_buffer
 {{end}}
 
 
@@ -733,7 +734,9 @@
     {{     if eq $.Name "vkCreateInstance"}}true
     {{else if eq $.Name "vkCreateDevice"}}true
     {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+    {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
     {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkGetDeviceQueue2"}}true
     {{else if eq $.Name "vkAllocateCommandBuffers"}}true
 
     {{/* Destroy functions of dispatchable objects */}}
@@ -958,6 +961,7 @@
     {{/* Create functions of dispatchable objects */}}
     {{     if eq $.Name "vkCreateDevice"}}true
     {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkGetDeviceQueue2"}}true
     {{else if eq $.Name "vkAllocateCommandBuffers"}}true
 
     {{/* Destroy functions of dispatchable objects */}}
@@ -969,6 +973,7 @@
 
     {{/* We cache physical devices in loader.cpp */}}
     {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+    {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
 
     {{else if eq $.Name "vkGetInstanceProcAddr"}}true
     {{else if eq $.Name "vkGetDeviceProcAddr"}}true
@@ -978,6 +983,7 @@
     {{else if eq $.Name "vkDestroyImage"}}true
 
     {{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
+    {{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true
     {{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
     {{end}}
 
@@ -1156,7 +1162,6 @@
 ------------------------------------------------------------------------------
   Reports whether an extension has functions exported by the loader.
   E.g. applications can directly link to an extension function.
-  Currently only support WSI extensions this way.
 ------------------------------------------------------------------------------
 */}}
 {{define "IsExtensionExported"}}
@@ -1164,6 +1169,7 @@
   {{     if eq $ext "VK_KHR_surface"}}true
   {{else if eq $ext "VK_KHR_swapchain"}}true
   {{else if eq $ext "VK_KHR_android_surface"}}true
+  {{else if eq $ext "VK_ANDROID_external_memory_android_hardware_buffer"}}true
   {{end}}
 {{end}}
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 947a2f7..56bc35e 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -19,14 +19,16 @@
 #include <string.h>
 #include <sys/prctl.h>
 
+#include <dlfcn.h>
 #include <algorithm>
 #include <array>
-#include <dlfcn.h>
 #include <new>
 
 #include <log/log.h>
 
 #include <android/dlext.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
 #include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <utils/Vector.h>
@@ -36,6 +38,9 @@
 #include "driver.h"
 #include "stubhal.h"
 
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
 android_namespace_t* android_get_exported_namespace(const char*);
@@ -94,6 +99,7 @@
     ~CreateInfoWrapper();
 
     VkResult Validate();
+    void DowngradeApiVersion();
 
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
     const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
@@ -131,6 +137,8 @@
         VkDeviceCreateInfo dev_info_;
     };
 
+    VkApplicationInfo application_info_;
+
     ExtensionFilter extension_filter_;
 
     std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
@@ -399,6 +407,12 @@
     for (uint32_t i = 0; i < ext_count; i++)
         FilterExtension(ext_names[i]);
 
+    // Enable device extensions that contain physical-device commands, so that
+    // vkGetInstanceProcAddr will return those physical-device commands.
+    if (is_instance_) {
+        hook_extensions_.set(ProcHook::KHR_swapchain);
+    }
+
     ext_names = extension_filter_.names;
     ext_count = extension_filter_.name_count;
 
@@ -486,13 +500,36 @@
                 // both we and HAL can take part in
                 hook_extensions_.set(ext_bit);
                 break;
-            case ProcHook::EXTENSION_UNKNOWN:
             case ProcHook::KHR_get_physical_device_properties2:
-                // HAL's extensions
+            case ProcHook::EXTENSION_UNKNOWN:
+                // Extensions we don't need to do anything about at this level
                 break;
-            default:
-                ALOGW("Ignored invalid instance extension %s", name);
+
+            case ProcHook::KHR_incremental_present:
+            case ProcHook::KHR_shared_presentable_image:
+            case ProcHook::KHR_swapchain:
+            case ProcHook::EXT_hdr_metadata:
+            case ProcHook::ANDROID_external_memory_android_hardware_buffer:
+            case ProcHook::ANDROID_native_buffer:
+            case ProcHook::GOOGLE_display_timing:
+            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_COUNT:
+                // Device and meta extensions. If we ever get here it's a bug in
+                // our code. But enumerating them lets us avoid having a default
+                // case, and default hides other bugs.
+                ALOGE(
+                    "CreateInfoWrapper::FilterExtension: invalid instance "
+                    "extension '%s'. FIX ME",
+                    name);
                 return;
+
+            // Don't use a default case. Without it, -Wswitch will tell us
+            // at compile time if someone adds a new ProcHook extension but
+            // doesn't handle it above. That's a real bug that has
+            // not-immediately-obvious effects.
+            //
+            // default:
+            //     break;
         }
     } else {
         switch (ext_bit) {
@@ -510,12 +547,36 @@
             case ProcHook::EXT_hdr_metadata:
                 hook_extensions_.set(ext_bit);
                 break;
+            case ProcHook::ANDROID_external_memory_android_hardware_buffer:
             case ProcHook::EXTENSION_UNKNOWN:
-                // HAL's extensions
+                // Extensions we don't need to do anything about at this level
                 break;
-            default:
-                ALOGW("Ignored invalid device extension %s", name);
+
+            case ProcHook::KHR_android_surface:
+            case ProcHook::KHR_get_physical_device_properties2:
+            case ProcHook::KHR_get_surface_capabilities2:
+            case ProcHook::KHR_surface:
+            case ProcHook::EXT_debug_report:
+            case ProcHook::EXT_swapchain_colorspace:
+            case ProcHook::ANDROID_native_buffer:
+            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_COUNT:
+                // Instance and meta extensions. If we ever get here it's a bug
+                // in our code. But enumerating them lets us avoid having a
+                // default case, and default hides other bugs.
+                ALOGE(
+                    "CreateInfoWrapper::FilterExtension: invalid device "
+                    "extension '%s'. FIX ME",
+                    name);
                 return;
+
+            // Don't use a default case. Without it, -Wswitch will tell us
+            // at compile time if someone adds a new ProcHook extension but
+            // doesn't handle it above. That's a real bug that has
+            // not-immediately-obvious effects.
+            //
+            // default:
+            //     break;
         }
     }
 
@@ -537,6 +598,15 @@
     }
 }
 
+void CreateInfoWrapper::DowngradeApiVersion() {
+    // If pApplicationInfo is NULL, apiVersion is assumed to be 1.0:
+    if (instance_info_.pApplicationInfo) {
+        application_info_ = *instance_info_.pApplicationInfo;
+        instance_info_.pApplicationInfo = &application_info_;
+        application_info_.apiVersion = VK_API_VERSION_1_0;
+    }
+}
+
 VKAPI_ATTR void* DefaultAllocate(void*,
                                  size_t size,
                                  size_t alignment,
@@ -778,7 +848,8 @@
     const InstanceData& data = GetData(physicalDevice);
 
     // GPDP2 must be present and enabled on the instance.
-    if (!data.driver.GetPhysicalDeviceProperties2KHR)
+    if (!data.driver.GetPhysicalDeviceProperties2KHR &&
+        !data.driver.GetPhysicalDeviceProperties2)
         return false;
 
     // Request the android-specific presentation properties via GPDP2
@@ -796,8 +867,12 @@
     presentation_properties->pNext = nullptr;
     presentation_properties->sharedImage = VK_FALSE;
 
-    data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
-                                                &properties);
+    if (data.driver.GetPhysicalDeviceProperties2KHR) {
+        data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
+                                                    &properties);
+    } else {
+        data.driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+    }
 
     return true;
 }
@@ -814,6 +889,14 @@
         VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
         VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
 
+    bool hdrBoardConfig =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(
+            false);
+    if (hdrBoardConfig) {
+        loader_extensions.push_back({VK_EXT_HDR_METADATA_EXTENSION_NAME,
+                                     VK_EXT_HDR_METADATA_SPEC_VERSION});
+    }
+
     VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
     if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
         presentation_properties.sharedImage) {
@@ -880,19 +963,6 @@
     const VkAllocationCallbacks& data_allocator =
         (pAllocator) ? *pAllocator : GetDefaultAllocator();
 
-    if (pCreateInfo->pApplicationInfo &&
-        pCreateInfo->pApplicationInfo->apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wold-style-cast"
-        ALOGI(
-            "Requested Vulkan instance version %d.%d is greater than max "
-            "supported version (1.0)",
-            VK_VERSION_MAJOR(pCreateInfo->pApplicationInfo->apiVersion),
-            VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion));
-#pragma clang diagnostic pop
-        return VK_ERROR_INCOMPATIBLE_DRIVER;
-    }
-
     CreateInfoWrapper wrapper(*pCreateInfo, data_allocator);
     VkResult result = wrapper.Validate();
     if (result != VK_SUCCESS)
@@ -904,6 +974,33 @@
 
     data->hook_extensions |= wrapper.GetHookExtensions();
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+    uint32_t api_version = ((pCreateInfo->pApplicationInfo)
+                                ? pCreateInfo->pApplicationInfo->apiVersion
+                                : VK_API_VERSION_1_0);
+    uint32_t api_major_version = VK_VERSION_MAJOR(api_version);
+    uint32_t api_minor_version = VK_VERSION_MINOR(api_version);
+    uint32_t icd_api_version;
+    PFN_vkEnumerateInstanceVersion pfn_enumerate_instance_version =
+        reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
+            Hal::Device().GetInstanceProcAddr(NULL,
+                                              "vkEnumerateInstanceVersion"));
+    if (!pfn_enumerate_instance_version) {
+        icd_api_version = VK_API_VERSION_1_0;
+    } else {
+        result = (*pfn_enumerate_instance_version)(&icd_api_version);
+    }
+    uint32_t icd_api_major_version = VK_VERSION_MAJOR(icd_api_version);
+    uint32_t icd_api_minor_version = VK_VERSION_MINOR(icd_api_version);
+
+    if ((icd_api_major_version == 1) && (icd_api_minor_version == 0) &&
+        ((api_major_version > 1) || (api_minor_version > 0))) {
+        api_version = VK_API_VERSION_1_0;
+        wrapper.DowngradeApiVersion();
+    }
+#pragma clang diagnostic pop
+
     // call into the driver
     VkInstance instance;
     result = Hal::Device().CreateInstance(
@@ -1056,6 +1153,65 @@
     return result;
 }
 
+VkResult EnumeratePhysicalDeviceGroups(
+    VkInstance instance,
+    uint32_t* pPhysicalDeviceGroupCount,
+    VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+    VkResult result = VK_SUCCESS;
+    const auto& data = GetData(instance);
+
+    if (!data.driver.EnumeratePhysicalDeviceGroups) {
+        uint32_t device_count = 0;
+        result = EnumeratePhysicalDevices(instance, &device_count, nullptr);
+        if (result < 0)
+            return result;
+        if (!pPhysicalDeviceGroupProperties) {
+            *pPhysicalDeviceGroupCount = device_count;
+            return result;
+        }
+
+        device_count = std::min(device_count, *pPhysicalDeviceGroupCount);
+        if (!device_count) {
+            *pPhysicalDeviceGroupCount = 0;
+            return result;
+        }
+
+        android::Vector<VkPhysicalDevice> devices;
+        devices.resize(device_count);
+
+        result = EnumeratePhysicalDevices(instance, &device_count,
+                                          devices.editArray());
+        if (result < 0)
+            return result;
+
+        devices.resize(device_count);
+        *pPhysicalDeviceGroupCount = device_count;
+        for (uint32_t i = 0; i < device_count; ++i) {
+            pPhysicalDeviceGroupProperties[i].physicalDeviceCount = 1;
+            pPhysicalDeviceGroupProperties[i].physicalDevices[0] = devices[i];
+            pPhysicalDeviceGroupProperties[i].subsetAllocation = 0;
+        }
+    } else {
+        result = data.driver.EnumeratePhysicalDeviceGroups(
+            instance, pPhysicalDeviceGroupCount,
+            pPhysicalDeviceGroupProperties);
+        if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
+            *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
+            for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
+                for (uint32_t j = 0;
+                     j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount;
+                     j++) {
+                    SetData(
+                        pPhysicalDeviceGroupProperties[i].physicalDevices[j],
+                        data);
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
 void GetDeviceQueue(VkDevice device,
                     uint32_t queueFamilyIndex,
                     uint32_t queueIndex,
@@ -1066,6 +1222,15 @@
     SetData(*pQueue, data);
 }
 
+void GetDeviceQueue2(VkDevice device,
+                     const VkDeviceQueueInfo2* pQueueInfo,
+                     VkQueue* pQueue) {
+    const auto& data = GetData(device);
+
+    data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue);
+    if (*pQueue != VK_NULL_HANDLE) SetData(*pQueue, data);
+}
+
 VKAPI_ATTR VkResult
 AllocateCommandBuffers(VkDevice device,
                        const VkCommandBufferAllocateInfo* pAllocateInfo,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 7f8ae98..57c956d 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -126,7 +126,10 @@
 VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
 
 VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+
 VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
 VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
 // clang-format on
 
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 82b464e..ec98b9f 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -75,6 +75,33 @@
     }
 }
 
+VKAPI_ATTR VkResult checkedGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+    if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+        return GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
+    } else {
+        Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupPresentCapabilitiesKHR not executed.");
+        return VK_SUCCESS;
+    }
+}
+
+VKAPI_ATTR VkResult checkedGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+        return GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+    } else {
+        Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkGetDeviceGroupSurfacePresentModesKHR not executed.");
+        return VK_SUCCESS;
+    }
+}
+
+VKAPI_ATTR VkResult checkedAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
+    if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
+        return AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
+    } else {
+        Logger(device).Err(device, "VK_KHR_swapchain not enabled. vkAcquireNextImage2KHR not executed.");
+        return VK_SUCCESS;
+    }
+}
+
 VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
     if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
         return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
@@ -122,6 +149,13 @@
         nullptr,
     },
     {
+        "vkAcquireNextImage2KHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImage2KHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImage2KHR),
+    },
+    {
         "vkAcquireNextImageKHR",
         ProcHook::DEVICE,
         ProcHook::KHR_swapchain,
@@ -227,6 +261,13 @@
         nullptr,
     },
     {
+        "vkEnumeratePhysicalDeviceGroups",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups),
+        nullptr,
+    },
+    {
         "vkEnumeratePhysicalDevices",
         ProcHook::INSTANCE,
         ProcHook::EXTENSION_CORE,
@@ -234,6 +275,20 @@
         nullptr,
     },
     {
+        "vkGetDeviceGroupPresentCapabilitiesKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupPresentCapabilitiesKHR),
+    },
+    {
+        "vkGetDeviceGroupSurfacePresentModesKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceGroupSurfacePresentModesKHR),
+    },
+    {
         "vkGetDeviceProcAddr",
         ProcHook::DEVICE,
         ProcHook::EXTENSION_CORE,
@@ -248,6 +303,13 @@
         nullptr,
     },
     {
+        "vkGetDeviceQueue2",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2),
+        nullptr,
+    },
+    {
         "vkGetInstanceProcAddr",
         ProcHook::INSTANCE,
         ProcHook::EXTENSION_CORE,
@@ -262,6 +324,13 @@
         reinterpret_cast<PFN_vkVoidFunction>(checkedGetPastPresentationTimingGOOGLE),
     },
     {
+        "vkGetPhysicalDevicePresentRectanglesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDevicePresentRectanglesKHR),
+        nullptr,
+    },
+    {
         "vkGetPhysicalDeviceSurfaceCapabilities2KHR",
         ProcHook::INSTANCE,
         ProcHook::KHR_get_surface_capabilities2,
@@ -388,6 +457,7 @@
     if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
     if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
     if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
+    if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
     // clang-format on
     return ProcHook::EXTENSION_UNKNOWN;
 }
@@ -423,6 +493,8 @@
     INIT_PROC(true, instance, GetPhysicalDeviceProperties);
     INIT_PROC(true, instance, CreateDevice);
     INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
+    INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+    INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
     INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
     INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
     INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
@@ -445,6 +517,7 @@
     INIT_PROC(true, dev, CreateImage);
     INIT_PROC(true, dev, DestroyImage);
     INIT_PROC(true, dev, AllocateCommandBuffers);
+    INIT_PROC(false, dev, GetDeviceQueue2);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 3b26a80..14c3aba 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -45,6 +45,7 @@
         KHR_swapchain,
         KHR_get_surface_capabilities2,
         KHR_get_physical_device_properties2,
+        ANDROID_external_memory_android_hardware_buffer,
 
         EXTENSION_CORE,  // valid bit
         EXTENSION_COUNT,
@@ -67,6 +68,8 @@
     PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
     PFN_vkCreateDevice CreateDevice;
     PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
+    PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+    PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
     PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
@@ -82,6 +85,7 @@
     PFN_vkCreateImage CreateImage;
     PFN_vkDestroyImage DestroyImage;
     PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
+    PFN_vkGetDeviceQueue2 GetDeviceQueue2;
     PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
     PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
     PFN_vkAcquireImageANDROID AcquireImageANDROID;
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 05856d3..3a59208 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -29,11 +29,10 @@
 #include <android/dlext.h>
 #include <android-base/strings.h>
 #include <cutils/properties.h>
+#include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
 #include <ziparchive/zip_archive.h>
 
-#include <vulkan/vulkan_loader_data.h>
-
 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
 // not a good long-term solution. Having a hard-coded enum of extensions is
 // bad, of course. Representing sets of extensions (requested, supported, etc.)
@@ -69,11 +68,16 @@
 
 class LayerLibrary {
    public:
-    explicit LayerLibrary(const std::string& path)
-        : path_(path), dlhandle_(nullptr), refcount_(0) {}
+    explicit LayerLibrary(const std::string& path,
+                          const std::string& filename)
+        : path_(path),
+          filename_(filename),
+          dlhandle_(nullptr),
+          refcount_(0) {}
 
     LayerLibrary(LayerLibrary&& other)
         : path_(std::move(other.path_)),
+          filename_(std::move(other.filename_)),
           dlhandle_(other.dlhandle_),
           refcount_(other.refcount_) {
         other.dlhandle_ = nullptr;
@@ -94,9 +98,14 @@
                  const char* gpa_name,
                  size_t gpa_name_len) const;
 
+    const std::string GetFilename() { return filename_; }
+
    private:
     const std::string path_;
 
+    // Track the filename alone so we can detect duplicates
+    const std::string filename_;
+
     std::mutex mutex_;
     void* dlhandle_;
     size_t refcount_;
@@ -111,7 +120,7 @@
         // any symbol dependencies will be resolved by system libraries. They
         // can't safely use libc++_shared, for example. Which is one reason
         // (among several) we only allow them in non-user builds.
-        auto app_namespace = LoaderData::GetInstance().app_namespace;
+        auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
         if (app_namespace &&
             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
             android_dlextinfo dlextinfo = {};
@@ -305,8 +314,8 @@
 std::vector<LayerLibrary> g_layer_libraries;
 std::vector<Layer> g_instance_layers;
 
-void AddLayerLibrary(const std::string& path) {
-    LayerLibrary library(path);
+void AddLayerLibrary(const std::string& path, const std::string& filename) {
+    LayerLibrary library(path + "/" + filename, filename);
     if (!library.Open())
         return;
 
@@ -398,7 +407,25 @@
         ForEachFileInPath(path, [&](const std::string& filename) {
             if (android::base::StartsWith(filename, "libVkLayer") &&
                 android::base::EndsWith(filename, ".so")) {
-                AddLayerLibrary(path + "/" + filename);
+
+                // Check to ensure we haven't seen this layer already
+                // Let the first instance of the shared object be enumerated
+                // We're searching for layers in following order:
+                // 1. system path
+                // 2. libraryPermittedPath (if enabled)
+                // 3. libraryPath
+
+                bool duplicate = false;
+                for (auto& layer : g_layer_libraries) {
+                    if (layer.GetFilename() == filename) {
+                        ALOGV("Skipping duplicate layer %s in %s",
+                              filename.c_str(), path.c_str());
+                        duplicate = true;
+                    }
+                }
+
+                if (!duplicate)
+                    AddLayerLibrary(path, filename);
             }
         });
     }
@@ -428,8 +455,8 @@
         prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
         DiscoverLayersInPathList(kSystemLayerLibraryDir);
     }
-    if (!LoaderData::GetInstance().layer_path.empty())
-        DiscoverLayersInPathList(LoaderData::GetInstance().layer_path);
+    if (!android::GraphicsEnv::getInstance().getLayerPaths().empty())
+        DiscoverLayersInPathList(android::GraphicsEnv::getInstance().getLayerPaths());
 }
 
 uint32_t GetLayerCount() {
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 1745925..0be66c9 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -1,12 +1,15 @@
 LIBVULKAN {
   global:
+    vkAcquireNextImage2KHR; # introduced=28
     vkAcquireNextImageKHR;
     vkAllocateCommandBuffers;
     vkAllocateDescriptorSets;
     vkAllocateMemory;
     vkBeginCommandBuffer;
     vkBindBufferMemory;
+    vkBindBufferMemory2; # introduced=28
     vkBindImageMemory;
+    vkBindImageMemory2; # introduced=28
     vkCmdBeginQuery;
     vkCmdBeginRenderPass;
     vkCmdBindDescriptorSets;
@@ -23,6 +26,7 @@
     vkCmdCopyImageToBuffer;
     vkCmdCopyQueryPoolResults;
     vkCmdDispatch;
+    vkCmdDispatchBase; # introduced=28
     vkCmdDispatchIndirect;
     vkCmdDraw;
     vkCmdDrawIndexed;
@@ -41,6 +45,7 @@
     vkCmdSetBlendConstants;
     vkCmdSetDepthBias;
     vkCmdSetDepthBounds;
+    vkCmdSetDeviceMask; # introduced=28
     vkCmdSetEvent;
     vkCmdSetLineWidth;
     vkCmdSetScissor;
@@ -58,6 +63,7 @@
     vkCreateComputePipelines;
     vkCreateDescriptorPool;
     vkCreateDescriptorSetLayout;
+    vkCreateDescriptorUpdateTemplate; # introduced=28
     vkCreateDevice;
     vkCreateEvent;
     vkCreateFence;
@@ -71,6 +77,7 @@
     vkCreateQueryPool;
     vkCreateRenderPass;
     vkCreateSampler;
+    vkCreateSamplerYcbcrConversion; # introduced=28
     vkCreateSemaphore;
     vkCreateShaderModule;
     vkCreateSwapchainKHR;
@@ -79,6 +86,7 @@
     vkDestroyCommandPool;
     vkDestroyDescriptorPool;
     vkDestroyDescriptorSetLayout;
+    vkDestroyDescriptorUpdateTemplate; # introduced=28
     vkDestroyDevice;
     vkDestroyEvent;
     vkDestroyFence;
@@ -92,6 +100,7 @@
     vkDestroyQueryPool;
     vkDestroyRenderPass;
     vkDestroySampler;
+    vkDestroySamplerYcbcrConversion; # introduced=28
     vkDestroySemaphore;
     vkDestroyShaderModule;
     vkDestroySurfaceKHR;
@@ -102,28 +111,51 @@
     vkEnumerateDeviceLayerProperties;
     vkEnumerateInstanceExtensionProperties;
     vkEnumerateInstanceLayerProperties;
+    vkEnumerateInstanceVersion; # introduced=28
+    vkEnumeratePhysicalDeviceGroups; # introduced=28
     vkEnumeratePhysicalDevices;
     vkFlushMappedMemoryRanges;
     vkFreeCommandBuffers;
     vkFreeDescriptorSets;
     vkFreeMemory;
+    vkGetAndroidHardwareBufferPropertiesANDROID; # introduced=28
     vkGetBufferMemoryRequirements;
+    vkGetBufferMemoryRequirements2; # introduced=28
+    vkGetDescriptorSetLayoutSupport; # introduced=28
+    vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
+    vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
+    vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
     vkGetDeviceMemoryCommitment;
     vkGetDeviceProcAddr;
     vkGetDeviceQueue;
+    vkGetDeviceQueue2; # introduced=28
     vkGetEventStatus;
     vkGetFenceStatus;
     vkGetImageMemoryRequirements;
+    vkGetImageMemoryRequirements2; # introduced=28
     vkGetImageSparseMemoryRequirements;
+    vkGetImageSparseMemoryRequirements2; # introduced=28
     vkGetImageSubresourceLayout;
     vkGetInstanceProcAddr;
+    vkGetMemoryAndroidHardwareBufferANDROID; # introduced=28
+    vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
+    vkGetPhysicalDeviceExternalFenceProperties; # introduced=28
+    vkGetPhysicalDeviceExternalSemaphoreProperties; # introduced=28
     vkGetPhysicalDeviceFeatures;
+    vkGetPhysicalDeviceFeatures2; # introduced=28
     vkGetPhysicalDeviceFormatProperties;
+    vkGetPhysicalDeviceFormatProperties2; # introduced=28
     vkGetPhysicalDeviceImageFormatProperties;
+    vkGetPhysicalDeviceImageFormatProperties2; # introduced=28
     vkGetPhysicalDeviceMemoryProperties;
+    vkGetPhysicalDeviceMemoryProperties2; # introduced=28
+    vkGetPhysicalDevicePresentRectanglesKHR; # introduced=28
     vkGetPhysicalDeviceProperties;
+    vkGetPhysicalDeviceProperties2; # introduced=28
     vkGetPhysicalDeviceQueueFamilyProperties;
+    vkGetPhysicalDeviceQueueFamilyProperties2; # introduced=28
     vkGetPhysicalDeviceSparseImageFormatProperties;
+    vkGetPhysicalDeviceSparseImageFormatProperties2; # introduced=28
     vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
     vkGetPhysicalDeviceSurfaceFormatsKHR;
     vkGetPhysicalDeviceSurfacePresentModesKHR;
@@ -145,8 +177,10 @@
     vkResetEvent;
     vkResetFences;
     vkSetEvent;
+    vkTrimCommandPool; # introduced=28
     vkUnmapMemory;
     vkUpdateDescriptorSets;
+    vkUpdateDescriptorSetWithTemplate; # introduced=28
     vkWaitForFences;
   local:
     *;
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 2926268..7404b94 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -97,7 +97,15 @@
     return VK_SUCCESS;
 }
 
-VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/,
+VKAPI_ATTR VkResult
+EnumeratePhysicalDeviceGroups(VkInstance /*instance*/,
+                              uint32_t* count,
+                              VkPhysicalDeviceGroupProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
                                                   const char* name) {
     if (strcmp(name, "vkCreateInstance") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
@@ -108,9 +116,14 @@
             EnumerateInstanceExtensionProperties);
     if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+    if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumeratePhysicalDeviceGroups);
     if (strcmp(name, "vkGetInstanceProcAddr") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
-
+    // Per the spec, return NULL if instance is NULL.
+    if (!instance)
+        return nullptr;
     // None of the other Vulkan functions should ever be called, as they all
     // take a VkPhysicalDevice or other object obtained from a physical device.
     return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 665a32b..3db8a39 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -23,9 +23,12 @@
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 #include <system/window.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 
 #include "driver.h"
 
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
 // TODO(jessehall): Currently we don't have a good error code for when a native
 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later
 // versions (post SDK 0.9) of the API/extension have a better error code.
@@ -182,6 +185,7 @@
 struct Surface {
     android::sp<ANativeWindow> window;
     VkSwapchainKHR swapchain_handle;
+    uint64_t consumer_usage;
 };
 
 VkSurfaceKHR HandleFromSurface(Surface* surface) {
@@ -493,9 +497,18 @@
 
     surface->window = pCreateInfo->window;
     surface->swapchain_handle = VK_NULL_HANDLE;
+    int err = native_window_get_consumer_usage(surface->window.get(),
+                                               &surface->consumer_usage);
+    if (err != android::NO_ERROR) {
+        ALOGE("native_window_get_consumer_usage() failed: %s (%d)",
+              strerror(-err), err);
+        surface->~Surface();
+        allocator->pfnFree(allocator->pUserData, surface);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
 
     // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
-    int err =
+    err =
         native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
@@ -533,9 +546,45 @@
 VKAPI_ATTR
 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
                                             uint32_t /*queue_family*/,
-                                            VkSurfaceKHR /*surface*/,
+                                            VkSurfaceKHR surface_handle,
                                             VkBool32* supported) {
-    *supported = VK_TRUE;
+    const Surface* surface = SurfaceFromHandle(surface_handle);
+    if (!surface) {
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+    const ANativeWindow* window = surface->window.get();
+
+    int query_value;
+    int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value);
+    if (err != 0 || query_value < 0) {
+        ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d",
+              strerror(-err), err, query_value);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+
+    android_pixel_format native_format =
+        static_cast<android_pixel_format>(query_value);
+
+    bool format_supported = false;
+    switch (native_format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            format_supported = true;
+            break;
+        default:
+            break;
+    }
+
+    // USAGE_CPU_READ_MASK 0xFUL
+    // USAGE_CPU_WRITE_MASK (0xFUL << 4)
+    // The currently used bits are as below:
+    // USAGE_CPU_READ_RARELY = 2UL
+    // USAGE_CPU_READ_OFTEN = 3UL
+    // USAGE_CPU_WRITE_RARELY = (2UL << 4)
+    // USAGE_CPU_WRITE_OFTEN = (3UL << 4)
+    *supported = static_cast<VkBool32>(format_supported ||
+                                       (surface->consumer_usage & 0xFFUL) == 0);
+
     return VK_SUCCESS;
 }
 
@@ -570,8 +619,15 @@
     }
 
     // TODO(jessehall): Figure out what the min/max values should be.
-    capabilities->minImageCount = 2;
-    capabilities->maxImageCount = 3;
+    int max_buffer_count;
+    err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
+    if (err != 0) {
+        ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
+              strerror(-err), err);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+    capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2;
+    capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
 
     capabilities->currentExtent =
         VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
@@ -741,11 +797,32 @@
 
 VKAPI_ATTR
 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,
-                                                 VkSurfaceKHR /*surface*/,
+                                                 VkSurfaceKHR surface,
                                                  uint32_t* count,
                                                  VkPresentModeKHR* modes) {
+    int err;
+    int query_value;
+    ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+    err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
+    if (err != 0 || query_value < 0) {
+        ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) value=%d",
+              strerror(-err), err, query_value);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+    err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
+    if (err != 0 || query_value < 0) {
+        ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
+              strerror(-err), err, query_value);
+        return VK_ERROR_SURFACE_LOST_KHR;
+    }
+    uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
+
     android::Vector<VkPresentModeKHR> present_modes;
-    present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+    if (min_undequeued_buffers + 1 < max_buffer_count)
+        present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
     present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
 
     VkPhysicalDevicePresentationPropertiesANDROID present_properties;
@@ -771,6 +848,77 @@
 }
 
 VKAPI_ATTR
+VkResult GetDeviceGroupPresentCapabilitiesKHR(
+    VkDevice,
+    VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+    ALOGV_IF(pDeviceGroupPresentCapabilities->sType !=
+                 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
+             "vkGetDeviceGroupPresentCapabilitiesKHR: invalid "
+             "VkDeviceGroupPresentCapabilitiesKHR structure type %d",
+             pDeviceGroupPresentCapabilities->sType);
+
+    memset(pDeviceGroupPresentCapabilities->presentMask, 0,
+           sizeof(pDeviceGroupPresentCapabilities->presentMask));
+
+    // assume device group of size 1
+    pDeviceGroupPresentCapabilities->presentMask[0] = 1 << 0;
+    pDeviceGroupPresentCapabilities->modes =
+        VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
+
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR
+VkResult GetDeviceGroupSurfacePresentModesKHR(
+    VkDevice,
+    VkSurfaceKHR,
+    VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR
+VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice,
+                                               VkSurfaceKHR surface,
+                                               uint32_t* pRectCount,
+                                               VkRect2D* pRects) {
+    if (!pRects) {
+        *pRectCount = 1;
+    } else {
+        uint32_t count = std::min(*pRectCount, 1u);
+        bool incomplete = *pRectCount < 1;
+
+        *pRectCount = count;
+
+        if (incomplete) {
+            return VK_INCOMPLETE;
+        }
+
+        int err;
+        ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+        int width = 0, height = 0;
+        err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+        if (err != 0) {
+            ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+                  strerror(-err), err);
+        }
+        err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+        if (err != 0) {
+            ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+                  strerror(-err), err);
+        }
+
+        // TODO: Return something better than "whole window"
+        pRects[0].offset.x = 0;
+        pRects[0].offset.y = 0;
+        pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width),
+                                      static_cast<uint32_t>(height)};
+    }
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR
 VkResult CreateSwapchainKHR(VkDevice device,
                             const VkSwapchainCreateInfoKHR* create_info,
                             const VkAllocationCallbacks* allocator,
@@ -996,7 +1144,7 @@
         return VK_ERROR_SURFACE_LOST_KHR;
     }
 
-    int gralloc_usage = 0;
+    int32_t legacy_usage = 0;
     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
         result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1006,18 +1154,25 @@
             ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
         }
-        gralloc_usage =
+        legacy_usage =
             android_convertGralloc1To0Usage(producer_usage, consumer_usage);
     } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
         result = dispatch.GetSwapchainGrallocUsageANDROID(
             device, create_info->imageFormat, create_info->imageUsage,
-            &gralloc_usage);
+            &legacy_usage);
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
         }
     }
-    err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage));
+    uint64_t native_usage = static_cast<uint64_t>(legacy_usage);
+
+    bool createProtectedSwapchain = false;
+    if (create_info->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) {
+        createProtectedSwapchain = true;
+        native_usage |= BufferUsage::PROTECTED;
+    }
+    err = native_window_set_usage(surface.window.get(), native_usage);
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
@@ -1065,7 +1220,7 @@
         .samples = VK_SAMPLE_COUNT_1_BIT,
         .tiling = VK_IMAGE_TILING_OPTIMAL,
         .usage = create_info->imageUsage,
-        .flags = 0,
+        .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         .sharingMode = create_info->imageSharingMode,
         .queueFamilyIndexCount = create_info->queueFamilyIndexCount,
         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
@@ -1113,19 +1268,19 @@
     //
     // TODO(jessehall): The error path here is the same as DestroySwapchain,
     // but not the non-error path. Should refactor/unify.
-    if (!swapchain->shared) {
-        for (uint32_t i = 0; i < num_images; i++) {
-            Swapchain::Image& img = swapchain->images[i];
-            if (img.dequeued) {
+    for (uint32_t i = 0; i < num_images; i++) {
+        Swapchain::Image& img = swapchain->images[i];
+        if (img.dequeued) {
+            if (!swapchain->shared) {
                 surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
                                              img.dequeue_fence);
                 img.dequeue_fence = -1;
                 img.dequeued = false;
             }
-            if (result != VK_SUCCESS) {
-                if (img.image)
-                    dispatch.DestroyImage(device, img.image, nullptr);
-            }
+        }
+        if (result != VK_SUCCESS) {
+            if (img.image)
+                dispatch.DestroyImage(device, img.image, nullptr);
         }
     }
 
@@ -1273,6 +1428,17 @@
     return VK_SUCCESS;
 }
 
+VKAPI_ATTR
+VkResult AcquireNextImage2KHR(VkDevice device,
+                              const VkAcquireNextImageInfoKHR* pAcquireInfo,
+                              uint32_t* pImageIndex) {
+    // TODO: this should actually be the other way around and this function
+    // should handle any additional structures that get passed in
+    return AcquireNextImageKHR(device, pAcquireInfo->swapchain,
+                               pAcquireInfo->timeout, pAcquireInfo->semaphore,
+                               pAcquireInfo->fence, pImageIndex);
+}
+
 static VkResult WorstPresentResult(VkResult a, VkResult b) {
     // See the error ranking for vkQueuePresentKHR at the end of section 29.6
     // (in spec version 1.0.14).
@@ -1558,15 +1724,39 @@
 }
 
 VKAPI_ATTR void SetHdrMetadataEXT(
-    VkDevice device,
+    VkDevice,
     uint32_t swapchainCount,
     const VkSwapchainKHR* pSwapchains,
     const VkHdrMetadataEXT* pHdrMetadataEXTs) {
-    // TODO: courtneygo: implement actual function
-    (void)device;
-    (void)swapchainCount;
-    (void)pSwapchains;
-    (void)pHdrMetadataEXTs;
+
+    for (uint32_t idx = 0; idx < swapchainCount; idx++) {
+        Swapchain* swapchain = SwapchainFromHandle(pSwapchains[idx]);
+        if (!swapchain)
+            continue;
+
+        if (swapchain->surface.swapchain_handle != pSwapchains[idx]) continue;
+
+        ANativeWindow* window = swapchain->surface.window.get();
+
+        VkHdrMetadataEXT vulkanMetadata = pHdrMetadataEXTs[idx];
+        const android_smpte2086_metadata smpteMetdata = {
+            {vulkanMetadata.displayPrimaryRed.x,
+             vulkanMetadata.displayPrimaryRed.y},
+            {vulkanMetadata.displayPrimaryGreen.x,
+             vulkanMetadata.displayPrimaryGreen.y},
+            {vulkanMetadata.displayPrimaryBlue.x,
+             vulkanMetadata.displayPrimaryBlue.y},
+            {vulkanMetadata.whitePoint.x, vulkanMetadata.whitePoint.y},
+            vulkanMetadata.maxLuminance,
+            vulkanMetadata.minLuminance};
+        native_window_set_buffers_smpte2086_metadata(window, &smpteMetdata);
+
+        const android_cta861_3_metadata cta8613Metadata = {
+            vulkanMetadata.maxContentLightLevel,
+            vulkanMetadata.maxFrameAverageLightLevel};
+        native_window_set_buffers_cta861_3_metadata(window, &cta8613Metadata);
+    }
+
     return;
 }
 
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index e3cf624..ed5718c 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -29,11 +29,15 @@
 VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
 VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface_handle, uint32_t* count, VkSurfaceFormatKHR* formats);
 VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
+VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
+VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
 VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
 VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
 VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
 VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
 VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info);
+VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
 VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
 VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
 VKAPI_ATTR VkResult GetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain);
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index a3da651..4647a80 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -16,6 +16,7 @@
 
 #include <hardware/hwvulkan.h>
 
+#include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
@@ -258,6 +259,12 @@
 // Global
 
 VKAPI_ATTR
+VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+    *pApiVersion = VK_API_VERSION_1_1;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR
 VkResult EnumerateInstanceExtensionProperties(
     const char* layer_name,
     uint32_t* count,
@@ -343,9 +350,14 @@
 VkResult EnumeratePhysicalDevices(VkInstance instance,
                                   uint32_t* physical_device_count,
                                   VkPhysicalDevice* physical_devices) {
-    if (physical_devices && *physical_device_count >= 1)
+    if (!physical_devices)
+        *physical_device_count = 1;
+    else if (*physical_device_count == 0)
+        return VK_INCOMPLETE;
+    else {
         physical_devices[0] = &instance->physical_device;
-    *physical_device_count = 1;
+        *physical_device_count = 1;
+    }
     return VK_SUCCESS;
 }
 
@@ -1469,6 +1481,93 @@
 void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage) {
 }
 
+VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+    return VK_SUCCESS;
+}
+
+VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+    return VK_SUCCESS;
+}
+
+void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+}
+
+void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+}
+
+void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+}
+
+VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+    return VK_SUCCESS;
+}
+
+void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+}
+
+void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+}
+
+void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+}
+
+void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+}
+
+void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+}
+
+VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+    return VK_SUCCESS;
+}
+
+void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+}
+
+void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+}
+
+void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+}
+
+void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+}
+
+void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+}
+
+VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+    return VK_SUCCESS;
+}
+
+void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+}
+
+VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+    return VK_SUCCESS;
+}
+
+void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+}
+
+void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+}
+
+void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+}
+
+void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+}
+
+void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+}
+
+void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+}
+
 #pragma clang diagnostic pop
 // clang-format on
 
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 25ee65a..92b7468 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -49,6 +49,7 @@
     {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance))},
     {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))},
     {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))},
+    {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))},
     // clang-format on
 };
 
@@ -60,7 +61,9 @@
     {"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateMemory>(AllocateMemory))},
     {"vkBeginCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBeginCommandBuffer>(BeginCommandBuffer))},
     {"vkBindBufferMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory>(BindBufferMemory))},
+    {"vkBindBufferMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindBufferMemory2>(BindBufferMemory2))},
     {"vkBindImageMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory>(BindImageMemory))},
+    {"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
     {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
     {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
     {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
@@ -77,6 +80,7 @@
     {"vkCmdCopyImageToBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyImageToBuffer>(CmdCopyImageToBuffer))},
     {"vkCmdCopyQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdCopyQueryPoolResults>(CmdCopyQueryPoolResults))},
     {"vkCmdDispatch", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatch>(CmdDispatch))},
+    {"vkCmdDispatchBase", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchBase>(CmdDispatchBase))},
     {"vkCmdDispatchIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDispatchIndirect>(CmdDispatchIndirect))},
     {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
     {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
@@ -95,6 +99,7 @@
     {"vkCmdSetBlendConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetBlendConstants>(CmdSetBlendConstants))},
     {"vkCmdSetDepthBias", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBias>(CmdSetDepthBias))},
     {"vkCmdSetDepthBounds", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDepthBounds>(CmdSetDepthBounds))},
+    {"vkCmdSetDeviceMask", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetDeviceMask>(CmdSetDeviceMask))},
     {"vkCmdSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetEvent>(CmdSetEvent))},
     {"vkCmdSetLineWidth", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetLineWidth>(CmdSetLineWidth))},
     {"vkCmdSetScissor", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdSetScissor>(CmdSetScissor))},
@@ -112,6 +117,7 @@
     {"vkCreateDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDebugReportCallbackEXT>(CreateDebugReportCallbackEXT))},
     {"vkCreateDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorPool>(CreateDescriptorPool))},
     {"vkCreateDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorSetLayout>(CreateDescriptorSetLayout))},
+    {"vkCreateDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDescriptorUpdateTemplate>(CreateDescriptorUpdateTemplate))},
     {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice))},
     {"vkCreateEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateEvent>(CreateEvent))},
     {"vkCreateFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateFence>(CreateFence))},
@@ -125,6 +131,7 @@
     {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
     {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
     {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
+    {"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
     {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
     {"vkCreateShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateShaderModule>(CreateShaderModule))},
     {"vkDebugReportMessageEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDebugReportMessageEXT>(DebugReportMessageEXT))},
@@ -134,6 +141,7 @@
     {"vkDestroyDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDebugReportCallbackEXT>(DestroyDebugReportCallbackEXT))},
     {"vkDestroyDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorPool>(DestroyDescriptorPool))},
     {"vkDestroyDescriptorSetLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorSetLayout>(DestroyDescriptorSetLayout))},
+    {"vkDestroyDescriptorUpdateTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDescriptorUpdateTemplate>(DestroyDescriptorUpdateTemplate))},
     {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice))},
     {"vkDestroyEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyEvent>(DestroyEvent))},
     {"vkDestroyFence", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyFence>(DestroyFence))},
@@ -147,6 +155,7 @@
     {"vkDestroyQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyQueryPool>(DestroyQueryPool))},
     {"vkDestroyRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyRenderPass>(DestroyRenderPass))},
     {"vkDestroySampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySampler>(DestroySampler))},
+    {"vkDestroySamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySamplerYcbcrConversion>(DestroySamplerYcbcrConversion))},
     {"vkDestroySemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySemaphore>(DestroySemaphore))},
     {"vkDestroyShaderModule", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyShaderModule>(DestroyShaderModule))},
     {"vkDeviceWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDeviceWaitIdle>(DeviceWaitIdle))},
@@ -155,34 +164,52 @@
     {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceLayerProperties>(EnumerateDeviceLayerProperties))},
     {"vkEnumerateInstanceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceExtensionProperties>(EnumerateInstanceExtensionProperties))},
     {"vkEnumerateInstanceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceLayerProperties>(EnumerateInstanceLayerProperties))},
+    {"vkEnumerateInstanceVersion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateInstanceVersion>(EnumerateInstanceVersion))},
+    {"vkEnumeratePhysicalDeviceGroups", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDeviceGroups>(EnumeratePhysicalDeviceGroups))},
     {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDevices>(EnumeratePhysicalDevices))},
     {"vkFlushMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFlushMappedMemoryRanges>(FlushMappedMemoryRanges))},
     {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
     {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
     {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
     {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
+    {"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+    {"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
+    {"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
     {"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
     {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
     {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
+    {"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
     {"vkGetEventStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetEventStatus>(GetEventStatus))},
     {"vkGetFenceStatus", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetFenceStatus>(GetFenceStatus))},
     {"vkGetImageMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements>(GetImageMemoryRequirements))},
+    {"vkGetImageMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageMemoryRequirements2>(GetImageMemoryRequirements2))},
     {"vkGetImageSparseMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements>(GetImageSparseMemoryRequirements))},
+    {"vkGetImageSparseMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSparseMemoryRequirements2>(GetImageSparseMemoryRequirements2))},
     {"vkGetImageSubresourceLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetImageSubresourceLayout>(GetImageSubresourceLayout))},
     {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr))},
+    {"vkGetPhysicalDeviceExternalBufferProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalBufferProperties>(GetPhysicalDeviceExternalBufferProperties))},
+    {"vkGetPhysicalDeviceExternalFenceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(GetPhysicalDeviceExternalFenceProperties))},
+    {"vkGetPhysicalDeviceExternalSemaphoreProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(GetPhysicalDeviceExternalSemaphoreProperties))},
     {"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures>(GetPhysicalDeviceFeatures))},
+    {"vkGetPhysicalDeviceFeatures2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2>(GetPhysicalDeviceFeatures2))},
     {"vkGetPhysicalDeviceFeatures2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(GetPhysicalDeviceFeatures2KHR))},
     {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetPhysicalDeviceFormatProperties))},
+    {"vkGetPhysicalDeviceFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(GetPhysicalDeviceFormatProperties2))},
     {"vkGetPhysicalDeviceFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>(GetPhysicalDeviceFormatProperties2KHR))},
     {"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetPhysicalDeviceImageFormatProperties))},
+    {"vkGetPhysicalDeviceImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(GetPhysicalDeviceImageFormatProperties2))},
     {"vkGetPhysicalDeviceImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>(GetPhysicalDeviceImageFormatProperties2KHR))},
     {"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetPhysicalDeviceMemoryProperties))},
+    {"vkGetPhysicalDeviceMemoryProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2>(GetPhysicalDeviceMemoryProperties2))},
     {"vkGetPhysicalDeviceMemoryProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>(GetPhysicalDeviceMemoryProperties2KHR))},
     {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties>(GetPhysicalDeviceProperties))},
+    {"vkGetPhysicalDeviceProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2>(GetPhysicalDeviceProperties2))},
     {"vkGetPhysicalDeviceProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(GetPhysicalDeviceProperties2KHR))},
     {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetPhysicalDeviceQueueFamilyProperties))},
+    {"vkGetPhysicalDeviceQueueFamilyProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2>(GetPhysicalDeviceQueueFamilyProperties2))},
     {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>(GetPhysicalDeviceQueueFamilyProperties2KHR))},
     {"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetPhysicalDeviceSparseImageFormatProperties))},
+    {"vkGetPhysicalDeviceSparseImageFormatProperties2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2>(GetPhysicalDeviceSparseImageFormatProperties2))},
     {"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>(GetPhysicalDeviceSparseImageFormatProperties2KHR))},
     {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
     {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
@@ -202,7 +229,9 @@
     {"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
     {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
     {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+    {"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
     {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
+    {"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
     {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
     {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
     // clang-format on
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 8a9a963..c6ad537 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -165,6 +165,34 @@
 VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
 VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
 VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
diff --git a/vulkan/vkjson/.clang-format b/vulkan/vkjson/.clang-format
new file mode 100644
index 0000000..3f19e61
--- /dev/null
+++ b/vulkan/vkjson/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Chromium
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
new file mode 100644
index 0000000..e387165
--- /dev/null
+++ b/vulkan/vkjson/Android.bp
@@ -0,0 +1,52 @@
+cc_library_static {
+    name: "libvkjson",
+    srcs: [
+        "vkjson.cc",
+        "vkjson_instance.cc",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++11",
+        "-Wno-sign-compare",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    whole_static_libs: [
+        "libjsoncpp",
+    ],
+    header_libs: [
+        "vulkan_headers",
+    ],
+}
+
+cc_library_static {
+    name: "libvkjson_ndk",
+    clang: true,
+    srcs: [
+        "vkjson.cc",
+        "vkjson_instance.cc",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++11",
+        "-Wno-sign-compare",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    whole_static_libs: [
+        "libjsoncpp_ndk",
+    ],
+    header_libs: [
+        "vulkan_headers_ndk",
+    ],
+    sdk_version: "24",
+    stl: "libc++_static",
+}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
new file mode 100644
index 0000000..6200383
--- /dev/null
+++ b/vulkan/vkjson/vkjson.cc
@@ -0,0 +1,1125 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////////
+
+#include "vkjson.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <cmath>
+#include <cinttypes>
+#include <cstdio>
+#include <limits>
+#include <memory>
+#include <sstream>
+#include <type_traits>
+#include <utility>
+
+#include <json/json.h>
+
+namespace {
+
+inline bool IsIntegral(double value) {
+#if defined(ANDROID)
+  // Android NDK doesn't provide std::trunc yet
+  return trunc(value) == value;
+#else
+  return std::trunc(value) == value;
+#endif
+}
+
+template <typename T> struct EnumTraits;
+template <> struct EnumTraits<VkPhysicalDeviceType> {
+  static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
+  static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
+template <> struct EnumTraits<VkFormat> {
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_FORMAT_UNDEFINED:
+      case VK_FORMAT_R4G4_UNORM_PACK8:
+      case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
+      case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
+      case VK_FORMAT_R5G6B5_UNORM_PACK16:
+      case VK_FORMAT_B5G6R5_UNORM_PACK16:
+      case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+      case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
+      case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
+      case VK_FORMAT_R8_UNORM:
+      case VK_FORMAT_R8_SNORM:
+      case VK_FORMAT_R8_USCALED:
+      case VK_FORMAT_R8_SSCALED:
+      case VK_FORMAT_R8_UINT:
+      case VK_FORMAT_R8_SINT:
+      case VK_FORMAT_R8_SRGB:
+      case VK_FORMAT_R8G8_UNORM:
+      case VK_FORMAT_R8G8_SNORM:
+      case VK_FORMAT_R8G8_USCALED:
+      case VK_FORMAT_R8G8_SSCALED:
+      case VK_FORMAT_R8G8_UINT:
+      case VK_FORMAT_R8G8_SINT:
+      case VK_FORMAT_R8G8_SRGB:
+      case VK_FORMAT_R8G8B8_UNORM:
+      case VK_FORMAT_R8G8B8_SNORM:
+      case VK_FORMAT_R8G8B8_USCALED:
+      case VK_FORMAT_R8G8B8_SSCALED:
+      case VK_FORMAT_R8G8B8_UINT:
+      case VK_FORMAT_R8G8B8_SINT:
+      case VK_FORMAT_R8G8B8_SRGB:
+      case VK_FORMAT_B8G8R8_UNORM:
+      case VK_FORMAT_B8G8R8_SNORM:
+      case VK_FORMAT_B8G8R8_USCALED:
+      case VK_FORMAT_B8G8R8_SSCALED:
+      case VK_FORMAT_B8G8R8_UINT:
+      case VK_FORMAT_B8G8R8_SINT:
+      case VK_FORMAT_B8G8R8_SRGB:
+      case VK_FORMAT_R8G8B8A8_UNORM:
+      case VK_FORMAT_R8G8B8A8_SNORM:
+      case VK_FORMAT_R8G8B8A8_USCALED:
+      case VK_FORMAT_R8G8B8A8_SSCALED:
+      case VK_FORMAT_R8G8B8A8_UINT:
+      case VK_FORMAT_R8G8B8A8_SINT:
+      case VK_FORMAT_R8G8B8A8_SRGB:
+      case VK_FORMAT_B8G8R8A8_UNORM:
+      case VK_FORMAT_B8G8R8A8_SNORM:
+      case VK_FORMAT_B8G8R8A8_USCALED:
+      case VK_FORMAT_B8G8R8A8_SSCALED:
+      case VK_FORMAT_B8G8R8A8_UINT:
+      case VK_FORMAT_B8G8R8A8_SINT:
+      case VK_FORMAT_B8G8R8A8_SRGB:
+      case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
+      case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
+      case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
+      case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
+      case VK_FORMAT_A8B8G8R8_UINT_PACK32:
+      case VK_FORMAT_A8B8G8R8_SINT_PACK32:
+      case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
+      case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+      case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+      case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+      case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+      case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+      case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+      case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+      case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+      case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+      case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+      case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+      case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+      case VK_FORMAT_R16_UNORM:
+      case VK_FORMAT_R16_SNORM:
+      case VK_FORMAT_R16_USCALED:
+      case VK_FORMAT_R16_SSCALED:
+      case VK_FORMAT_R16_UINT:
+      case VK_FORMAT_R16_SINT:
+      case VK_FORMAT_R16_SFLOAT:
+      case VK_FORMAT_R16G16_UNORM:
+      case VK_FORMAT_R16G16_SNORM:
+      case VK_FORMAT_R16G16_USCALED:
+      case VK_FORMAT_R16G16_SSCALED:
+      case VK_FORMAT_R16G16_UINT:
+      case VK_FORMAT_R16G16_SINT:
+      case VK_FORMAT_R16G16_SFLOAT:
+      case VK_FORMAT_R16G16B16_UNORM:
+      case VK_FORMAT_R16G16B16_SNORM:
+      case VK_FORMAT_R16G16B16_USCALED:
+      case VK_FORMAT_R16G16B16_SSCALED:
+      case VK_FORMAT_R16G16B16_UINT:
+      case VK_FORMAT_R16G16B16_SINT:
+      case VK_FORMAT_R16G16B16_SFLOAT:
+      case VK_FORMAT_R16G16B16A16_UNORM:
+      case VK_FORMAT_R16G16B16A16_SNORM:
+      case VK_FORMAT_R16G16B16A16_USCALED:
+      case VK_FORMAT_R16G16B16A16_SSCALED:
+      case VK_FORMAT_R16G16B16A16_UINT:
+      case VK_FORMAT_R16G16B16A16_SINT:
+      case VK_FORMAT_R16G16B16A16_SFLOAT:
+      case VK_FORMAT_R32_UINT:
+      case VK_FORMAT_R32_SINT:
+      case VK_FORMAT_R32_SFLOAT:
+      case VK_FORMAT_R32G32_UINT:
+      case VK_FORMAT_R32G32_SINT:
+      case VK_FORMAT_R32G32_SFLOAT:
+      case VK_FORMAT_R32G32B32_UINT:
+      case VK_FORMAT_R32G32B32_SINT:
+      case VK_FORMAT_R32G32B32_SFLOAT:
+      case VK_FORMAT_R32G32B32A32_UINT:
+      case VK_FORMAT_R32G32B32A32_SINT:
+      case VK_FORMAT_R32G32B32A32_SFLOAT:
+      case VK_FORMAT_R64_UINT:
+      case VK_FORMAT_R64_SINT:
+      case VK_FORMAT_R64_SFLOAT:
+      case VK_FORMAT_R64G64_UINT:
+      case VK_FORMAT_R64G64_SINT:
+      case VK_FORMAT_R64G64_SFLOAT:
+      case VK_FORMAT_R64G64B64_UINT:
+      case VK_FORMAT_R64G64B64_SINT:
+      case VK_FORMAT_R64G64B64_SFLOAT:
+      case VK_FORMAT_R64G64B64A64_UINT:
+      case VK_FORMAT_R64G64B64A64_SINT:
+      case VK_FORMAT_R64G64B64A64_SFLOAT:
+      case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+      case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+      case VK_FORMAT_D16_UNORM:
+      case VK_FORMAT_X8_D24_UNORM_PACK32:
+      case VK_FORMAT_D32_SFLOAT:
+      case VK_FORMAT_S8_UINT:
+      case VK_FORMAT_D16_UNORM_S8_UINT:
+      case VK_FORMAT_D24_UNORM_S8_UINT:
+      case VK_FORMAT_D32_SFLOAT_S8_UINT:
+      case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
+      case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
+      case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
+      case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
+      case VK_FORMAT_BC2_UNORM_BLOCK:
+      case VK_FORMAT_BC2_SRGB_BLOCK:
+      case VK_FORMAT_BC3_UNORM_BLOCK:
+      case VK_FORMAT_BC3_SRGB_BLOCK:
+      case VK_FORMAT_BC4_UNORM_BLOCK:
+      case VK_FORMAT_BC4_SNORM_BLOCK:
+      case VK_FORMAT_BC5_UNORM_BLOCK:
+      case VK_FORMAT_BC5_SNORM_BLOCK:
+      case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+      case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+      case VK_FORMAT_BC7_UNORM_BLOCK:
+      case VK_FORMAT_BC7_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+      case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+      case VK_FORMAT_EAC_R11_SNORM_BLOCK:
+      case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+      case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
+      case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+      case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
+      case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
+      case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
+      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
+      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
+      case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
+      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
+      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
+      case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+        return true;
+    }
+    return false;
+  }
+};
+
+template <>
+struct EnumTraits<VkPointClippingBehavior> {
+  static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
+  static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
+template <>
+struct EnumTraits<VkExternalFenceHandleTypeFlagBits> {
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
+        return true;
+    }
+    return false;
+  }
+};
+
+template <>
+struct EnumTraits<VkExternalSemaphoreHandleTypeFlagBits> {
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
+        return true;
+    }
+    return false;
+  }
+};
+
+// VkSparseImageFormatProperties
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkExtent3D* extents) {
+  return
+    visitor->Visit("width", &extents->width) &&
+    visitor->Visit("height", &extents->height) &&
+    visitor->Visit("depth", &extents->depth);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkImageFormatProperties* properties) {
+  return
+    visitor->Visit("maxExtent", &properties->maxExtent) &&
+    visitor->Visit("maxMipLevels", &properties->maxMipLevels) &&
+    visitor->Visit("maxArrayLayers", &properties->maxArrayLayers) &&
+    visitor->Visit("sampleCounts", &properties->sampleCounts) &&
+    visitor->Visit("maxResourceSize", &properties->maxResourceSize);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkPhysicalDeviceLimits* limits) {
+  return
+    visitor->Visit("maxImageDimension1D", &limits->maxImageDimension1D) &&
+    visitor->Visit("maxImageDimension2D", &limits->maxImageDimension2D) &&
+    visitor->Visit("maxImageDimension3D", &limits->maxImageDimension3D) &&
+    visitor->Visit("maxImageDimensionCube", &limits->maxImageDimensionCube) &&
+    visitor->Visit("maxImageArrayLayers", &limits->maxImageArrayLayers) &&
+    visitor->Visit("maxTexelBufferElements", &limits->maxTexelBufferElements) &&
+    visitor->Visit("maxUniformBufferRange", &limits->maxUniformBufferRange) &&
+    visitor->Visit("maxStorageBufferRange", &limits->maxStorageBufferRange) &&
+    visitor->Visit("maxPushConstantsSize", &limits->maxPushConstantsSize) &&
+    visitor->Visit("maxMemoryAllocationCount", &limits->maxMemoryAllocationCount) &&
+    visitor->Visit("maxSamplerAllocationCount", &limits->maxSamplerAllocationCount) &&
+    visitor->Visit("bufferImageGranularity", &limits->bufferImageGranularity) &&
+    visitor->Visit("sparseAddressSpaceSize", &limits->sparseAddressSpaceSize) &&
+    visitor->Visit("maxBoundDescriptorSets", &limits->maxBoundDescriptorSets) &&
+    visitor->Visit("maxPerStageDescriptorSamplers", &limits->maxPerStageDescriptorSamplers) &&
+    visitor->Visit("maxPerStageDescriptorUniformBuffers", &limits->maxPerStageDescriptorUniformBuffers) &&
+    visitor->Visit("maxPerStageDescriptorStorageBuffers", &limits->maxPerStageDescriptorStorageBuffers) &&
+    visitor->Visit("maxPerStageDescriptorSampledImages", &limits->maxPerStageDescriptorSampledImages) &&
+    visitor->Visit("maxPerStageDescriptorStorageImages", &limits->maxPerStageDescriptorStorageImages) &&
+    visitor->Visit("maxPerStageDescriptorInputAttachments", &limits->maxPerStageDescriptorInputAttachments) &&
+    visitor->Visit("maxPerStageResources", &limits->maxPerStageResources) &&
+    visitor->Visit("maxDescriptorSetSamplers", &limits->maxDescriptorSetSamplers) &&
+    visitor->Visit("maxDescriptorSetUniformBuffers", &limits->maxDescriptorSetUniformBuffers) &&
+    visitor->Visit("maxDescriptorSetUniformBuffersDynamic", &limits->maxDescriptorSetUniformBuffersDynamic) &&
+    visitor->Visit("maxDescriptorSetStorageBuffers", &limits->maxDescriptorSetStorageBuffers) &&
+    visitor->Visit("maxDescriptorSetStorageBuffersDynamic", &limits->maxDescriptorSetStorageBuffersDynamic) &&
+    visitor->Visit("maxDescriptorSetSampledImages", &limits->maxDescriptorSetSampledImages) &&
+    visitor->Visit("maxDescriptorSetStorageImages", &limits->maxDescriptorSetStorageImages) &&
+    visitor->Visit("maxDescriptorSetInputAttachments", &limits->maxDescriptorSetInputAttachments) &&
+    visitor->Visit("maxVertexInputAttributes", &limits->maxVertexInputAttributes) &&
+    visitor->Visit("maxVertexInputBindings", &limits->maxVertexInputBindings) &&
+    visitor->Visit("maxVertexInputAttributeOffset", &limits->maxVertexInputAttributeOffset) &&
+    visitor->Visit("maxVertexInputBindingStride", &limits->maxVertexInputBindingStride) &&
+    visitor->Visit("maxVertexOutputComponents", &limits->maxVertexOutputComponents) &&
+    visitor->Visit("maxTessellationGenerationLevel", &limits->maxTessellationGenerationLevel) &&
+    visitor->Visit("maxTessellationPatchSize", &limits->maxTessellationPatchSize) &&
+    visitor->Visit("maxTessellationControlPerVertexInputComponents", &limits->maxTessellationControlPerVertexInputComponents) &&
+    visitor->Visit("maxTessellationControlPerVertexOutputComponents", &limits->maxTessellationControlPerVertexOutputComponents) &&
+    visitor->Visit("maxTessellationControlPerPatchOutputComponents", &limits->maxTessellationControlPerPatchOutputComponents) &&
+    visitor->Visit("maxTessellationControlTotalOutputComponents", &limits->maxTessellationControlTotalOutputComponents) &&
+    visitor->Visit("maxTessellationEvaluationInputComponents", &limits->maxTessellationEvaluationInputComponents) &&
+    visitor->Visit("maxTessellationEvaluationOutputComponents", &limits->maxTessellationEvaluationOutputComponents) &&
+    visitor->Visit("maxGeometryShaderInvocations", &limits->maxGeometryShaderInvocations) &&
+    visitor->Visit("maxGeometryInputComponents", &limits->maxGeometryInputComponents) &&
+    visitor->Visit("maxGeometryOutputComponents", &limits->maxGeometryOutputComponents) &&
+    visitor->Visit("maxGeometryOutputVertices", &limits->maxGeometryOutputVertices) &&
+    visitor->Visit("maxGeometryTotalOutputComponents", &limits->maxGeometryTotalOutputComponents) &&
+    visitor->Visit("maxFragmentInputComponents", &limits->maxFragmentInputComponents) &&
+    visitor->Visit("maxFragmentOutputAttachments", &limits->maxFragmentOutputAttachments) &&
+    visitor->Visit("maxFragmentDualSrcAttachments", &limits->maxFragmentDualSrcAttachments) &&
+    visitor->Visit("maxFragmentCombinedOutputResources", &limits->maxFragmentCombinedOutputResources) &&
+    visitor->Visit("maxComputeSharedMemorySize", &limits->maxComputeSharedMemorySize) &&
+    visitor->Visit("maxComputeWorkGroupCount", &limits->maxComputeWorkGroupCount) &&
+    visitor->Visit("maxComputeWorkGroupInvocations", &limits->maxComputeWorkGroupInvocations) &&
+    visitor->Visit("maxComputeWorkGroupSize", &limits->maxComputeWorkGroupSize) &&
+    visitor->Visit("subPixelPrecisionBits", &limits->subPixelPrecisionBits) &&
+    visitor->Visit("subTexelPrecisionBits", &limits->subTexelPrecisionBits) &&
+    visitor->Visit("mipmapPrecisionBits", &limits->mipmapPrecisionBits) &&
+    visitor->Visit("maxDrawIndexedIndexValue", &limits->maxDrawIndexedIndexValue) &&
+    visitor->Visit("maxDrawIndirectCount", &limits->maxDrawIndirectCount) &&
+    visitor->Visit("maxSamplerLodBias", &limits->maxSamplerLodBias) &&
+    visitor->Visit("maxSamplerAnisotropy", &limits->maxSamplerAnisotropy) &&
+    visitor->Visit("maxViewports", &limits->maxViewports) &&
+    visitor->Visit("maxViewportDimensions", &limits->maxViewportDimensions) &&
+    visitor->Visit("viewportBoundsRange", &limits->viewportBoundsRange) &&
+    visitor->Visit("viewportSubPixelBits", &limits->viewportSubPixelBits) &&
+    visitor->Visit("minMemoryMapAlignment", &limits->minMemoryMapAlignment) &&
+    visitor->Visit("minTexelBufferOffsetAlignment", &limits->minTexelBufferOffsetAlignment) &&
+    visitor->Visit("minUniformBufferOffsetAlignment", &limits->minUniformBufferOffsetAlignment) &&
+    visitor->Visit("minStorageBufferOffsetAlignment", &limits->minStorageBufferOffsetAlignment) &&
+    visitor->Visit("minTexelOffset", &limits->minTexelOffset) &&
+    visitor->Visit("maxTexelOffset", &limits->maxTexelOffset) &&
+    visitor->Visit("minTexelGatherOffset", &limits->minTexelGatherOffset) &&
+    visitor->Visit("maxTexelGatherOffset", &limits->maxTexelGatherOffset) &&
+    visitor->Visit("minInterpolationOffset", &limits->minInterpolationOffset) &&
+    visitor->Visit("maxInterpolationOffset", &limits->maxInterpolationOffset) &&
+    visitor->Visit("subPixelInterpolationOffsetBits", &limits->subPixelInterpolationOffsetBits) &&
+    visitor->Visit("maxFramebufferWidth", &limits->maxFramebufferWidth) &&
+    visitor->Visit("maxFramebufferHeight", &limits->maxFramebufferHeight) &&
+    visitor->Visit("maxFramebufferLayers", &limits->maxFramebufferLayers) &&
+    visitor->Visit("framebufferColorSampleCounts", &limits->framebufferColorSampleCounts) &&
+    visitor->Visit("framebufferDepthSampleCounts", &limits->framebufferDepthSampleCounts) &&
+    visitor->Visit("framebufferStencilSampleCounts", &limits->framebufferStencilSampleCounts) &&
+    visitor->Visit("framebufferNoAttachmentsSampleCounts", &limits->framebufferNoAttachmentsSampleCounts) &&
+    visitor->Visit("maxColorAttachments", &limits->maxColorAttachments) &&
+    visitor->Visit("sampledImageColorSampleCounts", &limits->sampledImageColorSampleCounts) &&
+    visitor->Visit("sampledImageIntegerSampleCounts", &limits->sampledImageIntegerSampleCounts) &&
+    visitor->Visit("sampledImageDepthSampleCounts", &limits->sampledImageDepthSampleCounts) &&
+    visitor->Visit("sampledImageStencilSampleCounts", &limits->sampledImageStencilSampleCounts) &&
+    visitor->Visit("storageImageSampleCounts", &limits->storageImageSampleCounts) &&
+    visitor->Visit("maxSampleMaskWords", &limits->maxSampleMaskWords) &&
+    visitor->Visit("timestampComputeAndGraphics", &limits->timestampComputeAndGraphics) &&
+    visitor->Visit("timestampPeriod", &limits->timestampPeriod) &&
+    visitor->Visit("maxClipDistances", &limits->maxClipDistances) &&
+    visitor->Visit("maxCullDistances", &limits->maxCullDistances) &&
+    visitor->Visit("maxCombinedClipAndCullDistances", &limits->maxCombinedClipAndCullDistances) &&
+    visitor->Visit("discreteQueuePriorities", &limits->discreteQueuePriorities) &&
+    visitor->Visit("pointSizeRange", &limits->pointSizeRange) &&
+    visitor->Visit("lineWidthRange", &limits->lineWidthRange) &&
+    visitor->Visit("pointSizeGranularity", &limits->pointSizeGranularity) &&
+    visitor->Visit("lineWidthGranularity", &limits->lineWidthGranularity) &&
+    visitor->Visit("strictLines", &limits->strictLines) &&
+    visitor->Visit("standardSampleLocations", &limits->standardSampleLocations) &&
+    visitor->Visit("optimalBufferCopyOffsetAlignment", &limits->optimalBufferCopyOffsetAlignment) &&
+    visitor->Visit("optimalBufferCopyRowPitchAlignment", &limits->optimalBufferCopyRowPitchAlignment) &&
+    visitor->Visit("nonCoherentAtomSize", &limits->nonCoherentAtomSize);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceSparseProperties* properties) {
+  return
+    visitor->Visit("residencyStandard2DBlockShape", &properties->residencyStandard2DBlockShape) &&
+    visitor->Visit("residencyStandard2DMultisampleBlockShape", &properties->residencyStandard2DMultisampleBlockShape) &&
+    visitor->Visit("residencyStandard3DBlockShape", &properties->residencyStandard3DBlockShape) &&
+    visitor->Visit("residencyAlignedMipSize", &properties->residencyAlignedMipSize) &&
+    visitor->Visit("residencyNonResidentStrict", &properties->residencyNonResidentStrict);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceProperties* properties) {
+  return
+    visitor->Visit("apiVersion", &properties->apiVersion) &&
+    visitor->Visit("driverVersion", &properties->driverVersion) &&
+    visitor->Visit("vendorID", &properties->vendorID) &&
+    visitor->Visit("deviceID", &properties->deviceID) &&
+    visitor->Visit("deviceType", &properties->deviceType) &&
+    visitor->Visit("deviceName", &properties->deviceName) &&
+    visitor->Visit("pipelineCacheUUID", &properties->pipelineCacheUUID) &&
+    visitor->Visit("limits", &properties->limits) &&
+    visitor->Visit("sparseProperties", &properties->sparseProperties);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkPhysicalDeviceFeatures* features) {
+  return
+    visitor->Visit("robustBufferAccess", &features->robustBufferAccess) &&
+    visitor->Visit("fullDrawIndexUint32", &features->fullDrawIndexUint32) &&
+    visitor->Visit("imageCubeArray", &features->imageCubeArray) &&
+    visitor->Visit("independentBlend", &features->independentBlend) &&
+    visitor->Visit("geometryShader", &features->geometryShader) &&
+    visitor->Visit("tessellationShader", &features->tessellationShader) &&
+    visitor->Visit("sampleRateShading", &features->sampleRateShading) &&
+    visitor->Visit("dualSrcBlend", &features->dualSrcBlend) &&
+    visitor->Visit("logicOp", &features->logicOp) &&
+    visitor->Visit("multiDrawIndirect", &features->multiDrawIndirect) &&
+    visitor->Visit("drawIndirectFirstInstance", &features->drawIndirectFirstInstance) &&
+    visitor->Visit("depthClamp", &features->depthClamp) &&
+    visitor->Visit("depthBiasClamp", &features->depthBiasClamp) &&
+    visitor->Visit("fillModeNonSolid", &features->fillModeNonSolid) &&
+    visitor->Visit("depthBounds", &features->depthBounds) &&
+    visitor->Visit("wideLines", &features->wideLines) &&
+    visitor->Visit("largePoints", &features->largePoints) &&
+    visitor->Visit("alphaToOne", &features->alphaToOne) &&
+    visitor->Visit("multiViewport", &features->multiViewport) &&
+    visitor->Visit("samplerAnisotropy", &features->samplerAnisotropy) &&
+    visitor->Visit("textureCompressionETC2", &features->textureCompressionETC2) &&
+    visitor->Visit("textureCompressionASTC_LDR", &features->textureCompressionASTC_LDR) &&
+    visitor->Visit("textureCompressionBC", &features->textureCompressionBC) &&
+    visitor->Visit("occlusionQueryPrecise", &features->occlusionQueryPrecise) &&
+    visitor->Visit("pipelineStatisticsQuery", &features->pipelineStatisticsQuery) &&
+    visitor->Visit("vertexPipelineStoresAndAtomics", &features->vertexPipelineStoresAndAtomics) &&
+    visitor->Visit("fragmentStoresAndAtomics", &features->fragmentStoresAndAtomics) &&
+    visitor->Visit("shaderTessellationAndGeometryPointSize", &features->shaderTessellationAndGeometryPointSize) &&
+    visitor->Visit("shaderImageGatherExtended", &features->shaderImageGatherExtended) &&
+    visitor->Visit("shaderStorageImageExtendedFormats", &features->shaderStorageImageExtendedFormats) &&
+    visitor->Visit("shaderStorageImageMultisample", &features->shaderStorageImageMultisample) &&
+    visitor->Visit("shaderStorageImageReadWithoutFormat", &features->shaderStorageImageReadWithoutFormat) &&
+    visitor->Visit("shaderStorageImageWriteWithoutFormat", &features->shaderStorageImageWriteWithoutFormat) &&
+    visitor->Visit("shaderUniformBufferArrayDynamicIndexing", &features->shaderUniformBufferArrayDynamicIndexing) &&
+    visitor->Visit("shaderSampledImageArrayDynamicIndexing", &features->shaderSampledImageArrayDynamicIndexing) &&
+    visitor->Visit("shaderStorageBufferArrayDynamicIndexing", &features->shaderStorageBufferArrayDynamicIndexing) &&
+    visitor->Visit("shaderStorageImageArrayDynamicIndexing", &features->shaderStorageImageArrayDynamicIndexing) &&
+    visitor->Visit("shaderClipDistance", &features->shaderClipDistance) &&
+    visitor->Visit("shaderCullDistance", &features->shaderCullDistance) &&
+    visitor->Visit("shaderFloat64", &features->shaderFloat64) &&
+    visitor->Visit("shaderInt64", &features->shaderInt64) &&
+    visitor->Visit("shaderInt16", &features->shaderInt16) &&
+    visitor->Visit("shaderResourceResidency", &features->shaderResourceResidency) &&
+    visitor->Visit("shaderResourceMinLod", &features->shaderResourceMinLod) &&
+    visitor->Visit("sparseBinding", &features->sparseBinding) &&
+    visitor->Visit("sparseResidencyBuffer", &features->sparseResidencyBuffer) &&
+    visitor->Visit("sparseResidencyImage2D", &features->sparseResidencyImage2D) &&
+    visitor->Visit("sparseResidencyImage3D", &features->sparseResidencyImage3D) &&
+    visitor->Visit("sparseResidency2Samples", &features->sparseResidency2Samples) &&
+    visitor->Visit("sparseResidency4Samples", &features->sparseResidency4Samples) &&
+    visitor->Visit("sparseResidency8Samples", &features->sparseResidency8Samples) &&
+    visitor->Visit("sparseResidency16Samples", &features->sparseResidency16Samples) &&
+    visitor->Visit("sparseResidencyAliased", &features->sparseResidencyAliased) &&
+    visitor->Visit("variableMultisampleRate", &features->variableMultisampleRate) &&
+    visitor->Visit("inheritedQueries", &features->inheritedQueries);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkJsonExtVariablePointerFeatures* features) {
+  return visitor->Visit("variablePointerFeaturesKHR",
+                        &features->variable_pointer_features_khr);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkMemoryType* type) {
+  return
+    visitor->Visit("propertyFlags", &type->propertyFlags) &&
+    visitor->Visit("heapIndex", &type->heapIndex);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) {
+  return
+    visitor->Visit("size", &heap->size) &&
+    visitor->Visit("flags", &heap->flags);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkPhysicalDeviceMemoryProperties* properties) {
+  return
+    visitor->Visit("memoryTypeCount", &properties->memoryTypeCount) &&
+    visitor->VisitArray("memoryTypes", properties->memoryTypeCount, &properties->memoryTypes) &&
+    visitor->Visit("memoryHeapCount", &properties->memoryHeapCount) &&
+    visitor->VisitArray("memoryHeaps", properties->memoryHeapCount, &properties->memoryHeaps);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceSubgroupProperties* properties) {
+  return visitor->Visit("subgroupSize", &properties->subgroupSize) &&
+         visitor->Visit("supportedStages", &properties->supportedStages) &&
+         visitor->Visit("supportedOperations",
+                        &properties->supportedOperations) &&
+         visitor->Visit("quadOperationsInAllStages",
+                        &properties->quadOperationsInAllStages);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDevicePointClippingProperties* properties) {
+  return visitor->Visit("pointClippingBehavior",
+                        &properties->pointClippingBehavior);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMultiviewProperties* properties) {
+  return visitor->Visit("maxMultiviewViewCount",
+                        &properties->maxMultiviewViewCount) &&
+         visitor->Visit("maxMultiviewInstanceIndex",
+                        &properties->maxMultiviewInstanceIndex);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceIDProperties* properties) {
+  return visitor->Visit("deviceUUID", &properties->deviceUUID) &&
+         visitor->Visit("driverUUID", &properties->driverUUID) &&
+         visitor->Visit("deviceLUID", &properties->deviceLUID) &&
+         visitor->Visit("deviceNodeMask", &properties->deviceNodeMask) &&
+         visitor->Visit("deviceLUIDValid", &properties->deviceLUIDValid);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMaintenance3Properties* properties) {
+  return visitor->Visit("maxPerSetDescriptors",
+                        &properties->maxPerSetDescriptors) &&
+         visitor->Visit("maxMemoryAllocationSize",
+                        &properties->maxMemoryAllocationSize);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDevice16BitStorageFeatures* features) {
+  return visitor->Visit("storageBuffer16BitAccess",
+                        &features->storageBuffer16BitAccess) &&
+         visitor->Visit("uniformAndStorageBuffer16BitAccess",
+                        &features->uniformAndStorageBuffer16BitAccess) &&
+         visitor->Visit("storagePushConstant16",
+                        &features->storagePushConstant16) &&
+         visitor->Visit("storageInputOutput16",
+                        &features->storageInputOutput16);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMultiviewFeatures* features) {
+  return visitor->Visit("multiview", &features->multiview) &&
+         visitor->Visit("multiviewGeometryShader",
+                        &features->multiviewGeometryShader) &&
+         visitor->Visit("multiviewTessellationShader",
+                        &features->multiviewTessellationShader);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceVariablePointerFeatures* features) {
+  return visitor->Visit("variablePointersStorageBuffer",
+                        &features->variablePointersStorageBuffer) &&
+         visitor->Visit("variablePointers", &features->variablePointers);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceProtectedMemoryFeatures* features) {
+  return visitor->Visit("protectedMemory", &features->protectedMemory);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceSamplerYcbcrConversionFeatures* features) {
+  return visitor->Visit("samplerYcbcrConversion",
+                        &features->samplerYcbcrConversion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceShaderDrawParameterFeatures* features) {
+  return visitor->Visit("shaderDrawParameters",
+                        &features->shaderDrawParameters);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkExternalFenceProperties* properties) {
+  return visitor->Visit("exportFromImportedHandleTypes",
+                        &properties->exportFromImportedHandleTypes) &&
+         visitor->Visit("compatibleHandleTypes",
+                        &properties->compatibleHandleTypes) &&
+         visitor->Visit("externalFenceFeatures",
+                        &properties->externalFenceFeatures);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkExternalSemaphoreProperties* properties) {
+  return visitor->Visit("exportFromImportedHandleTypes",
+                        &properties->exportFromImportedHandleTypes) &&
+         visitor->Visit("compatibleHandleTypes",
+                        &properties->compatibleHandleTypes) &&
+         visitor->Visit("externalSemaphoreFeatures",
+                        &properties->externalSemaphoreFeatures);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkQueueFamilyProperties* properties) {
+  return
+    visitor->Visit("queueFlags", &properties->queueFlags) &&
+    visitor->Visit("queueCount", &properties->queueCount) &&
+    visitor->Visit("timestampValidBits", &properties->timestampValidBits) &&
+    visitor->Visit("minImageTransferGranularity", &properties->minImageTransferGranularity);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkExtensionProperties* properties) {
+  return
+    visitor->Visit("extensionName", &properties->extensionName) &&
+    visitor->Visit("specVersion", &properties->specVersion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkLayerProperties* properties) {
+  return
+    visitor->Visit("layerName", &properties->layerName) &&
+    visitor->Visit("specVersion", &properties->specVersion) &&
+    visitor->Visit("implementationVersion", &properties->implementationVersion) &&
+    visitor->Visit("description", &properties->description);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkFormatProperties* properties) {
+  return
+    visitor->Visit("linearTilingFeatures", &properties->linearTilingFeatures) &&
+    visitor->Visit("optimalTilingFeatures", &properties->optimalTilingFeatures) &&
+    visitor->Visit("bufferFeatures", &properties->bufferFeatures);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonLayer* layer) {
+  return visitor->Visit("properties", &layer->properties) &&
+         visitor->Visit("extensions", &layer->extensions);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonDeviceGroup* device_group) {
+  return visitor->Visit("devices", &device_group->device_inds) &&
+         visitor->Visit("subsetAllocation",
+                        &device_group->properties.subsetAllocation);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonDevice* device) {
+  bool ret = true;
+  switch (device->properties.apiVersion ^
+          VK_VERSION_PATCH(device->properties.apiVersion)) {
+    case VK_API_VERSION_1_1:
+      ret &=
+          visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
+          visitor->Visit("pointClippingProperties",
+                         &device->point_clipping_properties) &&
+          visitor->Visit("multiviewProperties",
+                         &device->multiview_properties) &&
+          visitor->Visit("idProperties", &device->id_properties) &&
+          visitor->Visit("maintenance3Properties",
+                         &device->maintenance3_properties) &&
+          visitor->Visit("16bitStorageFeatures",
+                         &device->bit16_storage_features) &&
+          visitor->Visit("multiviewFeatures", &device->multiview_features) &&
+          visitor->Visit("variablePointerFeatures",
+                         &device->variable_pointer_features) &&
+          visitor->Visit("protectedMemoryFeatures",
+                         &device->protected_memory_features) &&
+          visitor->Visit("samplerYcbcrConversionFeatures",
+                         &device->sampler_ycbcr_conversion_features) &&
+          visitor->Visit("shaderDrawParameterFeatures",
+                         &device->shader_draw_parameter_features) &&
+          visitor->Visit("externalFenceProperties",
+                         &device->external_fence_properties) &&
+          visitor->Visit("externalSemaphoreProperties",
+                         &device->external_semaphore_properties);
+    case VK_API_VERSION_1_0:
+      ret &= visitor->Visit("properties", &device->properties) &&
+             visitor->Visit("features", &device->features) &&
+             visitor->Visit("VK_KHR_variable_pointers",
+                            &device->ext_variable_pointer_features) &&
+             visitor->Visit("memory", &device->memory) &&
+             visitor->Visit("queues", &device->queues) &&
+             visitor->Visit("extensions", &device->extensions) &&
+             visitor->Visit("layers", &device->layers) &&
+             visitor->Visit("formats", &device->formats);
+  }
+  return ret;
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
+  bool ret = true;
+  switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
+    case VK_API_VERSION_1_1:
+      ret &= visitor->Visit("deviceGroups", &instance->device_groups);
+    case VK_API_VERSION_1_0:
+      ret &= visitor->Visit("layers", &instance->layers) &&
+             visitor->Visit("extensions", &instance->extensions) &&
+             visitor->Visit("devices", &instance->devices);
+  }
+  return ret;
+}
+
+template <typename T>
+using EnableForArithmetic =
+    typename std::enable_if<std::is_arithmetic<T>::value, void>::type;
+
+template <typename T>
+using EnableForStruct =
+    typename std::enable_if<std::is_class<T>::value, void>::type;
+
+template <typename T>
+using EnableForEnum =
+    typename std::enable_if<std::is_enum<T>::value, void>::type;
+
+template <typename T, typename = EnableForStruct<T>, typename = void>
+Json::Value ToJsonValue(const T& value);
+
+template <typename T, typename = EnableForArithmetic<T>>
+inline Json::Value ToJsonValue(const T& value) {
+  return Json::Value(static_cast<double>(value));
+}
+
+inline Json::Value ToJsonValue(const uint64_t& value) {
+  char string[19] = {0};  // "0x" + 16 digits + terminal \0
+  snprintf(string, sizeof(string), "0x%016" PRIx64, value);
+  return Json::Value(string);
+}
+
+template <typename T, typename = EnableForEnum<T>, typename = void,
+          typename = void>
+inline Json::Value ToJsonValue(const T& value) {
+  return Json::Value(static_cast<double>(value));
+}
+
+template <typename T>
+inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) {
+  Json::Value array(Json::arrayValue);
+  for (unsigned int i = 0; i < count; ++i) array.append(ToJsonValue(values[i]));
+  return array;
+}
+
+template <typename T, unsigned int N>
+inline Json::Value ToJsonValue(const T (&value)[N]) {
+  return ArrayToJsonValue(N, value);
+}
+
+template <size_t N>
+inline Json::Value ToJsonValue(const char (&value)[N]) {
+  assert(strlen(value) < N);
+  return Json::Value(value);
+}
+
+template <typename T>
+inline Json::Value ToJsonValue(const std::vector<T>& value) {
+  assert(value.size() <= std::numeric_limits<uint32_t>::max());
+  return ArrayToJsonValue(static_cast<uint32_t>(value.size()), value.data());
+}
+
+template <typename F, typename S>
+inline Json::Value ToJsonValue(const std::pair<F, S>& value) {
+  Json::Value array(Json::arrayValue);
+  array.append(ToJsonValue(value.first));
+  array.append(ToJsonValue(value.second));
+  return array;
+}
+
+template <typename F, typename S>
+inline Json::Value ToJsonValue(const std::map<F, S>& value) {
+  Json::Value array(Json::arrayValue);
+  for (auto& kv : value) array.append(ToJsonValue(kv));
+  return array;
+}
+
+class JsonWriterVisitor {
+ public:
+  JsonWriterVisitor() : object_(Json::objectValue) {}
+
+  ~JsonWriterVisitor() {}
+
+  template <typename T> bool Visit(const char* key, const T* value) {
+    object_[key] = ToJsonValue(*value);
+    return true;
+  }
+
+  template <typename T, uint32_t N>
+  bool VisitArray(const char* key, uint32_t count, const T (*value)[N]) {
+    assert(count <= N);
+    object_[key] = ArrayToJsonValue(count, *value);
+    return true;
+  }
+
+  Json::Value get_object() const { return object_; }
+
+ private:
+  Json::Value object_;
+};
+
+template <typename Visitor, typename T>
+inline void VisitForWrite(Visitor* visitor, const T& t) {
+  Iterate(visitor, const_cast<T*>(&t));
+}
+
+template <typename T, typename /*= EnableForStruct<T>*/, typename /*= void*/>
+Json::Value ToJsonValue(const T& value) {
+  JsonWriterVisitor visitor;
+  VisitForWrite(&visitor, value);
+  return visitor.get_object();
+}
+
+template <typename T, typename = EnableForStruct<T>>
+bool AsValue(Json::Value* json_value, T* t);
+
+inline bool AsValue(Json::Value* json_value, int32_t* value) {
+  if (json_value->type() != Json::realValue) return false;
+  double d = json_value->asDouble();
+  if (!IsIntegral(d) ||
+      d < static_cast<double>(std::numeric_limits<int32_t>::min()) ||
+      d > static_cast<double>(std::numeric_limits<int32_t>::max()))
+    return false;
+  *value = static_cast<int32_t>(d);
+  return true;
+}
+
+inline bool AsValue(Json::Value* json_value, uint64_t* value) {
+  if (json_value->type() != Json::stringValue) return false;
+  int result =
+      std::sscanf(json_value->asString().c_str(), "0x%016" PRIx64, value);
+  return result == 1;
+}
+
+inline bool AsValue(Json::Value* json_value, uint32_t* value) {
+  if (json_value->type() != Json::realValue) return false;
+  double d = json_value->asDouble();
+  if (!IsIntegral(d) || d < 0.0 ||
+      d > static_cast<double>(std::numeric_limits<uint32_t>::max()))
+    return false;
+  *value = static_cast<uint32_t>(d);
+  return true;
+}
+
+inline bool AsValue(Json::Value* json_value, uint8_t* value) {
+  uint32_t value32 = 0;
+  AsValue(json_value, &value32);
+  if (value32 > std::numeric_limits<uint8_t>::max())
+    return false;
+  *value = static_cast<uint8_t>(value32);
+  return true;
+}
+
+inline bool AsValue(Json::Value* json_value, float* value) {
+  if (json_value->type() != Json::realValue) return false;
+  *value = static_cast<float>(json_value->asDouble());
+  return true;
+}
+
+template <typename T>
+inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) {
+  if (json_value->type() != Json::arrayValue || json_value->size() != count)
+    return false;
+  for (uint32_t i = 0; i < count; ++i) {
+    if (!AsValue(&(*json_value)[i], values + i)) return false;
+  }
+  return true;
+}
+
+template <typename T, unsigned int N>
+inline bool AsValue(Json::Value* json_value, T (*value)[N]) {
+  return AsArray(json_value, N, *value);
+}
+
+template <size_t N>
+inline bool AsValue(Json::Value* json_value, char (*value)[N]) {
+  if (json_value->type() != Json::stringValue) return false;
+  size_t len = json_value->asString().length();
+  if (len >= N)
+    return false;
+  memcpy(*value, json_value->asString().c_str(), len);
+  memset(*value + len, 0, N-len);
+  return true;
+}
+
+template <typename T, typename = EnableForEnum<T>, typename = void>
+inline bool AsValue(Json::Value* json_value, T* t) {
+  uint32_t value = 0;
+  if (!AsValue(json_value, &value))
+      return false;
+  if (!EnumTraits<T>::exist(value)) return false;
+  *t = static_cast<T>(value);
+  return true;
+}
+
+template <typename T>
+inline bool AsValue(Json::Value* json_value, std::vector<T>* value) {
+  if (json_value->type() != Json::arrayValue) return false;
+  int size = json_value->size();
+  value->resize(size);
+  return AsArray(json_value, size, value->data());
+}
+
+template <typename F, typename S>
+inline bool AsValue(Json::Value* json_value, std::pair<F, S>* value) {
+  if (json_value->type() != Json::arrayValue || json_value->size() != 2)
+    return false;
+  return AsValue(&(*json_value)[0], &value->first) &&
+         AsValue(&(*json_value)[1], &value->second);
+}
+
+template <typename F, typename S>
+inline bool AsValue(Json::Value* json_value, std::map<F, S>* value) {
+  if (json_value->type() != Json::arrayValue) return false;
+  int size = json_value->size();
+  for (int i = 0; i < size; ++i) {
+    std::pair<F, S> elem;
+    if (!AsValue(&(*json_value)[i], &elem)) return false;
+    if (!value->insert(elem).second)
+      return false;
+  }
+  return true;
+}
+
+template <typename T>
+bool ReadValue(Json::Value* object, const char* key, T* value,
+               std::string* errors) {
+  Json::Value json_value = (*object)[key];
+  if (!json_value) {
+    if (errors)
+      *errors = std::string(key) + " missing.";
+    return false;
+  }
+  if (AsValue(&json_value, value)) return true;
+  if (errors)
+    *errors = std::string("Wrong type for ") + std::string(key) + ".";
+  return false;
+}
+
+template <typename Visitor, typename T>
+inline bool VisitForRead(Visitor* visitor, T* t) {
+  return Iterate(visitor, t);
+}
+
+class JsonReaderVisitor {
+ public:
+  JsonReaderVisitor(Json::Value* object, std::string* errors)
+      : object_(object), errors_(errors) {}
+
+  template <typename T> bool Visit(const char* key, T* value) const {
+    return ReadValue(object_, key, value, errors_);
+  }
+
+  template <typename T, uint32_t N>
+  bool VisitArray(const char* key, uint32_t count, T (*value)[N]) {
+    if (count > N)
+      return false;
+    Json::Value json_value = (*object_)[key];
+    if (!json_value) {
+      if (errors_)
+        *errors_ = std::string(key) + " missing.";
+      return false;
+    }
+    if (AsArray(&json_value, count, *value)) return true;
+    if (errors_)
+      *errors_ = std::string("Wrong type for ") + std::string(key) + ".";
+    return false;
+  }
+
+
+ private:
+  Json::Value* object_;
+  std::string* errors_;
+};
+
+template <typename T, typename /*= EnableForStruct<T>*/>
+bool AsValue(Json::Value* json_value, T* t) {
+  if (json_value->type() != Json::objectValue) return false;
+  JsonReaderVisitor visitor(json_value, nullptr);
+  return VisitForRead(&visitor, t);
+}
+
+
+template <typename T> std::string VkTypeToJson(const T& t) {
+  JsonWriterVisitor visitor;
+  VisitForWrite(&visitor, t);
+  return visitor.get_object().toStyledString();
+}
+
+template <typename T> bool VkTypeFromJson(const std::string& json,
+                                          T* t,
+                                          std::string* errors) {
+  *t = T();
+  Json::Value object(Json::objectValue);
+  Json::Reader reader;
+  reader.parse(json, object, false);
+  if (!object) {
+    if (errors) errors->assign(reader.getFormatedErrorMessages());
+    return false;
+  }
+  return AsValue(&object, t);
+}
+
+}  // anonymous namespace
+
+std::string VkJsonInstanceToJson(const VkJsonInstance& instance) {
+  return VkTypeToJson(instance);
+}
+
+bool VkJsonInstanceFromJson(const std::string& json,
+                            VkJsonInstance* instance,
+                            std::string* errors) {
+  return VkTypeFromJson(json, instance, errors);
+}
+
+std::string VkJsonDeviceToJson(const VkJsonDevice& device) {
+  return VkTypeToJson(device);
+}
+
+bool VkJsonDeviceFromJson(const std::string& json,
+                          VkJsonDevice* device,
+                          std::string* errors) {
+  return VkTypeFromJson(json, device, errors);
+};
+
+std::string VkJsonImageFormatPropertiesToJson(
+    const VkImageFormatProperties& properties) {
+  return VkTypeToJson(properties);
+}
+
+bool VkJsonImageFormatPropertiesFromJson(const std::string& json,
+                                         VkImageFormatProperties* properties,
+                                         std::string* errors) {
+  return VkTypeFromJson(json, properties, errors);
+};
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
new file mode 100644
index 0000000..5e8428a
--- /dev/null
+++ b/vulkan/vkjson/vkjson.h
@@ -0,0 +1,162 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// 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 VKJSON_H_
+#define VKJSON_H_
+
+#include <vulkan/vulkan.h>
+#include <string.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#ifdef WIN32
+#undef min
+#undef max
+#endif
+
+#ifndef VK_API_VERSION_1_0
+#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
+#endif
+
+#ifndef VK_API_VERSION_1_1
+#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)
+#endif
+
+struct VkJsonLayer {
+  VkLayerProperties properties;
+  std::vector<VkExtensionProperties> extensions;
+};
+
+struct VkJsonExtVariablePointerFeatures {
+  VkJsonExtVariablePointerFeatures() {
+    memset(&variable_pointer_features_khr, 0,
+           sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
+  }
+  VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
+};
+
+struct VkJsonDevice {
+  VkJsonDevice() {
+    memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
+    memset(&features, 0, sizeof(VkPhysicalDeviceFeatures));
+    memset(&memory, 0, sizeof(VkPhysicalDeviceMemoryProperties));
+    memset(&subgroup_properties, 0, sizeof(VkPhysicalDeviceSubgroupProperties));
+    memset(&point_clipping_properties, 0,
+           sizeof(VkPhysicalDevicePointClippingProperties));
+    memset(&multiview_properties, 0,
+           sizeof(VkPhysicalDeviceMultiviewProperties));
+    memset(&id_properties, 0, sizeof(VkPhysicalDeviceIDProperties));
+    memset(&maintenance3_properties, 0,
+           sizeof(VkPhysicalDeviceMaintenance3Properties));
+    memset(&bit16_storage_features, 0,
+           sizeof(VkPhysicalDevice16BitStorageFeatures));
+    memset(&multiview_features, 0, sizeof(VkPhysicalDeviceMultiviewFeatures));
+    memset(&variable_pointer_features, 0,
+           sizeof(VkPhysicalDeviceVariablePointerFeatures));
+    memset(&protected_memory_features, 0,
+           sizeof(VkPhysicalDeviceProtectedMemoryFeatures));
+    memset(&sampler_ycbcr_conversion_features, 0,
+           sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
+    memset(&shader_draw_parameter_features, 0,
+           sizeof(VkPhysicalDeviceShaderDrawParameterFeatures));
+  }
+  VkPhysicalDeviceProperties properties;
+  VkPhysicalDeviceFeatures features;
+  VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
+  VkPhysicalDeviceMemoryProperties memory;
+  std::vector<VkQueueFamilyProperties> queues;
+  std::vector<VkExtensionProperties> extensions;
+  std::vector<VkLayerProperties> layers;
+  std::map<VkFormat, VkFormatProperties> formats;
+  VkPhysicalDeviceSubgroupProperties subgroup_properties;
+  VkPhysicalDevicePointClippingProperties point_clipping_properties;
+  VkPhysicalDeviceMultiviewProperties multiview_properties;
+  VkPhysicalDeviceIDProperties id_properties;
+  VkPhysicalDeviceMaintenance3Properties maintenance3_properties;
+  VkPhysicalDevice16BitStorageFeatures bit16_storage_features;
+  VkPhysicalDeviceMultiviewFeatures multiview_features;
+  VkPhysicalDeviceVariablePointerFeatures variable_pointer_features;
+  VkPhysicalDeviceProtectedMemoryFeatures protected_memory_features;
+  VkPhysicalDeviceSamplerYcbcrConversionFeatures
+      sampler_ycbcr_conversion_features;
+  VkPhysicalDeviceShaderDrawParameterFeatures shader_draw_parameter_features;
+  std::map<VkExternalFenceHandleTypeFlagBits, VkExternalFenceProperties>
+      external_fence_properties;
+  std::map<VkExternalSemaphoreHandleTypeFlagBits, VkExternalSemaphoreProperties>
+      external_semaphore_properties;
+};
+
+struct VkJsonDeviceGroup {
+  VkJsonDeviceGroup() {
+    memset(&properties, 0, sizeof(VkPhysicalDeviceGroupProperties));
+  }
+  VkPhysicalDeviceGroupProperties properties;
+  std::vector<uint32_t> device_inds;
+};
+
+struct VkJsonInstance {
+  VkJsonInstance() : api_version(0) {}
+  uint32_t api_version;
+  std::vector<VkJsonLayer> layers;
+  std::vector<VkExtensionProperties> extensions;
+  std::vector<VkJsonDevice> devices;
+  std::vector<VkJsonDeviceGroup> device_groups;
+};
+
+VkJsonInstance VkJsonGetInstance();
+std::string VkJsonInstanceToJson(const VkJsonInstance& instance);
+bool VkJsonInstanceFromJson(const std::string& json,
+                            VkJsonInstance* instance,
+                            std::string* errors);
+
+VkJsonDevice VkJsonGetDevice(VkInstance instance,
+                             VkPhysicalDevice device,
+                             uint32_t instanceExtensionCount,
+                             const char* const* instanceExtensions);
+std::string VkJsonDeviceToJson(const VkJsonDevice& device);
+bool VkJsonDeviceFromJson(const std::string& json,
+                          VkJsonDevice* device,
+                          std::string* errors);
+
+std::string VkJsonImageFormatPropertiesToJson(
+    const VkImageFormatProperties& properties);
+bool VkJsonImageFormatPropertiesFromJson(const std::string& json,
+                                         VkImageFormatProperties* properties,
+                                         std::string* errors);
+
+// Backward-compatibility aliases
+typedef VkJsonDevice VkJsonAllProperties;
+inline VkJsonAllProperties VkJsonGetAllProperties(
+    VkPhysicalDevice physicalDevice) {
+  return VkJsonGetDevice(VK_NULL_HANDLE, physicalDevice, 0, nullptr);
+}
+inline std::string VkJsonAllPropertiesToJson(
+    const VkJsonAllProperties& properties) {
+  return VkJsonDeviceToJson(properties);
+}
+inline bool VkJsonAllPropertiesFromJson(const std::string& json,
+                                        VkJsonAllProperties* properties,
+                                        std::string* errors) {
+  return VkJsonDeviceFromJson(json, properties, errors);
+}
+
+#endif  // VKJSON_H_
diff --git a/vulkan/vkjson/vkjson_info.cc b/vulkan/vkjson/vkjson_info.cc
new file mode 100644
index 0000000..3c4b08b
--- /dev/null
+++ b/vulkan/vkjson/vkjson_info.cc
@@ -0,0 +1,184 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// 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 VK_PROTOTYPES
+#define VK_PROTOTYPES
+#endif
+
+#include "vkjson.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+#include <vector>
+
+const uint32_t unsignedNegOne = (uint32_t)(-1);
+
+struct Options {
+  bool instance = false;
+  uint32_t device_index = unsignedNegOne;
+  std::string device_name;
+  std::string output_file;
+};
+
+bool ParseOptions(int argc, char* argv[], Options* options) {
+  for (int i = 1; i < argc; ++i) {
+    std::string arg(argv[i]);
+    if (arg == "--instance" || arg == "-i") {
+      options->instance = true;
+    } else if (arg == "--first" || arg == "-f") {
+      options->device_index = 0;
+    } else {
+      ++i;
+      if (i >= argc) {
+        std::cerr << "Missing parameter after: " << arg << std::endl;
+        return false;
+      }
+      std::string arg2(argv[i]);
+      if (arg == "--device-index" || arg == "-d") {
+        int result = sscanf(arg2.c_str(), "%u", &options->device_index);
+        if (result != 1) {
+          options->device_index = static_cast<uint32_t>(-1);
+          std::cerr << "Unable to parse index: " << arg2 << std::endl;
+          return false;
+        }
+      } else if (arg == "--device-name" || arg == "-n") {
+        options->device_name = arg2;
+      } else if (arg == "--output" || arg == "-o") {
+        options->output_file = arg2;
+      } else {
+        std::cerr << "Unknown argument: " << arg << std::endl;
+        return false;
+      }
+    }
+  }
+  if (options->instance && (options->device_index != unsignedNegOne ||
+                            !options->device_name.empty())) {
+    std::cerr << "Specifying a specific device is incompatible with dumping "
+                 "the whole instance." << std::endl;
+    return false;
+  }
+  if (options->device_index != unsignedNegOne && !options->device_name.empty()) {
+    std::cerr << "Must specify only one of device index and device name."
+              << std::endl;
+    return false;
+  }
+  if (options->instance && options->output_file.empty()) {
+    std::cerr << "Must specify an output file when dumping the whole instance."
+              << std::endl;
+    return false;
+  }
+  if (!options->output_file.empty() && !options->instance &&
+      options->device_index == unsignedNegOne && options->device_name.empty()) {
+    std::cerr << "Must specify instance, device index, or device name when "
+                 "specifying "
+                 "output file." << std::endl;
+    return false;
+  }
+  return true;
+}
+
+bool Dump(const VkJsonInstance& instance, const Options& options) {
+  const VkJsonDevice* out_device = nullptr;
+  if (options.device_index != unsignedNegOne) {
+    if (static_cast<uint32_t>(options.device_index) >=
+        instance.devices.size()) {
+      std::cerr << "Error: device " << options.device_index
+                << " requested but only " << instance.devices.size()
+                << " devices found." << std::endl;
+      return false;
+    }
+    out_device = &instance.devices[options.device_index];
+  } else if (!options.device_name.empty()) {
+    for (const auto& device : instance.devices) {
+      if (device.properties.deviceName == options.device_name) {
+        out_device = &device;
+      }
+    }
+    if (!out_device) {
+      std::cerr << "Error: device '" << options.device_name
+                << "' requested but not found." << std::endl;
+      return false;
+    }
+  }
+
+  std::string output_file;
+  if (options.output_file.empty()) {
+    assert(out_device);
+#if defined(ANDROID)
+    output_file.assign("/sdcard/Android/" + std::string(out_device->properties.deviceName));
+#else
+    output_file.assign(out_device->properties.deviceName);
+#endif
+    output_file.append(".json");
+  } else {
+    output_file = options.output_file;
+  }
+  FILE* file = nullptr;
+  if (output_file == "-") {
+    file = stdout;
+  } else {
+    file = fopen(output_file.c_str(), "w");
+    if (!file) {
+      std::cerr << "Unable to open file " << output_file << "." << std::endl;
+      return false;
+    }
+  }
+
+  std::string json = out_device ? VkJsonDeviceToJson(*out_device)
+                                : VkJsonInstanceToJson(instance);
+  fwrite(json.data(), 1, json.size(), file);
+  fputc('\n', file);
+
+  if (output_file != "-") {
+    fclose(file);
+    std::cout << "Wrote file " << output_file;
+    if (out_device)
+      std::cout << " for device " << out_device->properties.deviceName;
+    std::cout << "." << std::endl;
+  }
+  return true;
+}
+
+int main(int argc, char* argv[]) {
+#if defined(ANDROID)
+  int vulkanSupport = InitVulkan();
+  if (vulkanSupport == 0)
+    return 1;
+#endif
+  Options options;
+  if (!ParseOptions(argc, argv, &options))
+    return 1;
+
+  VkJsonInstance instance = VkJsonGetInstance();
+  if (options.instance || options.device_index != unsignedNegOne ||
+      !options.device_name.empty()) {
+    Dump(instance, options);
+  } else {
+    for (uint32_t i = 0, n = static_cast<uint32_t>(instance.devices.size()); i < n; i++) {
+      options.device_index = i;
+      Dump(instance, options);
+    }
+  }
+
+  return 0;
+}
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
new file mode 100644
index 0000000..db0450d
--- /dev/null
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -0,0 +1,417 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// 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 VK_PROTOTYPES
+#define VK_PROTOTYPES
+#endif
+
+#include "vkjson.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace {
+const char* kSupportedInstanceExtensions[] = {
+    "VK_KHR_get_physical_device_properties2"};
+
+bool EnumerateExtensions(const char* layer_name,
+                         std::vector<VkExtensionProperties>* extensions) {
+  VkResult result;
+  uint32_t count = 0;
+  result = vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
+  if (result != VK_SUCCESS)
+    return false;
+  extensions->resize(count);
+  result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
+                                                  extensions->data());
+  if (result != VK_SUCCESS)
+    return false;
+  return true;
+}
+
+bool HasExtension(const char* extension_name,
+                  uint32_t count,
+                  const char* const* extensions) {
+  return std::find_if(extensions, extensions + count,
+                      [extension_name](const char* extension) {
+                        return strcmp(extension, extension_name) == 0;
+                      }) != extensions + count;
+}
+
+bool HasExtension(const char* extension_name,
+                  const std::vector<VkExtensionProperties>& extensions) {
+  return std::find_if(extensions.cbegin(), extensions.cend(),
+                      [extension_name](const VkExtensionProperties& extension) {
+                        return strcmp(extension.extensionName,
+                                      extension_name) == 0;
+                      }) != extensions.cend();
+}
+}  // anonymous namespace
+
+VkJsonDevice VkJsonGetDevice(VkInstance instance,
+                             VkPhysicalDevice physical_device,
+                             uint32_t instance_extension_count,
+                             const char* const* instance_extensions) {
+  VkJsonDevice device;
+
+  PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
+      nullptr;
+  if (instance != VK_NULL_HANDLE &&
+      HasExtension("VK_KHR_get_physical_device_properties2",
+                   instance_extension_count, instance_extensions)) {
+    vkpGetPhysicalDeviceFeatures2KHR =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
+  }
+
+  uint32_t extension_count = 0;
+  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
+                                       &extension_count, nullptr);
+  if (extension_count > 0) {
+    device.extensions.resize(extension_count);
+    vkEnumerateDeviceExtensionProperties(
+        physical_device, nullptr, &extension_count, device.extensions.data());
+  }
+
+  uint32_t layer_count = 0;
+  vkEnumerateDeviceLayerProperties(physical_device, &layer_count, nullptr);
+  if (layer_count > 0) {
+    device.layers.resize(layer_count);
+    vkEnumerateDeviceLayerProperties(physical_device, &layer_count,
+                                     device.layers.data());
+  }
+
+  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
+  if (HasExtension("VK_KHR_get_physical_device_properties2",
+                   instance_extension_count, instance_extensions)) {
+    VkPhysicalDeviceFeatures2KHR features = {
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
+        nullptr,
+        {}  // features
+    };
+    if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+      device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
+      device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
+          features.pNext;
+      features.pNext =
+          &device.ext_variable_pointer_features.variable_pointer_features_khr;
+    }
+    vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
+    device.features = features.features;
+  } else {
+    vkGetPhysicalDeviceFeatures(physical_device, &device.features);
+  }
+  vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);
+
+  uint32_t queue_family_count = 0;
+  vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
+                                           nullptr);
+  if (queue_family_count > 0) {
+    device.queues.resize(queue_family_count);
+    vkGetPhysicalDeviceQueueFamilyProperties(
+        physical_device, &queue_family_count, device.queues.data());
+  }
+
+  VkFormatProperties format_properties = {};
+  for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
+       format <= VK_FORMAT_END_RANGE;
+       format = static_cast<VkFormat>(format + 1)) {
+    vkGetPhysicalDeviceFormatProperties(physical_device, format,
+                                        &format_properties);
+    if (format_properties.linearTilingFeatures ||
+        format_properties.optimalTilingFeatures ||
+        format_properties.bufferFeatures) {
+      device.formats.insert(std::make_pair(format, format_properties));
+    }
+  }
+
+  if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
+    for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+         format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
+         format = static_cast<VkFormat>(format + 1)) {
+      vkGetPhysicalDeviceFormatProperties(physical_device, format,
+                                          &format_properties);
+      if (format_properties.linearTilingFeatures ||
+          format_properties.optimalTilingFeatures ||
+          format_properties.bufferFeatures) {
+        device.formats.insert(std::make_pair(format, format_properties));
+      }
+    }
+
+    PFN_vkGetPhysicalDeviceProperties2 vkpGetPhysicalDeviceProperties2 =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+    if (vkpGetPhysicalDeviceProperties2) {
+      VkPhysicalDeviceProperties2 properties2 = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
+
+      device.subgroup_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+      device.subgroup_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.subgroup_properties;
+
+      device.point_clipping_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
+      device.point_clipping_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.point_clipping_properties;
+
+      device.multiview_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+      device.multiview_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.multiview_properties;
+
+      device.id_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+      device.id_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.id_properties;
+
+      device.maintenance3_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+      device.maintenance3_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.maintenance3_properties;
+
+      (*vkpGetPhysicalDeviceProperties2)(physical_device, &properties2);
+    }
+
+    PFN_vkGetPhysicalDeviceFeatures2 vkpGetPhysicalDeviceFeatures2 =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+    if (vkpGetPhysicalDeviceFeatures2) {
+      VkPhysicalDeviceFeatures2 features2 = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, nullptr, {}};
+
+      device.bit16_storage_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
+      device.bit16_storage_features.pNext = features2.pNext;
+      features2.pNext = &device.bit16_storage_features;
+
+      device.multiview_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+      device.multiview_features.pNext = features2.pNext;
+      features2.pNext = &device.multiview_features;
+
+      device.variable_pointer_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
+      device.variable_pointer_features.pNext = features2.pNext;
+      features2.pNext = &device.variable_pointer_features;
+
+      device.protected_memory_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+      device.protected_memory_features.pNext = features2.pNext;
+      features2.pNext = &device.protected_memory_features;
+
+      device.sampler_ycbcr_conversion_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+      device.sampler_ycbcr_conversion_features.pNext = features2.pNext;
+      features2.pNext = &device.sampler_ycbcr_conversion_features;
+
+      device.shader_draw_parameter_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
+      device.shader_draw_parameter_features.pNext = features2.pNext;
+      features2.pNext = &device.shader_draw_parameter_features;
+
+      (*vkpGetPhysicalDeviceFeatures2)(physical_device, &features2);
+    }
+
+    PFN_vkGetPhysicalDeviceExternalFenceProperties
+        vkpGetPhysicalDeviceExternalFenceProperties =
+            reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+                vkGetInstanceProcAddr(
+                    instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+    if (vkpGetPhysicalDeviceExternalFenceProperties) {
+      VkPhysicalDeviceExternalFenceInfo external_fence_info = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr,
+          VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT};
+      VkExternalFenceProperties external_fence_properties = {};
+
+      for (VkExternalFenceHandleTypeFlagBits handle_type =
+               VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT;
+           handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+           handle_type = static_cast<VkExternalFenceHandleTypeFlagBits>(
+               handle_type << 1)) {
+        external_fence_info.handleType = handle_type;
+        (*vkpGetPhysicalDeviceExternalFenceProperties)(
+            physical_device, &external_fence_info, &external_fence_properties);
+        if (external_fence_properties.exportFromImportedHandleTypes ||
+            external_fence_properties.compatibleHandleTypes ||
+            external_fence_properties.externalFenceFeatures) {
+          device.external_fence_properties.insert(
+              std::make_pair(handle_type, external_fence_properties));
+        }
+      }
+    }
+
+    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties
+        vkpGetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<
+            PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+            vkGetInstanceProcAddr(
+                instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+    if (vkpGetPhysicalDeviceExternalSemaphoreProperties) {
+      VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr,
+          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT};
+      VkExternalSemaphoreProperties external_semaphore_properties = {};
+
+      for (VkExternalSemaphoreHandleTypeFlagBits handle_type =
+               VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
+           handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+           handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>(
+               handle_type << 1)) {
+        external_semaphore_info.handleType = handle_type;
+        (*vkpGetPhysicalDeviceExternalSemaphoreProperties)(
+            physical_device, &external_semaphore_info,
+            &external_semaphore_properties);
+        if (external_semaphore_properties.exportFromImportedHandleTypes ||
+            external_semaphore_properties.compatibleHandleTypes ||
+            external_semaphore_properties.externalSemaphoreFeatures) {
+          device.external_semaphore_properties.insert(
+              std::make_pair(handle_type, external_semaphore_properties));
+        }
+      }
+    }
+  }
+
+  return device;
+}
+
+VkJsonInstance VkJsonGetInstance() {
+  VkJsonInstance instance;
+  VkResult result;
+  uint32_t count;
+
+  count = 0;
+  result = vkEnumerateInstanceLayerProperties(&count, nullptr);
+  if (result != VK_SUCCESS)
+    return VkJsonInstance();
+  if (count > 0) {
+    std::vector<VkLayerProperties> layers(count);
+    result = vkEnumerateInstanceLayerProperties(&count, layers.data());
+    if (result != VK_SUCCESS)
+      return VkJsonInstance();
+    instance.layers.reserve(count);
+    for (auto& layer : layers) {
+      instance.layers.push_back(VkJsonLayer{layer, std::vector<VkExtensionProperties>()});
+      if (!EnumerateExtensions(layer.layerName,
+                               &instance.layers.back().extensions))
+        return VkJsonInstance();
+    }
+  }
+
+  if (!EnumerateExtensions(nullptr, &instance.extensions))
+    return VkJsonInstance();
+
+  std::vector<const char*> instance_extensions;
+  for (const auto extension : kSupportedInstanceExtensions) {
+    if (HasExtension(extension, instance.extensions))
+      instance_extensions.push_back(extension);
+  }
+
+  const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
+                                      nullptr,
+                                      "vkjson_info",
+                                      1,
+                                      "",
+                                      0,
+                                      VK_API_VERSION_1_0};
+  VkInstanceCreateInfo instance_info = {
+      VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+      nullptr,
+      0,
+      &app_info,
+      0,
+      nullptr,
+      static_cast<uint32_t>(instance_extensions.size()),
+      instance_extensions.data()};
+  VkInstance vkinstance;
+  result = vkCreateInstance(&instance_info, nullptr, &vkinstance);
+  if (result != VK_SUCCESS)
+    return VkJsonInstance();
+
+  count = 0;
+  result = vkEnumeratePhysicalDevices(vkinstance, &count, nullptr);
+  if (result != VK_SUCCESS) {
+    vkDestroyInstance(vkinstance, nullptr);
+    return VkJsonInstance();
+  }
+
+  std::vector<VkPhysicalDevice> devices(count, VK_NULL_HANDLE);
+  result = vkEnumeratePhysicalDevices(vkinstance, &count, devices.data());
+  if (result != VK_SUCCESS) {
+    vkDestroyInstance(vkinstance, nullptr);
+    return VkJsonInstance();
+  }
+
+  std::map<VkPhysicalDevice, uint32_t> device_map;
+  const uint32_t sz = devices.size();
+  instance.devices.reserve(sz);
+  for (uint32_t i = 0; i < sz; ++i) {
+    device_map.insert(std::make_pair(devices[i], i));
+    instance.devices.emplace_back(VkJsonGetDevice(vkinstance, devices[i],
+                                                  instance_extensions.size(),
+                                                  instance_extensions.data()));
+  }
+
+  PFN_vkEnumerateInstanceVersion vkpEnumerateInstanceVersion =
+      reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
+          vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
+  if (!vkpEnumerateInstanceVersion) {
+    instance.api_version = VK_API_VERSION_1_0;
+  } else {
+    result = (*vkpEnumerateInstanceVersion)(&instance.api_version);
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+  }
+
+  PFN_vkEnumeratePhysicalDeviceGroups vkpEnumeratePhysicalDeviceGroups =
+      reinterpret_cast<PFN_vkEnumeratePhysicalDeviceGroups>(
+          vkGetInstanceProcAddr(vkinstance, "vkEnumeratePhysicalDeviceGroups"));
+  if (vkpEnumeratePhysicalDeviceGroups) {
+    count = 0;
+    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count, nullptr);
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+
+    VkJsonDeviceGroup device_group;
+    std::vector<VkPhysicalDeviceGroupProperties> group_properties;
+    group_properties.resize(count);
+    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count,
+                                                 group_properties.data());
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+    for (auto properties : group_properties) {
+      device_group.properties = properties;
+      for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) {
+        device_group.device_inds.push_back(
+            device_map[properties.physicalDevices[i]]);
+      }
+      instance.device_groups.push_back(device_group);
+    }
+  }
+
+  vkDestroyInstance(vkinstance, nullptr);
+  return instance;
+}
diff --git a/vulkan/vkjson/vkjson_unittest.cc b/vulkan/vkjson/vkjson_unittest.cc
new file mode 100644
index 0000000..de765cd
--- /dev/null
+++ b/vulkan/vkjson/vkjson_unittest.cc
@@ -0,0 +1,101 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////////
+
+#include "vkjson.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <iostream>
+
+#define EXPECT(X) if (!(X)) \
+  ReportFailure(__FILE__, __LINE__, #X);
+
+#define ASSERT(X) if (!(X)) { \
+  ReportFailure(__FILE__, __LINE__, #X); \
+  return 2; \
+}
+
+int g_failures;
+
+void ReportFailure(const char* file, int line, const char* assertion) {
+  std::cout << file << ":" << line << ": \"" << assertion << "\" failed."
+            << std::endl;
+  ++g_failures;
+}
+
+int main(int argc, char* argv[]) {
+  std::string errors;
+  bool result = false;
+
+  VkJsonInstance instance;
+  instance.devices.resize(1);
+  VkJsonDevice& device = instance.devices[0];
+
+  const char name[] = "Test device";
+  memcpy(device.properties.deviceName, name, sizeof(name));
+  device.properties.limits.maxImageDimension1D = 3;
+  device.properties.limits.maxSamplerLodBias = 3.5f;
+  device.properties.limits.bufferImageGranularity = 0x1ffffffffull;
+  device.properties.limits.maxViewportDimensions[0] = 1;
+  device.properties.limits.maxViewportDimensions[1] = 2;
+  VkFormatProperties format_props = {
+      VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,
+      VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
+      VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT};
+  device.formats.insert(std::make_pair(VK_FORMAT_R8_UNORM, format_props));
+  device.formats.insert(std::make_pair(VK_FORMAT_R8G8_UNORM, format_props));
+
+  std::string json = VkJsonInstanceToJson(instance);
+  std::cout << json << std::endl;
+
+  VkJsonInstance instance2;
+  result = VkJsonInstanceFromJson(json, &instance2, &errors);
+  EXPECT(result);
+  if (!result)
+    std::cout << "Error: " << errors << std::endl;
+  const VkJsonDevice& device2 = instance2.devices.at(0);
+
+  EXPECT(!memcmp(&device.properties, &device2.properties,
+                 sizeof(device.properties)));
+  for (auto& kv : device.formats) {
+    auto it = device2.formats.find(kv.first);
+    EXPECT(it != device2.formats.end());
+    EXPECT(!memcmp(&kv.second, &it->second, sizeof(kv.second)));
+  }
+
+  VkImageFormatProperties props = {};
+  json = VkJsonImageFormatPropertiesToJson(props);
+  VkImageFormatProperties props2 = {};
+  result = VkJsonImageFormatPropertiesFromJson(json, &props2, &errors);
+  EXPECT(result);
+  if (!result)
+    std::cout << "Error: " << errors << std::endl;
+
+  EXPECT(!memcmp(&props, &props2, sizeof(props)));
+
+  if (g_failures) {
+    std::cout << g_failures << " failures." << std::endl;
+    return 1;
+  } else {
+    std::cout << "Success." << std::endl;
+    return 0;
+  }
+}