Merge "SF: Use getVisibleLayers... in doComposeSurfaces"
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
new file mode 100644
index 0000000..79f666b
--- /dev/null
+++ b/include/android/system_fonts.h
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file system_fonts.h
+ * @brief Provides the system font configurations.
+ *
+ * These APIs provides the list of system installed font files with additional metadata about the
+ * font.
+ *
+ * The ASystemFontIterator_open method will give you an iterator which can iterate all system
+ * installed font files as shown in the following example.
+ *
+ * <code>
+ *   ASystemFontIterator* iterator = ASystemFontIterator_open();
+ *   ASystemFont* font = NULL;
+ *
+ *   while ((font = ASystemFontIterator_next(iterator)) != nullptr) {
+ *       // Look if the font is your desired one.
+ *       if (ASystemFont_getWeight(font) == 400 && !ASystemFont_isItalic(font)
+ *           && ASystemFont_getLocale(font) == NULL) {
+ *           break;
+ *       }
+ *       ASystemFont_close(font);
+ *   }
+ *   ASystemFontIterator_close(iterator);
+ *
+ *   int fd = open(ASystemFont_getFontFilePath(font), O_RDONLY);
+ *   int collectionIndex = ASystemFont_getCollectionINdex(font);
+ *   std::vector<std::pair<uint32_t, float>> variationSettings;
+ *   for (size_t i = 0; i < ASystemFont_getAxisCount(font); ++i) {
+ *       variationSettings.push_back(std::make_pair(
+ *           ASystemFont_getAxisTag(font, i),
+ *           ASystemFont_getAxisValue(font, i)));
+ *   }
+ *   ASystemFont_close(font);
+ *
+ *   // Use this font for your text rendering engine.
+ *
+ * </code>
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_SYSTEM_FONTS_H
+#define ANDROID_SYSTEM_FONTS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.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
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+enum {
+    /** The minimum value fot the font weight value. */
+    ASYSTEM_FONT_WEIGHT_MIN = 0,
+
+    /** A font weight value for the thin weight. */
+    ASYSTEM_FONT_WEIGHT_THIN = 100,
+
+    /** A font weight value for the extra-light weight. */
+    ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT = 200,
+
+    /** A font weight value for the light weight. */
+    ASYSTEM_FONT_WEIGHT_LIGHT = 300,
+
+    /** A font weight value for the normal weight. */
+    ASYSTEM_FONT_WEIGHT_NORMAL = 400,
+
+    /** A font weight value for the medium weight. */
+    ASYSTEM_FONT_WEIGHT_MEDIUM = 500,
+
+    /** A font weight value for the semi-bold weight. */
+    ASYSTEM_FONT_WEIGHT_SEMI_BOLD = 600,
+
+    /** A font weight value for the bold weight. */
+    ASYSTEM_FONT_WEIGHT_BOLD = 700,
+
+    /** A font weight value for the extra-bold weight. */
+    ASYSTEM_FONT_WEIGHT_EXTRA_BOLD = 800,
+
+    /** A font weight value for the black weight. */
+    ASYSTEM_FONT_WEIGHT_BLACK = 900,
+
+    /** The maximum value for the font weight value. */
+    ASYSTEM_FONT_WEIGHT_MAX = 1000
+};
+
+/**
+ * ASystemFontIterator provides access to the system font configuration.
+ *
+ * ASystemFontIterator is an iterator for all available system font settings.
+ * This iterator is not a thread-safe object. Do not pass this iterator to other threads.
+ */
+struct ASystemFontIterator;
+
+/**
+ * ASystemFont provides information of the single system font configuration.
+ */
+struct ASystemFont;
+
+/**
+ * Create a system font iterator.
+ *
+ * Use ASystemFont_close() to close the iterator.
+ *
+ * \return a pointer for a newly allocated iterator, nullptr on failure.
+ */
+ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
+
+/**
+ * Close an opened system font iterator, freeing any related resources.
+ *
+ * \param a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
+ */
+void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
+
+/**
+ * Move to the next system font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if more system fonts are available, otherwise false.
+ */
+ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
+
+/**
+ * Close an ASystemFont returned by ASystemFontIterator_next.
+ *
+ * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ */
+void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an absolute path to the current font file.
+ *
+ * Here is a list of font formats returned by this method:
+ * <ul>
+ *   <li>OpenType</li>
+ *   <li>OpenType Font Collection</li>
+ *   <li>TrueType</li>
+ *   <li>TrueType Collection</li>
+ * </ul>
+ * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc.
+ *
+ * The font file returned is guaranteed to be opend with O_RDONLY.
+ * Note that the returned pointer is valid until ASystemFont_close() is called for the given font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a string of the font file path.
+ */
+const char* _Nonnull ASystemFont_getFontFilePath(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a weight value associated with the current font.
+ *
+ * The weight values are positive and less than or equal to 1000.
+ * Here are pairs of the common names and their values.
+ * <p>
+ *  <table>
+ *  <thead>
+ *  <tr>
+ *  <th align="center">Value</th>
+ *  <th align="center">Name</th>
+ *  <th align="center">NDK Definition</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *  <td align="center">100</td>
+ *  <td align="center">Thin</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_THIN}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">200</td>
+ *  <td align="center">Extra Light (Ultra Light)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">300</td>
+ *  <td align="center">Light</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">400</td>
+ *  <td align="center">Normal (Regular)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_NORMAL}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">500</td>
+ *  <td align="center">Medium</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_MEDIUM}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">600</td>
+ *  <td align="center">Semi Bold (Demi Bold)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_SEMI_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">700</td>
+ *  <td align="center">Bold</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">800</td>
+ *  <td align="center">Extra Bold (Ultra Bold)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">900</td>
+ *  <td align="center">Black (Heavy)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_BLACK}</td>
+ *  </tr>
+ *  </tbody>
+ * </p>
+ * Note that the weight value may fall in between above values, e.g. 250 weight.
+ *
+ * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
+ */
+uint16_t ASystemFont_getWeight(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return true if the current font is italic, otherwise returns false.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if italic, otherwise false.
+ */
+bool ASystemFont_isItalic(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a IETF BCP47 compliant language tag associated with the current font.
+ *
+ * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)")
+ *
+ * Note that the returned pointer is valid until ASystemFont_close() is called.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a IETF BCP47 compliant langauge tag or nullptr if not available.
+ */
+const char* _Nullable ASystemFont_getLocale(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a font collection index value associated with the current font.
+ *
+ * In case the target font file is a font collection (e.g. .ttc or .otc), this
+ * returns a non-negative value as an font offset in the collection. This
+ * always returns 0 if the target font file is a regular font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a font collection index.
+ */
+size_t ASystemFont_getCollectionIndex(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a count of font variation settings associated with the current font
+ *
+ * The font variation settings are provided as multiple tag-values pairs.
+ *
+ * For example, bold italic font may have following font variation settings:
+ *     'wght' 700, 'slnt' -12
+ * In this case, ASystemFont_getAxisCount returns 2 and ASystemFont_getAxisTag
+ * and ASystemFont_getAxisValue will return following values.
+ * <code>
+ *     ASystemFont* font = ASystemFontIterator_next(ite);
+ *
+ *     // Returns the number of axes
+ *     ASystemFont_getAxisCount(font);  // Returns 2
+ *
+ *     // Returns the tag-value pair for the first axis.
+ *     ASystemFont_getAxisTag(font, 0);  // Returns 'wght'(0x77676874)
+ *     ASystemFont_getAxisValue(font, 0);  // Returns 700.0
+ *
+ *     // Returns the tag-value pair for the second axis.
+ *     ASystemFont_getAxisTag(font, 1);  // Returns 'slnt'(0x736c6e74)
+ *     ASystemFont_getAxisValue(font, 1);  // Returns -12.0
+ * </code>
+ *
+ * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a number of font variation settings.
+ */
+size_t ASystemFont_getAxisCount(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an OpenType axis tag associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ *        equal to {@link ASystemFont_getAxisCount} is not allowed.
+ * \return an OpenType axis tag value for the given font variation setting.
+ */
+uint32_t ASystemFont_getAxisTag(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+/**
+ * Return an OpenType axis value associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ *         equal to {@link ASYstemFont_getAxisCount} is not allwed.
+ * \return a float value for the given font variation setting.
+ */
+float ASystemFont_getAxisValue(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SYSTEM_FONTS_H
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 76d5a73..e5c68b5 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -24,10 +24,10 @@
     ],
 
     srcs: [
-        "ABinderProcess.cpp",
-        "AIBinder.cpp",
-        "AParcel.cpp",
-        "AServiceManager.cpp",
+        "ibinder.cpp",
+        "parcel.cpp",
+        "process.cpp",
+        "service_manager.cpp",
     ],
 
     shared_libs: [
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/ibinder.cpp
similarity index 99%
rename from libs/binder/ndk/AIBinder.cpp
rename to libs/binder/ndk/ibinder.cpp
index c02a77a..8a1ec05 100644
--- a/libs/binder/ndk/AIBinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -15,10 +15,10 @@
  */
 
 #include <android/binder_ibinder.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <android/binder_status.h>
-#include "AParcel_internal.h"
+#include "parcel_internal.h"
 
 #include <android-base/logging.h>
 
diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/ibinder_internal.h
similarity index 99%
rename from libs/binder/ndk/AIBinder_internal.h
rename to libs/binder/ndk/ibinder_internal.h
index 30009d2..fcf1b0b 100644
--- a/libs/binder/ndk/AIBinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -17,7 +17,7 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <atomic>
 #include <mutex>
diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/parcel.cpp
similarity index 98%
rename from libs/binder/ndk/AParcel.cpp
rename to libs/binder/ndk/parcel.cpp
index f090929..ccdfc7b 100644
--- a/libs/binder/ndk/AParcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <android/binder_parcel.h>
-#include "AParcel_internal.h"
+#include "parcel_internal.h"
 
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <binder/Parcel.h>
 
diff --git a/libs/binder/ndk/AParcel_internal.h b/libs/binder/ndk/parcel_internal.h
similarity index 98%
rename from libs/binder/ndk/AParcel_internal.h
rename to libs/binder/ndk/parcel_internal.h
index 9f30a2f..b6a9110 100644
--- a/libs/binder/ndk/AParcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -21,7 +21,7 @@
 #include <sys/cdefs.h>
 
 #include <binder/Parcel.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 struct AParcel {
     const ::android::Parcel* operator->() const { return mParcel; }
diff --git a/libs/binder/ndk/ABinderProcess.cpp b/libs/binder/ndk/process.cpp
similarity index 100%
rename from libs/binder/ndk/ABinderProcess.cpp
rename to libs/binder/ndk/process.cpp
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 5c0b936..794afe2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -81,7 +81,7 @@
         source += "}\n\n"
 
     replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header)
-    replaceFileTags(ROOT + "AParcel.cpp", source)
+    replaceFileTags(ROOT + "parcel.cpp", source)
 
     print("Updating DONE.")
 
diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/service_manager.cpp
similarity index 97%
rename from libs/binder/ndk/AServiceManager.cpp
rename to libs/binder/ndk/service_manager.cpp
index 90dd1c8..5bc69b0 100644
--- a/libs/binder/ndk/AServiceManager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <android/binder_manager.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <binder/IServiceManager.h>
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 1f2c517..a296d20 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -440,6 +440,9 @@
 Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
     uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
     uint64_t usage, size_t buffer_count) {
+  if (buffer_count == 0) {
+    return {};
+  }
   if (capacity() + buffer_count > kMaxQueueCapacity) {
     ALOGE(
         "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
@@ -481,10 +484,13 @@
     }
   }
 
-  if (buffer_slots.size() == 0) {
-    // Error out if no buffer is allocated and improted.
-    ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
-    ErrorStatus(ENOMEM);
+  if (buffer_slots.size() != buffer_count) {
+    // Error out if the count of allocated/imported buffer(s) is not correct.
+    ALOGE(
+        "ProducerQueue::AllocateBuffers: requested to import %zu "
+        "buffers, but actually imported %zu buffers.",
+        buffer_count, buffer_slots.size());
+    return ErrorStatus(ENOMEM);
   }
 
   return {std::move(buffer_slots)};
@@ -502,12 +508,6 @@
           status.GetErrorMessage().c_str());
     return status.error_status();
   }
-
-  if (status.get().size() == 0) {
-    ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
-    ErrorStatus(ENOMEM);
-  }
-
   return {status.get()[0]};
 }
 
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 2975f56..c1f322c 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -562,6 +562,28 @@
   ASSERT_EQ(cs2, ps2);
 }
 
+TEST_F(BufferHubQueueTest, TestAllocateTwoBuffers) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+  ASSERT_EQ(producer_queue_->capacity(), 0);
+
+  auto status = producer_queue_->AllocateBuffers(
+      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+      kBufferUsage, 2);
+  ASSERT_TRUE(status.ok());
+  ASSERT_EQ(producer_queue_->capacity(), 2);
+}
+
+TEST_F(BufferHubQueueTest, TestAllocateZeroBuffers) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+  ASSERT_EQ(producer_queue_->capacity(), 0);
+
+  auto status = producer_queue_->AllocateBuffers(
+      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+      kBufferUsage, 0);
+  ASSERT_TRUE(status.ok());
+  ASSERT_EQ(producer_queue_->capacity(), 0);
+}
+
 TEST_F(BufferHubQueueTest, TestUsageSetMask) {
   const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
   ASSERT_TRUE(
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 23201aa..3845b22 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -591,6 +591,9 @@
 
     friend class impl::SurfaceInterceptor;
 
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+
     void commitTransaction(const State& stateToCommit);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index a8bdec4..2722b01 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -87,6 +87,9 @@
     friend class ColorLayer;
     friend class SurfaceFlinger;
 
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+
     LayerBE(Layer* layer, std::string layerName);
     explicit LayerBE(const LayerBE& layer);
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f1f0fbf..6fe52d3 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Android Open Source Project
+// 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.
@@ -16,8 +16,15 @@
     name: "libsurfaceflinger_unittest",
     defaults: ["libsurfaceflinger_defaults"],
     test_suites: ["device-tests"],
+    sanitize: {
+        // Using the address sanitizer not only helps uncover issues in the code
+        // covered by the tests, but also covers some of the tricky injection of
+        // fakes the unit tests currently do.
+        address: true,
+    },
     srcs: [
         ":libsurfaceflinger_sources",
+        "CompositionTest.cpp",
         "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
new file mode 100644
index 0000000..5aa6e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -0,0 +1,1275 @@
+/*
+ * 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 "CompositionTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/IProducerListener.h>
+#include <log/log.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+#include "BufferQueueLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/RenderEngine/MockRenderEngine.h"
+
+namespace android {
+namespace {
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::IsNull;
+using testing::Mock;
+using testing::NotNull;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+
+using android::Hwc2::Error;
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+using android::Hwc2::Transform;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+constexpr int DEFAULT_CONFIG_ID = 0;
+constexpr int DEFAULT_TEXTURE_ID = 6000;
+constexpr int DEFAULT_LAYER_STACK = 7000;
+
+constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
+
+constexpr int DEFAULT_SIDEBAND_STREAM = 51;
+
+class CompositionTest : public testing::Test {
+public:
+    CompositionTest() {
+        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());
+
+        mFlinger.mutableEventControlThread().reset(mEventControlThread);
+        mFlinger.mutableEventThread().reset(mEventThread);
+        mFlinger.mutableEventQueue().reset(mMessageQueue);
+
+        mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
+        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+        mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+        setupComposer(0);
+    }
+
+    ~CompositionTest() {
+        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 setupComposer(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 setupForceGeometryDirty() {
+        // TODO: This requires the visible region and other related
+        // state to be set, and is problematic for BufferLayers since they are
+        // not visible without a buffer (and setting up a buffer looks like a
+        // pain)
+        // mFlinger.mutableVisibleRegionsDirty() = true;
+
+        mFlinger.mutableGeometryInvalid() = true;
+    }
+
+    template <typename Case>
+    void displayRefreshCompositionDirtyGeometry();
+
+    template <typename Case>
+    void displayRefreshCompositionDirtyFrame();
+
+    template <typename Case>
+    void captureScreenComposition();
+
+    std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+
+    TestableSurfaceFlinger mFlinger;
+    sp<DisplayDevice> mDisplay;
+    sp<DisplayDevice> mExternalDisplay;
+    sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+    renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+
+    mock::EventThread* mEventThread = new mock::EventThread();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    Hwc2::mock::Composer* mComposer = nullptr;
+    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+    renderengine::mock::Image* mReImage = new renderengine::mock::Image();
+    renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
+
+    sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
+
+    sp<GraphicBuffer> mCaptureScreenBuffer;
+};
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyGeometry() {
+    setupForceGeometryDirty();
+    LayerCase::setupForDirtyGeometry(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+    LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyFrame() {
+    LayerCase::setupForDirtyFrame(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+    LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::captureScreenComposition() {
+    LayerCase::setupForScreenCapture(this);
+
+    const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+    constexpr int32_t minLayerZ = -1;
+    constexpr int32_t maxLayerZ = 1000;
+    constexpr bool useIdentityTransform = true;
+    constexpr bool forSystem = true;
+
+    DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
+                                 DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+
+    auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
+        return mFlinger.traverseLayersInDisplay(mDisplay, minLayerZ, maxLayerZ, visitor);
+    };
+
+    // TODO: Eliminate expensive/real allocation if possible.
+    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+                                             HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+
+    int fd = -1;
+    status_t result =
+            mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+                                             useIdentityTransform, forSystem, &fd);
+    if (fd >= 0) {
+        close(fd);
+    }
+
+    EXPECT_EQ(NO_ERROR, result);
+
+    LayerCase::cleanup(this);
+}
+
+/* ------------------------------------------------------------------------
+ * Variants for each display configuration which can be tested
+ */
+
+template <typename Derived>
+struct BaseDisplayVariant {
+    static constexpr bool IS_SECURE = true;
+    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+
+    static void setupPreconditions(CompositionTest* test) {
+        FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+                .setCapabilities(&test->mDefaultCapabilities)
+                .inject(&test->mFlinger, test->mComposer);
+
+        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
+                                                   DisplayDevice::DISPLAY_PRIMARY)
+                                 .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+                                 .setDisplaySurface(test->mDisplaySurface)
+                                 .setRenderSurface(std::unique_ptr<renderengine::Surface>(
+                                         test->mRenderSurface))
+                                 .setSecure(Derived::IS_SECURE)
+                                 .setPowerMode(Derived::INIT_POWER_MODE)
+                                 .inject();
+        test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+    }
+
+    template <typename Case>
+    static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+                .Times(1);
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
+        EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+                .WillOnce(Return(true));
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1);
+
+        EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
+        EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
+
+        Case::CompositionType::setupHwcSetCallExpectations(test);
+        Case::CompositionType::setupHwcGetCallExpectations(test);
+    }
+
+    template <typename Case>
+    static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
+        // Called once with a non-null value to set a framebuffer, and then
+        // again with nullptr to clear it.
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+        EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+                .WillOnce(Return(
+                        ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+        EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
+        EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+                .Times(1);
+        // This expectation retires on saturation as setViewportAndProjection is
+        // called an extra time for the code path this setup is for.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1)
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+    }
+
+    static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, beginFrame(true)).Times(1);
+    }
+
+    static void setupEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, beginFrame(false)).Times(1);
+    }
+
+    static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+                .Times(1);
+        EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+                .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+
+        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupColorTransform(_)).Times(2);
+        // These expectations retire on saturation as the code path these
+        // expectations are for appears to make an extra call to them.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1)
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+                .WillOnce(Return(true))
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+    }
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupRECompositionCallExpectations(test);
+    }
+
+    template <typename Case>
+    static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupREScreenshotCompositionCallExpectations(test);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+    }
+};
+
+struct DefaultDisplaySetupVariant : public BaseDisplayVariant<DefaultDisplaySetupVariant> {};
+
+struct InsecureDisplaySetupVariant : public BaseDisplayVariant<InsecureDisplaySetupVariant> {
+    static constexpr bool IS_SECURE = false;
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupInsecureRECompositionCallExpectations(test);
+
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    template <typename Case>
+    static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+    }
+};
+
+struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
+    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+
+    template <typename Case>
+    static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+        // TODO: This seems like an unnecessary call if display is powered off.
+        EXPECT_CALL(*test->mComposer,
+                    setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+                .Times(1);
+
+        // TODO: This seems like an unnecessary call if display is powered off.
+        Case::CompositionType::setupHwcSetCallExpectations(test);
+    }
+
+    static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        // TODO: This seems like an unnecessary call if display is powered off.
+        EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+                .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+    }
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest*) {}
+};
+
+/* ------------------------------------------------------------------------
+ * Variants for each layer configuration which can be tested
+ */
+
+template <typename LayerProperties>
+struct BaseLayerProperties {
+    static constexpr uint32_t WIDTH = 100;
+    static constexpr uint32_t HEIGHT = 100;
+    static constexpr PixelFormat FORMAT = PIXEL_FORMAT_RGBA_8888;
+    static constexpr uint64_t USAGE =
+            GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_SW_WRITE_NEVER;
+    static constexpr android_dataspace DATASPACE = HAL_DATASPACE_UNKNOWN;
+    static constexpr uint32_t SCALING_MODE = 0;
+    static constexpr uint32_t TRANSFORM = 0;
+    static constexpr uint32_t LAYER_FLAGS = 0;
+    static constexpr float COLOR[] = {1.f, 1.f, 1.f, 1.f};
+    static constexpr IComposerClient::BlendMode BLENDMODE =
+            IComposerClient::BlendMode::PREMULTIPLIED;
+
+    static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) {
+        auto producer = layer->getProducer();
+
+        IGraphicBufferProducer::QueueBufferOutput qbo;
+        status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to connect() (%d)", result);
+            return;
+        }
+
+        int slot;
+        sp<Fence> fence;
+        result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH,
+                                         LayerProperties::HEIGHT, LayerProperties::FORMAT,
+                                         LayerProperties::USAGE, nullptr, nullptr);
+        if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            ALOGE("Failed to dequeueBuffer() (%d)", result);
+            return;
+        }
+
+        sp<GraphicBuffer> buffer;
+        result = producer->requestBuffer(slot, &buffer);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to requestBuffer() (%d)", result);
+            return;
+        }
+
+        IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */,
+                                                     LayerProperties::DATASPACE,
+                                                     Rect(LayerProperties::WIDTH,
+                                                          LayerProperties::HEIGHT),
+                                                     LayerProperties::SCALING_MODE,
+                                                     LayerProperties::TRANSFORM, Fence::NO_FENCE);
+        result = producer->queueBuffer(slot, qbi, &qbo);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to queueBuffer (%d)", result);
+            return;
+        }
+    }
+
+    static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        // TODO: Eliminate the complexity of actually creating a buffer
+        EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
+        EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
+        status_t err =
+                layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                                  LayerProperties::FORMAT);
+        ASSERT_EQ(NO_ERROR, err);
+        Mock::VerifyAndClear(test->mRenderEngine);
+
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+        enqueueBuffer(test, layer);
+        Mock::VerifyAndClear(test->mMessageQueue);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, createImage())
+                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).Times(1);
+        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, false)).WillOnce(Return(true));
+        bool ignoredRecomputeVisibleRegions;
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+        Mock::VerifyAndClear(test->mRenderEngine);
+        Mock::VerifyAndClear(test->mReImage);
+    }
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        setupLatchedBuffer(test, layer);
+    }
+
+    static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
+        // BufferLayer::onPostComposition(), when there is no present fence
+        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
+                .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
+    }
+
+    static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer,
+                    setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+                .Times(1);
+        // TODO: Coverage of other values for origin
+        EXPECT_CALL(*test->mComposer,
+                    setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+                                         IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+                                                                LayerProperties::HEIGHT})))
+                .Times(1);
+        EXPECT_CALL(*test->mComposer,
+                    setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+                .Times(1);
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+
+        // These expectations retire on saturation as the code path these
+        // expectations are for appears to make an extra call to them.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+                .Times(1)
+                .RetiresOnSaturation();
+    }
+
+    static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+                                                               LayerProperties::HEIGHT})))
+                .Times(1);
+    }
+
+    static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+                                          std::vector<IComposerClient::Rect>({IComposerClient::Rect(
+                                                  {0, 0, LayerProperties::WIDTH,
+                                                   LayerProperties::HEIGHT})})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+
+        // TODO: use COLOR
+        EXPECT_CALL(*test->mComposer,
+                    setLayerColor(HWC_DISPLAY, HWC_LAYER,
+                                  IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+                .Times(1);
+
+        // TODO: ColorLayer::onPreComposition() always returns true, triggering an
+        // extra layer update in SurfaceFlinger::preComposition(). This seems
+        // wrong on the surface.
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+    }
+
+    static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+
+        setupBufferLayerPostFrameCallExpectations(test);
+    }
+
+    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, false,
+                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+                .Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+        // This call retires on saturation as the code that renders a texture disables the state,
+        // along with a top-level disable to ensure it is disabled for non-buffer layers.
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+    }
+
+    static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+
+        // TODO - Investigate and eliminate these differences between display
+        // composition and screenshot composition.
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+        setupREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+    }
+
+    static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+    }
+
+    static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupREColorCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, true,
+                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+    }
+
+    static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
+        setupREColorCompositionCallExpectations(test);
+    }
+};
+
+struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
+
+struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+
+struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
+    using Base = BaseLayerProperties<SidebandLayerProperties>;
+    static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        sp<NativeHandle> stream =
+                NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+                                     false);
+        test->mFlinger.setLayerSidebandStream(layer, stream);
+    }
+
+    static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, -1.f, -1.f})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSidebandStream(HWC_DISPLAY, HWC_LAYER,
+                                           reinterpret_cast<native_handle_t*>(
+                                                   DEFAULT_SIDEBAND_STREAM)))
+                .WillOnce(Return(Error::NONE));
+
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+    }
+
+    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+    }
+};
+
+struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
+    using Base = BaseLayerProperties<SecureLayerProperties>;
+
+    static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
+
+    static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, false,
+                                       half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
+                                             Base::COLOR[3])))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+        // This call retires on saturation as the code that renders a texture disables the state,
+        // along with a top-level disable to ensure it is disabled for non-buffer layers.
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+    }
+
+    static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+        setupInsecureREBufferCompositionCommonCallExpectations(test);
+        Base::setupBufferLayerPostFrameCallExpectations(test);
+    }
+
+    static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        setupInsecureREBufferCompositionCommonCallExpectations(test);
+    }
+};
+
+struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> {
+    using Base = BaseLayerProperties<CursorLayerProperties>;
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        Base::setupLayerState(test, layer);
+        test->mFlinger.setLayerPotentialCursor(layer, true);
+    }
+};
+
+struct NoLayerVariant {
+    using FlingerLayerType = sp<BufferQueueLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); }
+    static void injectLayer(CompositionTest*, FlingerLayerType) {}
+    static void cleanupInjectedLayers(CompositionTest*) {}
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+template <typename LayerProperties>
+struct BaseLayerVariant {
+    template <typename L, typename F>
+    static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+
+        sp<L> layer = factory();
+
+        Mock::VerifyAndClear(test->mComposer);
+        Mock::VerifyAndClear(test->mRenderEngine);
+        Mock::VerifyAndClear(test->mMessageQueue);
+
+        auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+        layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+        layerDrawingState.active.w = 100;
+        layerDrawingState.active.h = 100;
+        layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                        LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
+
+        layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+
+        return layer;
+    }
+
+    static void injectLayer(CompositionTest* test, sp<Layer> layer) {
+        EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
+                .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
+
+        layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+
+        Mock::VerifyAndClear(test->mComposer);
+
+        Vector<sp<Layer>> layers;
+        layers.add(layer);
+        test->mDisplay->setVisibleLayersSortedByZ(layers);
+        test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+    }
+
+    static void cleanupInjectedLayers(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
+                .WillOnce(Return(Error::NONE));
+        for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
+            layer->destroyHwcLayer(test->mDisplay->getId());
+        }
+        test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+    }
+};
+
+template <typename LayerProperties>
+struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+    using Base = BaseLayerVariant<LayerProperties>;
+    using FlingerLayerType = sp<ColorLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest* test) {
+        FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
+            return new ColorLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+                                  String8("test-layer"), LayerProperties::WIDTH,
+                                  LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS);
+        });
+        return layer;
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREColorCompositionCommonCallExpectations(test);
+        LayerProperties::setupREColorCompositionCallExpectations(test);
+    }
+
+    static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREColorScreenshotCompositionCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        LayerProperties::setupHwcSetGeometryCallExpectations(test);
+        LayerProperties::setupHwcSetSourceCropColorCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+        LayerProperties::setupHwcSetPerFrameColorCallExpectations(test);
+    }
+};
+
+template <typename LayerProperties>
+struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> {
+    using Base = BaseLayerVariant<LayerProperties>;
+    using FlingerLayerType = sp<BufferQueueLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest* test) {
+        test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID);
+
+        FlingerLayerType layer =
+                Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
+                    return new BufferQueueLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+                                                String8("test-layer"), LayerProperties::WIDTH,
+                                                LayerProperties::HEIGHT,
+                                                LayerProperties::LAYER_FLAGS);
+                });
+
+        LayerProperties::setupLayerState(test, layer);
+
+        return layer;
+    }
+
+    static void cleanupInjectedLayers(CompositionTest* test) {
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(2);
+        Base::cleanupInjectedLayers(test);
+    }
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        LayerProperties::setupHwcSetGeometryCallExpectations(test);
+        LayerProperties::setupHwcSetSourceCropBufferCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+        LayerProperties::setupHwcSetPerFrameBufferCallExpectations(test);
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupInsecureRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupInsecureREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferScreenshotCompositionCallExpectations(test);
+    }
+
+    static void setupInsecureREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupInsecureREBufferScreenshotCompositionCallExpectations(test);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to control how the composition type is changed
+ */
+
+struct NoCompositionTypeVariant {
+    static void setupHwcSetCallExpectations(CompositionTest*) {}
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+    }
+};
+
+template <IComposerClient::Composition CompositionType>
+struct KeepCompositionTypeVariant {
+    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+
+    static void setupHwcSetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+                .Times(1);
+    }
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+    }
+};
+
+template <IComposerClient::Composition InitialCompositionType,
+          IComposerClient::Composition FinalCompositionType>
+struct ChangeCompositionTypeVariant {
+    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+
+    static void setupHwcSetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+                .Times(1);
+    }
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::Layer>{
+                                        static_cast<Hwc2::Layer>(HWC_LAYER)}),
+                                SetArgPointee<2>(std::vector<IComposerClient::Composition>{
+                                        FinalCompositionType}),
+                                Return(Error::NONE)));
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to select how the composition is expected to be handled
+ */
+
+struct CompositionResultBaseVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        Case::Layer::setupCallExpectationsForDirtyGeometry(test);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        Case::Layer::setupCallExpectationsForDirtyFrame(test);
+    }
+};
+
+struct NoCompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcCompositionCallExpectations(test);
+    }
+};
+
+struct HwcCompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcCompositionCallExpectations(test);
+    }
+};
+
+struct RECompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+};
+
+struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer> layer) {
+        layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct EmptyScreenshotResultVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest*) {}
+};
+
+struct REScreenshotResultVariant : public EmptyScreenshotResultVariant {
+    using Base = EmptyScreenshotResultVariant;
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Base::template setupCallExpectations<Case>(test);
+        Case::Display::template setupRELayerScreenshotCompositionCallExpectations<Case>(test);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition test case, containing all the variants being tested
+ */
+
+template <typename DisplayCase, typename LayerCase, typename CompositionTypeCase,
+          typename CompositionResultCase>
+struct CompositionCase {
+    using ThisCase =
+            CompositionCase<DisplayCase, LayerCase, CompositionTypeCase, CompositionResultCase>;
+    using Display = DisplayCase;
+    using Layer = LayerCase;
+    using CompositionType = CompositionTypeCase;
+    using CompositionResult = CompositionResultCase;
+
+    static void setupCommon(CompositionTest* test) {
+        Display::setupPreconditions(test);
+
+        auto layer = Layer::createLayer(test);
+        Layer::injectLayer(test, layer);
+        CompositionResult::setupLayerState(test, layer);
+    }
+
+    static void setupForDirtyGeometry(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyGeometry<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void setupForDirtyFrame(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void setupForScreenCapture(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonScreensCaptureCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void cleanup(CompositionTest* test) {
+        Layer::cleanupInjectedLayers(test);
+
+        for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
+            hwcDisplay->mutableLayers().clear();
+        }
+
+        test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition cases to test
+ */
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkToCaptureScreen) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            EmptyScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Simple buffer layers
+ */
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedNormalBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Single-color layers
+ */
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedColorLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenColorLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with sideband buffers
+ */
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSidebandBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::SIDEBAND,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSidebandBufferLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with ISurfaceComposerClient::eSecure, on a secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSecureBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with ISurfaceComposerClient::eSecure, on a non-secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) {
+    captureScreenComposition<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Cursor layers
+ */
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedCursorLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::CURSOR,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenCursorLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Simple buffer layer on a display which is powered off.
+ */
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+    displayRefreshCompositionDirtyFrame<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                         IComposerClient::Composition::CLIENT>,
+            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayerOnPoweredOffDisplay) {
+    captureScreenComposition<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 1bba480..341734c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "DisplayDevice.h"
+#include "Layer.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
@@ -56,6 +57,21 @@
 
     using HotplugEvent = SurfaceFlinger::HotplugEvent;
 
+    auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
+    auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
+
+    void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
+        layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
+    }
+
+    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
+        layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
+    };
+
+    void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
+        layer->mPotentialCursor = potentialCursor;
+    }
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
@@ -96,6 +112,21 @@
         return mFlinger->setPowerModeInternal(display, mode, stateLockHeld);
     }
 
