Vulkan loader changes to support VK_EXT_image_compression_control

Bug: 218365766
Test: Build
Change-Id: I91cddbee0daac27d838e6201ba63c51a5158412c
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index ba98696..40cf9fb 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -49,7 +49,13 @@
  * in VkBindImageMemorySwapchainInfoKHR will be additionally chained to the
  * pNext chain of VkBindImageMemoryInfo and passed down to the driver.
  */
-#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8
+/*
+ * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
+ *
+ * This version of the extension is largely designed to clean up the mix of
+ * GrallocUsage and GrallocUsage2
+ */
+#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
 
 #define VK_ANDROID_NATIVE_BUFFER_ENUM(type, id) \
@@ -61,6 +67,8 @@
     VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
 #define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID \
     VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 2)
+#define VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID \
+    VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 3)
 
 /* clang-format off */
 typedef enum VkSwapchainImageUsageFlagBitsANDROID {
@@ -90,6 +98,7 @@
  * format: gralloc format requested when the buffer was allocated
  * usage: gralloc usage requested when the buffer was allocated
  * usage2: gralloc usage requested when the buffer was allocated
+ * usage3: gralloc usage requested when the buffer was allocated
  */
 typedef struct {
     VkStructureType                   sType;
@@ -98,7 +107,8 @@
     int                               stride;
     int                               format;
     int                               usage; /* DEPRECATED in SPEC_VERSION 6 */
-    VkNativeBufferUsage2ANDROID       usage2; /* ADDED in SPEC_VERSION 6 */
+    VkNativeBufferUsage2ANDROID       usage2; /* DEPRECATED in SPEC_VERSION 9 */
+    uint64_t                          usage3; /* ADDED in SPEC_VERSION 9 */
 } VkNativeBufferANDROID;
 
 /*
@@ -127,6 +137,21 @@
     VkBool32                          sharedImage;
 } VkPhysicalDevicePresentationPropertiesANDROID;
 
+/*
+ * struct VkGrallocUsageInfoANDROID
+ *
+ * sType: VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID
+ * pNext: NULL or a pointer to a structure extending this structure
+ * format: value specifying the format the image will be created with
+ * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage
+ */
+typedef struct {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkFormat                          format;
+    VkImageUsageFlags                 imageUsage;
+} VkGrallocUsageInfoANDROID;
+
 /* DEPRECATED in SPEC_VERSION 6 */
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(
     VkDevice                          device,
@@ -134,7 +159,7 @@
     VkImageUsageFlags                 imageUsage,
     int*                              grallocUsage);
 
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(
     VkDevice                          device,
     VkFormat                          format,
@@ -143,6 +168,12 @@
     uint64_t*                         grallocConsumerUsage,
     uint64_t*                         grallocProducerUsage);
 
+/* ADDED in SPEC_VERSION 9 */
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage3ANDROID)(
+    VkDevice                          device,
+    const VkGrallocUsageInfoANDROID*  grallocUsageInfo,
+    uint64_t*                         grallocUsage);
+
 typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(
     VkDevice                          device,
     VkImage                           image,
@@ -167,7 +198,7 @@
     int*                              grallocUsage
 );
 
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
 VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
     VkDevice                          device,
     VkFormat                          format,
@@ -177,6 +208,13 @@
     uint64_t*                         grallocProducerUsage
 );
 
+/* ADDED in SPEC_VERSION 9 */
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage3ANDROID(
+    VkDevice                          device,
+    const VkGrallocUsageInfoANDROID*  grallocUsageInfo,
+    uint64_t*                         grallocUsage
+);
+
 VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID(
     VkDevice                          device,
     VkImage                           image,
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7664518..4927150 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -1027,6 +1027,39 @@
     }
 }
 
