Implement the VK_KHR_swapchain_mutable_format device extension in the vulkan loader

Add an implementation for the VK_KHR_swapchain_mutable_format extension.

Test: Stepped through changes in debugger
Test: Ran sample app with VVL which used the extension
Test: Ran dEQP-VK.image.swapchain_mutable.android.* dEQP tests
Flag: com.android.graphics.libvulkan.flags.swapchain_mutable_format_ext
Bug: 341978292
Change-Id: Ib0e5b9f750cd5a94ab65419542898db207716fcc
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 436e6c6..4c4e341 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -32,6 +32,18 @@
     ],
 }
 
+aconfig_declarations {
+    name: "libvulkan_flags",
+    package: "com.android.graphics.libvulkan.flags",
+    container: "system",
+    srcs: ["libvulkan_flags.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "libvulkanflags",
+    aconfig_declarations: "libvulkan_flags",
+}
+
 cc_library_shared {
     name: "libvulkan",
     llndk: {
@@ -113,5 +125,8 @@
         "android.hardware.graphics.common@1.0",
         "libSurfaceFlingerProp",
     ],
-    static_libs: ["libgrallocusage"],
+    static_libs: [
+        "libgrallocusage",
+        "libvulkanflags",
+    ],
 }
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index a3fe33e..9ff0b46 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -25,6 +25,9 @@
 #undef VK_NO_PROTOTYPES
 #include "api.h"
 
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
 namespace vulkan {
 namespace api {
 
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 4998018..b468a89 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -25,6 +25,9 @@
 
 #include "driver_gen.h"
 
+/*
+ * This file is autogenerated by api_generator.py. Do not edit directly.
+ */
 namespace vulkan {
 namespace api {
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index ef213f0..01436db 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -41,10 +41,12 @@
 #include <new>
 #include <vector>
 
+#include <com_android_graphics_libvulkan_flags.h>
 #include "stubhal.h"
 
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using namespace com::android::graphics::libvulkan;
 
 extern "C" android_namespace_t* android_get_exported_namespace(const char*);
 
@@ -688,6 +690,7 @@
             case ProcHook::KHR_incremental_present:
             case ProcHook::KHR_shared_presentable_image:
             case ProcHook::KHR_swapchain:
+            case ProcHook::KHR_swapchain_mutable_format:
             case ProcHook::EXT_hdr_metadata:
             case ProcHook::EXT_swapchain_maintenance1:
             case ProcHook::ANDROID_external_memory_android_hardware_buffer:
@@ -740,6 +743,7 @@
                 break;
             case ProcHook::ANDROID_external_memory_android_hardware_buffer:
             case ProcHook::KHR_external_fence_fd:
+            case ProcHook::KHR_swapchain_mutable_format:
             case ProcHook::EXTENSION_UNKNOWN:
                 // Extensions we don't need to do anything about at this level
                 break;
@@ -1251,6 +1255,15 @@
                 VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION});
     }
 
+    VkPhysicalDeviceProperties pDeviceProperties;
+    data.driver.GetPhysicalDeviceProperties(physicalDevice, &pDeviceProperties);
+    if (flags::swapchain_mutable_format_ext() &&
+        pDeviceProperties.apiVersion >= VK_API_VERSION_1_2) {
+        loader_extensions.push_back(
+            {VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
+             VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION});
+    }
+
     // enumerate our extensions first
     if (!pLayerName && pProperties) {
         uint32_t count = std::min(
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 8f09008..f741977 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -26,6 +26,9 @@
 namespace vulkan {
 namespace driver {
 
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
 namespace {
 
 // clang-format off
@@ -613,6 +616,7 @@
     if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities;
     if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities;
     if (strcmp(name, "VK_KHR_external_fence_fd") == 0) return ProcHook::KHR_external_fence_fd;
+    if (strcmp(name, "VK_KHR_swapchain_mutable_format") == 0) return ProcHook::KHR_swapchain_mutable_format;
     // clang-format on
     return ProcHook::EXTENSION_UNKNOWN;
 }
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 4527214..649c0f1 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -26,6 +26,9 @@
 #include <optional>
 #include <vector>
 
+/*
+ * This file is autogenerated by driver_generator.py. Do not edit directly.
+ */
 namespace vulkan {
 namespace driver {
 
@@ -59,6 +62,7 @@
         KHR_external_semaphore_capabilities,
         KHR_external_fence_capabilities,
         KHR_external_fence_fd,
+        KHR_swapchain_mutable_format,
 
         EXTENSION_CORE_1_0,
         EXTENSION_CORE_1_1,
diff --git a/vulkan/libvulkan/libvulkan_flags.aconfig b/vulkan/libvulkan/libvulkan_flags.aconfig
new file mode 100644
index 0000000..891bc02
--- /dev/null
+++ b/vulkan/libvulkan/libvulkan_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.graphics.libvulkan.flags"
+container: "system"
+
+flag {
+  name: "swapchain_mutable_format_ext"
+  namespace: "core_graphics"
+  description: "Enable the VK_KHR_swapchain_mutable_format vulkan extension"
+  bug: "341978292"
+  is_fixed_read_only: true
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 00e987f..0c23cf1 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1465,6 +1465,12 @@
             .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
         };
 
+        // If supporting mutable format swapchain add the mutable format flag
+        if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+            image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+            image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
+        }
+
         VkAndroidHardwareBufferUsageANDROID ahb_usage;
         ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
         ahb_usage.pNext = nullptr;
@@ -1883,6 +1889,11 @@
         num_images = 1;
     }
 
+    VkImageFormatListCreateInfo extra_mutable_formats = {
+        .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
+    };
+    VkImageFormatListCreateInfo* extra_mutable_formats_ptr;
+
     // Look through the create_info pNext chain passed to createSwapchainKHR
     // for an image compression control struct.
     // if one is found AND the appropriate extensions are enabled, create a
@@ -1901,7 +1912,29 @@
                 image_compression.pNext = nullptr;
                 usage_info_pNext = &image_compression;
             } break;
-
+            case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: {
+                const VkImageFormatListCreateInfo* format_list =
+                    reinterpret_cast<const VkImageFormatListCreateInfo*>(
+                        create_infos);
+                if (create_info->flags &
+                    VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+                    if (format_list && format_list->viewFormatCount > 0 &&
+                        format_list->pViewFormats) {
+                        extra_mutable_formats.viewFormatCount =
+                            format_list->viewFormatCount;
+                        extra_mutable_formats.pViewFormats =
+                            format_list->pViewFormats;
+                        extra_mutable_formats_ptr = &extra_mutable_formats;
+                    } else {
+                        ALOGE(
+                            "vk_swapchain_create_mutable_format_bit_khr was "
+                            "set during swapchain creation but no valid "
+                            "vkimageformatlistcreateinfo was found in the "
+                            "pnext chain");
+                        return VK_ERROR_INITIALIZATION_FAILED;
+                    }
+                }
+            } break;
             default:
                 // Ignore all other info structs
                 break;
@@ -1997,6 +2030,11 @@
         .pQueueFamilyIndices = create_info->pQueueFamilyIndices,
     };
 
+    if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+        image_create.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+        image_create.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
+    }
+
     // Note: don't do deferred allocation for shared present modes. There's only one buffer
     // involved so very little benefit.
     if ((create_info->flags & VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT) &&
@@ -2006,7 +2044,7 @@
         // AcquireNextImage.
         VkImageSwapchainCreateInfoKHR image_swapchain_create = {
             .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
-            .pNext = nullptr,
+            .pNext = extra_mutable_formats_ptr,
             .swapchain = HandleFromSwapchain(swapchain),
         };
         image_create.pNext = &image_swapchain_create;
@@ -2058,6 +2096,11 @@
                 ANativeWindowBuffer_getHardwareBuffer(img.buffer.get());
             image_create.pNext = &image_native_buffer;
 
+            if (extra_mutable_formats_ptr) {
+                extra_mutable_formats_ptr->pNext = image_create.pNext;
+                image_create.pNext = extra_mutable_formats_ptr;
+            }
+
             ATRACE_BEGIN("CreateImage");
             result =
                 dispatch.CreateImage(device, &image_create, nullptr, &img.image);