+    auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
+
+    auto captureScreenImplLocked(const RenderArea& renderArea,
+                                 TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer,
+                                 bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+        return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
+                                                 useIdentityTransform, forSystem, outSyncFd);
+    }
+
+    auto traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+                                 int32_t maxLayerZ, const LayerVector::Visitor& visitor) {
+        return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, minLayerZ, maxLayerZ,
+                                                                 visitor);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -116,20 +147,22 @@
     auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
     auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
 
-    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
-    auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
+    auto& mutableDisplays() { return mFlinger->mDisplays; }
+    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
     auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
     auto& mutableEventQueue() { return mFlinger->mEventQueue; }
     auto& mutableEventThread() { return mFlinger->mEventThread; }
+    auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
     auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
     auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
     auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
     auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
+    auto& mutableTexturePool() { return mFlinger->mTexturePool; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
 
@@ -175,6 +208,7 @@
 
         auto& mutableIsConnected() { return this->mIsConnected; }
         auto& mutableConfigs() { return this->mConfigs; }
+        auto& mutableLayers() { return this->mLayers; }
     };
 
     class FakeHwcDisplayInjector {
@@ -324,14 +358,25 @@
             return *this;
         }
 
+        auto& setDisplaySize(int width, int height) {
+            mWidth = width;
+            mHeight = height;
+            return *this;
+        }
+
+        auto& setPowerMode(int mode) {
+            mPowerMode = mode;
+            return *this;
+        }
+
         sp<DisplayDevice> inject() {
             std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents;
             sp<DisplayDevice> device =
                     new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure,
                                       mDisplayToken, mNativeWindow, mDisplaySurface,
-                                      std::move(mRenderSurface), 0, 0,
+                                      std::move(mRenderSurface), mWidth, mHeight,
                                       DisplayState::eOrientationDefault, false, HdrCapabilities(),
-                                      0, hdrAndRenderIntents, HWC_POWER_MODE_NORMAL);
+                                      0, hdrAndRenderIntents, mPowerMode);
             mFlinger.mutableDisplays().emplace(mDisplayToken, device);
 
             DisplayDeviceState state;