+bool GetAndroidNativeBufferSpecVersion9Support(
+    VkPhysicalDevice physicalDevice) {
+    const InstanceData& data = GetData(physicalDevice);
+
+    // Call to get propertyCount
+    uint32_t propertyCount = 0;
+    ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, nullptr, &propertyCount, nullptr);
+    ATRACE_END();
+
+    // Call to enumerate properties
+    std::vector<VkExtensionProperties> properties(propertyCount);
+    ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+    result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, nullptr, &propertyCount, properties.data());
+    ATRACE_END();
+
+    for (uint32_t i = 0; i < propertyCount; i++) {
+        auto& prop = properties[i];
+
+        if (strcmp(prop.extensionName,
+                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+            continue;
+
+        if (prop.specVersion >= 9) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 VkResult EnumerateDeviceExtensionProperties(
     VkPhysicalDevice physicalDevice,
     const char* pLayerName,
@@ -1061,6 +1094,37 @@
                 VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
     }
 
+    // Conditionally add VK_EXT_IMAGE_COMPRESSION_CONTROL* if feature and ANB
+    // support is provided by the driver
+    VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT
+        swapchainCompFeats = {};
+    swapchainCompFeats.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT;
+    swapchainCompFeats.pNext = nullptr;
+    VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+    imageCompFeats.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+    imageCompFeats.pNext = &swapchainCompFeats;
+
+    VkPhysicalDeviceFeatures2 feats2 = {};
+    feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    feats2.pNext = &imageCompFeats;
+
+    GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+
+    bool anb9 = GetAndroidNativeBufferSpecVersion9Support(physicalDevice);
+
+    if (anb9 && imageCompFeats.imageCompressionControl) {
+        loader_extensions.push_back(
+            {VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME,
+             VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION});
+    }
+    if (anb9 && swapchainCompFeats.imageCompressionControlSwapchain) {
+        loader_extensions.push_back(
+            {VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME,
+             VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION});
+    }
+
     // enumerate our extensions first
     if (!pLayerName && pProperties) {
         uint32_t count = std::min(
@@ -1254,15 +1318,18 @@
         return VK_ERROR_INCOMPATIBLE_DRIVER;
     }
 
-    // sanity check ANDROID_native_buffer implementation, whose set of
+    // Confirming ANDROID_native_buffer implementation, whose set of
     // entrypoints varies according to the spec version.
     if ((wrapper.GetHalExtensions()[ProcHook::ANDROID_native_buffer]) &&
         !data->driver.GetSwapchainGrallocUsageANDROID &&
-        !data->driver.GetSwapchainGrallocUsage2ANDROID) {
-        ALOGE("Driver's implementation of ANDROID_native_buffer is broken;"
-              " must expose at least one of "
-              "vkGetSwapchainGrallocUsageANDROID or "
-              "vkGetSwapchainGrallocUsage2ANDROID");
+        !data->driver.GetSwapchainGrallocUsage2ANDROID &&
+        !data->driver.GetSwapchainGrallocUsage3ANDROID) {
+        ALOGE(
+            "Driver's implementation of ANDROID_native_buffer is broken;"
+            " must expose at least one of "
+            "vkGetSwapchainGrallocUsageANDROID or "
+            "vkGetSwapchainGrallocUsage2ANDROID or "
+            "vkGetSwapchainGrallocUsage3ANDROID");
 
         data->driver.DestroyDevice(dev, pAllocator);
         FreeDeviceData(data, data_allocator);
@@ -1441,10 +1508,83 @@
 
     if (driver.GetPhysicalDeviceFeatures2) {
         driver.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+    } else {
+        driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    }
+
+    // Conditionally add imageCompressionControlSwapchain if
+    // imageCompressionControl is supported Check for imageCompressionControl in
+    // the pChain
+    bool imageCompressionControl = false;
+    bool imageCompressionControlInChain = false;
+    bool imageCompressionControlSwapchainInChain = false;
+    VkPhysicalDeviceFeatures2* pFeats = pFeatures;
+    while (pFeats) {
+        switch (pFeats->sType) {
+            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: {
+                const VkPhysicalDeviceImageCompressionControlFeaturesEXT*
+                    compressionFeat = reinterpret_cast<
+                        const VkPhysicalDeviceImageCompressionControlFeaturesEXT*>(
+                        pFeats);
+                imageCompressionControl =
+                    compressionFeat->imageCompressionControl;
+                imageCompressionControlInChain = true;
+            } break;
+
+            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+                imageCompressionControlSwapchainInChain = true;
+            } break;
+
+            default:
+                break;
+        }
+        pFeats = reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+    }
+
+    if (!imageCompressionControlSwapchainInChain) {
         return;
     }
 
-    driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    // If not in pchain, explicitly query for imageCompressionControl
+    if (!imageCompressionControlInChain) {
+        VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+        imageCompFeats.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+        imageCompFeats.pNext = nullptr;
+
+        VkPhysicalDeviceFeatures2 feats2 = {};
+        feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+        feats2.pNext = &imageCompFeats;
+
+        if (driver.GetPhysicalDeviceFeatures2) {
+            driver.GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+        } else {
+            driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, &feats2);
+        }
+
+        imageCompressionControl = imageCompFeats.imageCompressionControl;
+    }
+
+    // Only enumerate imageCompressionControlSwapchin if imageCompressionControl
+    if (imageCompressionControl) {
+        pFeats = pFeatures;
+        while (pFeats) {
+            switch (pFeats->sType) {
+                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+                    VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+                        compressionFeat = reinterpret_cast<
+                            VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+                            pFeats);
+                    compressionFeat->imageCompressionControlSwapchain = true;
+                } break;
+
+                default:
+                    break;
+            }
+            pFeats =
+                reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+        }
+    }
 }
 
 void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 14c516b..4d2bbd6 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -107,6 +107,8 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties);
 