@@ -356,6 +401,9 @@
         sp<DisplaySurface> mDisplaySurface;
         std::unique_ptr<renderengine::Surface> mRenderSurface;
         bool mSecure = false;
+        int mWidth = 0;
+        int mHeight = 0;
+        int mPowerMode = HWC_POWER_MODE_NORMAL;
     };
 
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index 06ef0b2..af54df6 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -32,6 +32,9 @@
 Image::Image() = default;
 Image::~Image() = default;
 
+Framebuffer::Framebuffer() = default;
+Framebuffer::~Framebuffer() = default;
+
 } // namespace mock
 } // namespace renderengine
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 84d3c63..39ed622 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -18,6 +18,7 @@
 
 #include <gmock/gmock.h>
 
+#include <renderengine/Framebuffer.h>
 #include <renderengine/Image.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/RenderEngine.h>
@@ -103,6 +104,14 @@
                  bool(ANativeWindowBuffer* buffer, bool isProtected));
 };
 
+class Framebuffer : public renderengine::Framebuffer {
+public:
+    Framebuffer();
+    ~Framebuffer() override;
+
+    MOCK_METHOD1(setNativeWindowBuffer, bool(ANativeWindowBuffer*));
+};
+
 } // namespace mock
 } // namespace renderengine
 } // namespace android
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 76eca35..8817e8d 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 82
+define VERSION_PATCH 84
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -221,6 +221,10 @@
 @extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
 @extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
 
+// 68
+@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1
+@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
+
 // 70
 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_SPEC_VERSION 2
 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
@@ -437,6 +441,10 @@
 @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"
 
+// 139
+@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1
+@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block"
+
 // 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"
@@ -526,8 +534,8 @@
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
 
 // 191
-@extension("VK_EXT_vertex_attribute_divisor") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
-@extension("VK_EXT_vertex_attribute_divisor") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
+@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
+@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
 // 199
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
@@ -537,6 +545,10 @@
 @extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2
 @extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints"
 
+// 212
+@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
+@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
+
 /////////////
 //  Types  //
 /////////////
@@ -697,6 +709,9 @@
     VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC               = 0x00000008,
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC               = 0x00000009,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT                     = 0x0000000a,
+
+    //@extension("VK_EXT_inline_uniform_block") // 139
+    VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT             = 1000138000,
 }
 
 enum VkQueryType {
@@ -1416,6 +1431,10 @@
     //@extension("VK_NN_vi_surface") // 63
     VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN                 = 1000062000,
 
+    //@extension("VK_EXT_astc_decode_mode") // 68
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT           = 1000067000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT  = 1000067001,
+
     //@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,
@@ -1595,6 +1614,12 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
     VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
 
+    //@extension("VK_EXT_inline_uniform_block") // 139
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT     = 1000138000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT   = 1000138001,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT         = 1000138002,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT  = 1000138003,
+
     //@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,
@@ -1667,10 +1692,14 @@
     //@extension("VK_EXT_vertex_attribute_divisor") // 191
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT   = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT       = 1000190001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT     = 1000190002,
 
     //@extension("VK_NV_device_diagnostic_checkpoints") // 207
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV                        = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV     = 1000206001,
+
+    //@extension("VK_KHR_vulkan_memory_model") // 212
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
 }
 
 enum VkSubpassContents {
@@ -5354,6 +5383,20 @@
     void*                                       window
 }
 