+bool GetAndroidNativeBufferSpecVersion9Support(VkPhysicalDevice physicalDevice);
+
 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
                                                   const char* pName);
 VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index b436db1..de98aa7 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -496,6 +496,13 @@
         nullptr,
     },
     {
+        "vkGetSwapchainGrallocUsage3ANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+    },
+    {
         "vkGetSwapchainGrallocUsageANDROID",
         ProcHook::DEVICE,
         ProcHook::ANDROID_native_buffer,
@@ -664,6 +671,7 @@
     INIT_PROC(false, dev, GetDeviceQueue2);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage3ANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
     // clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 079f9cc..2f60086 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -123,6 +123,7 @@
     PFN_vkGetDeviceQueue2 GetDeviceQueue2;
     PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
     PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
+    PFN_vkGetSwapchainGrallocUsage3ANDROID GetSwapchainGrallocUsage3ANDROID;
     PFN_vkAcquireImageANDROID AcquireImageANDROID;
     PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
     // clang-format on
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index f49e8f3..b189c68 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -178,6 +178,7 @@
     vkGetImageSparseMemoryRequirements;
     vkGetImageSparseMemoryRequirements2; # introduced=28
     vkGetImageSubresourceLayout;
+    vkGetImageSubresourceLayout2EXT; # introduced=UpsideDownCake
     vkGetInstanceProcAddr;
     vkGetMemoryAndroidHardwareBufferANDROID; # introduced=28
     vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a75108c..83bc655 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -948,11 +948,60 @@
             surface_formats.data());
 
         if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+            const auto& driver = GetData(physicalDevice).driver;
+
             // marshal results individually due to stride difference.
-            // completely ignore any chained extension structs.
             uint32_t formats_to_marshal = *pSurfaceFormatCount;
             for (uint32_t i = 0u; i < formats_to_marshal; i++) {
                 pSurfaceFormats[i].surfaceFormat = surface_formats[i];
+
+                // Query the compression properties for the surface format
+                if (pSurfaceFormats[i].pNext) {
+                    VkImageCompressionPropertiesEXT* surfaceCompressionProps =
+                        reinterpret_cast<VkImageCompressionPropertiesEXT*>(
+                            pSurfaceFormats[i].pNext);
+
+                    if (surfaceCompressionProps &&
+                        driver.GetPhysicalDeviceImageFormatProperties2KHR) {
+                        VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
+                        imageFormatInfo.sType =
+                            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+                        imageFormatInfo.format =
+                            pSurfaceFormats[i].surfaceFormat.format;
+                        imageFormatInfo.pNext = nullptr;
+
+                        VkImageCompressionControlEXT compressionControl = {};
+                        compressionControl.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT;
+                        compressionControl.pNext = imageFormatInfo.pNext;
+
+                        imageFormatInfo.pNext = &compressionControl;
+
+                        VkImageCompressionPropertiesEXT compressionProps = {};
+                        compressionProps.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT;
+                        compressionProps.pNext = nullptr;
+
+                        VkImageFormatProperties2KHR imageFormatProps = {};
+                        imageFormatProps.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
+                        imageFormatProps.pNext = &compressionProps;
+
+                        VkResult compressionRes =
+                            driver.GetPhysicalDeviceImageFormatProperties2KHR(
+                                physicalDevice, &imageFormatInfo,
+                                &imageFormatProps);
+                        if (compressionRes == VK_SUCCESS) {
+                            surfaceCompressionProps->imageCompressionFlags =
+                                compressionProps.imageCompressionFlags;
+                            surfaceCompressionProps
+                                ->imageCompressionFixedRateFlags =
+                                compressionProps.imageCompressionFixedRateFlags;
+                        } else {
+                            return compressionRes;
+                        }
+                    }
+                }
             }
         }
 