+@extension("VK_EXT_astc_decode_mode") // 68
+class VkImageViewASTCDecodeModeEXT {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkFormat                                    decodeMode
+}
+
+@extension("VK_EXT_astc_decode_mode") // 68
+class VkPhysicalDeviceASTCDecodeFeaturesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    VkBool32                                    decodeModeSharedExponent
+}
+
 @extension("VK_KHR_device_group_creation") // 71
 class VkPhysicalDeviceGroupPropertiesKHR {
     VkStructureType                                 sType
@@ -6386,6 +6429,40 @@
     VkBool32                                        filterMinmaxImageComponentMapping
 }
 
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkPhysicalDeviceInlineUniformBlockFeaturesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        inlineUniformBlock
+    VkBool32                                        descriptorBindingInlineUniformBlockUpdateAfterBind
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkPhysicalDeviceInlineUniformBlockPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             maxInlineUniformBlockSize
+    u32                                             maxPerStageDescriptorInlineUniformBlocks
+    u32                                             maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks
+    u32                                             maxDescriptorSetInlineUniformBlocks
+    u32                                             maxDescriptorSetUpdateAfterBindInlineUniformBlocks
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkWriteDescriptorSetInlineUniformBlockEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             dataSize
+    const void*                                     pData
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkDescriptorPoolInlineUniformBlockCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             maxInlineUniformBlockBindings
+}
+
 @extension("VK_EXT_sample_locations") // 144
 class VkSampleLocationEXT {
     f32                                             x
@@ -6796,6 +6873,14 @@
     const VkVertexInputBindingDivisorDescriptionEXT*    pVertexBindingDivisors
 }
 
+@extension("VK_EXT_vertex_attribute_divisor") // 191
+class VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        vertexAttributeInstanceRateDivisor
+    VkBool32                                        vertexAttributeInstanceRateZeroDivisor
+}
+
 @extension("VK_NV_device_diagnostic_checkpoints") // 207
 class VkQueueFamilyCheckpointPropertiesNV {
     VkStructureType                                 sType
@@ -6811,6 +6896,14 @@
     void*                                           pCheckpointMarker
 }
 
+@extension("VK_KHR_vulkan_memory_model") // 212
+class VkPhysicalDeviceVulkanMemoryModelFeaturesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        vulkanMemoryModel
+    VkBool32                                        vulkanMemoryModelDeviceScope
+}
+
 
 ////////////////
 //  Commands  //
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index d511015..fe45014 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 82
+#define VK_HEADER_VERSION 84
 
 
 #define VK_NULL_HANDLE 0
@@ -305,6 +305,8 @@
     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_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001,
     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,
@@ -380,6 +382,10 @@
     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_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003,
     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,
@@ -406,8 +412,11 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+    VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
     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,
@@ -442,6 +451,7 @@
     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_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT,
     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,
@@ -1120,6 +1130,7 @@
     VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
+    VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
     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),
@@ -4575,7 +4586,6 @@
 
 #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 {