@@ -1370,8 +1419,48 @@
         num_images = 1;
     }
 
+    void* usage_info_pNext = nullptr;
+    VkImageCompressionControlEXT image_compression = {};
     uint64_t native_usage = 0;
-    if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+    if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+        ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+        VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+        gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+        gralloc_usage_info.format = create_info->imageFormat;
+        gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+        // Look through the pNext chain for an image compression control struct
+        // if one is found AND the appropriate extensions are enabled,
+        // append it to be the gralloc usage pNext chain
+        const VkSwapchainCreateInfoKHR* create_infos = create_info;
+        while (create_infos->pNext) {
+            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+                create_infos->pNext);
+            switch (create_infos->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+                    const VkImageCompressionControlEXT* compression_infos =
+                        reinterpret_cast<const VkImageCompressionControlEXT*>(
+                            create_infos);
+                    image_compression = *compression_infos;
+                    image_compression.pNext = nullptr;
+                    usage_info_pNext = &image_compression;
+                } break;
+
+                default:
+                    // Ignore all other info structs
+                    break;
+            }
+        }
+        gralloc_usage_info.pNext = usage_info_pNext;
+
+        result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+            device, &gralloc_usage_info, &native_usage);
+        ATRACE_END();
+        if (result != VK_SUCCESS) {
+            ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+    } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
         ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
         result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1383,7 +1472,7 @@
             return VK_ERROR_SURFACE_LOST_KHR;
         }
         native_usage =
-            convertGralloc1ToBufferUsage(consumer_usage, producer_usage);
+            convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
     } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
         ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
         int32_t legacy_usage = 0;
@@ -1437,7 +1526,7 @@
 #pragma clang diagnostic ignored "-Wold-style-cast"
         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
 #pragma clang diagnostic pop
-        .pNext = nullptr,
+        .pNext = usage_info_pNext,
         .usage = swapchain_image_usage,
     };
     VkNativeBufferANDROID image_native_buffer = {
@@ -1495,6 +1584,7 @@
         android_convertGralloc0To1Usage(int(img.buffer->usage),
             &image_native_buffer.usage2.producer,
             &image_native_buffer.usage2.consumer);
+        image_native_buffer.usage3 = img.buffer->usage;
 
         ATRACE_BEGIN("CreateImage");
         result =
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3c91150..f998b1a 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -948,6 +948,17 @@
     return VK_SUCCESS;
 }
 
+VkResult GetSwapchainGrallocUsage3ANDROID(
+    VkDevice,
+    const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+    uint64_t* grallocUsage) {
+    // The null driver never reads or writes the gralloc buffer
+    ALOGV("TODO: vk%s - grallocUsageInfo->format:%i", __FUNCTION__,
+          grallocUsageInfo->format);
+    *grallocUsage = 0;
+    return VK_SUCCESS;
+}
+
 VkResult AcquireImageANDROID(VkDevice,
                              VkImage,
                              int fence,
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index f6dcf09..0cb7bd3 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -261,6 +261,7 @@
     {"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
     {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
     {"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
+    {"vkGetSwapchainGrallocUsage3ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage3ANDROID>(GetSwapchainGrallocUsage3ANDROID))},
     {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
     {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
     {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 3e003e3..5c7fea0 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -209,6 +209,7 @@
 VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage3ANDROID(VkDevice device, const VkGrallocUsageInfoANDROID* grallocUsageInfo, uint64_t* grallocUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
 VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
 VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 4176509..c25c6cb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -69,6 +69,7 @@
 _OPTIONAL_COMMANDS = [
     'vkGetSwapchainGrallocUsageANDROID',
     'vkGetSwapchainGrallocUsage2ANDROID',
+    'vkGetSwapchainGrallocUsage3ANDROID',
 ]
 
 # Dict for mapping dispatch table to a type.