@@ -4594,6 +4604,7 @@
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
     VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
+    VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     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),
@@ -5981,13 +5992,24 @@
 
 
 
+#define VK_KHR_vulkan_memory_model 1
+#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
+#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
+
+typedef struct VkPhysicalDeviceVulkanMemoryModelFeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           vulkanMemoryModel;
+    VkBool32           vulkanMemoryModelDeviceScope;
+} VkPhysicalDeviceVulkanMemoryModelFeaturesKHR;
+
+
+
 #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 {
@@ -6027,6 +6049,8 @@
     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_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
     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,
@@ -6431,6 +6455,24 @@
 #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
 
 
+#define VK_EXT_astc_decode_mode 1
+#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1
+#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
+
+typedef struct VkImageViewASTCDecodeModeEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkFormat           decodeMode;
+} VkImageViewASTCDecodeModeEXT;
+
+typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           decodeModeSharedExponent;
+} VkPhysicalDeviceASTCDecodeFeaturesEXT;
+
+
+
 #define VK_EXT_conditional_rendering 1
 #define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1
 #define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering"
@@ -6746,7 +6788,6 @@
 #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 {
@@ -7300,6 +7341,42 @@
 #define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
 
 
+#define VK_EXT_inline_uniform_block 1
+#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1
+#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block"
+
+typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           inlineUniformBlock;
+    VkBool32           descriptorBindingInlineUniformBlockUpdateAfterBind;
+} VkPhysicalDeviceInlineUniformBlockFeaturesEXT;
+
+typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxInlineUniformBlockSize;
+    uint32_t           maxPerStageDescriptorInlineUniformBlocks;
+    uint32_t           maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
+    uint32_t           maxDescriptorSetInlineUniformBlocks;
+    uint32_t           maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
+} VkPhysicalDeviceInlineUniformBlockPropertiesEXT;
+
+typedef struct VkWriteDescriptorSetInlineUniformBlockEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           dataSize;
+    const void*        pData;
+} VkWriteDescriptorSetInlineUniformBlockEXT;
+
+typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           maxInlineUniformBlockBindings;
+} VkDescriptorPoolInlineUniformBlockCreateInfoEXT;
+
+
+
 #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"
@@ -7483,7 +7560,6 @@
 
 #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 {
@@ -7734,7 +7810,7 @@
 
 
 #define VK_EXT_vertex_attribute_divisor 1
-#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
+#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
 typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
@@ -7755,6 +7831,13 @@
     const VkVertexInputBindingDivisorDescriptionEXT*    pVertexBindingDivisors;
 } VkPipelineVertexInputDivisorStateCreateInfoEXT;
 
+typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           vertexAttributeInstanceRateDivisor;
+    VkBool32           vertexAttributeInstanceRateZeroDivisor;
+} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT;
+
 
 
 #define VK_NV_shader_subgroup_partitioned 1
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 96c5563..b32977a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -165,8 +165,13 @@
     std::lock_guard<std::mutex> lock(mutex_);
     if (--refcount_ == 0) {
         ALOGV("closing layer library '%s'", path_.c_str());
-        dlclose(dlhandle_);
-        dlhandle_ = nullptr;
+        std::string error_msg;
+        if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
+            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+            refcount_++;
+        } else {
+           dlhandle_ = nullptr;
+        }
     }
 }