loader: Extend pre-instance intercepts for 1.1

Add the ability to intercept vkEnumerateInstanceVersion through the
pre-instance intercept mechanism
diff --git a/loader/loader.c b/loader/loader.c
index ff777d5..0b88f66 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -98,6 +98,10 @@
 
 LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
 
+// This loader supports Vulkan API version 1.1
+uint32_t loader_major_version = 1;
+uint32_t loader_minor_version = 1;
+
 void *loader_instance_heap_alloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope alloc_scope) {
     void *pMemory = NULL;
 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
@@ -2864,6 +2868,15 @@
                 props->pre_instance_functions.enumerate_instance_layer_properties[len] = '\0';
                 cJSON_Free(inst_layer_name);
             }
+
+            cJSON *inst_version_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceVersion");
+            if (inst_version_json) {
+                char *inst_version_name = cJSON_Print(inst_version_json);
+                size_t len = strlen(inst_version_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_version_name) - 2;
+                strncpy(props->pre_instance_functions.enumerate_instance_version, inst_version_name + 1, len);
+                props->pre_instance_functions.enumerate_instance_version[len] = '\0';
+                cJSON_Free(inst_version_name);
+            }
         }
     }
 
@@ -6095,6 +6108,14 @@
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL
+terminator_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain, uint32_t* pApiVersion) {
+    // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead
+    // prefers us crashing.
+    *pApiVersion = VK_MAKE_VERSION(loader_major_version, loader_minor_version, 0);
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
 terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
                                                 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
     struct loader_extension_list *global_ext_list = NULL;
diff --git a/loader/loader.h b/loader/loader.h
index 9342e21..8abc034 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -140,6 +140,7 @@
     struct {
         char enumerate_instance_extension_properties[MAX_STRING_SIZE];
         char enumerate_instance_layer_properties[MAX_STRING_SIZE];
+        char enumerate_instance_version[MAX_STRING_SIZE];
     } pre_instance_functions;
 };
 
diff --git a/loader/trampoline.c b/loader/trampoline.c
index dff1ccd..51f1377 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -33,9 +33,6 @@
 #include "vk_loader_extensions.h"
 #include "gpa_helper.h"
 
-// This loader only supports Vulkan API version 1.0
-uint32_t loader_major_version = 1;
-uint32_t loader_minor_version = 1;
 
 // Trampoline entrypoints are in this file for core Vulkan commands
 
@@ -273,10 +270,91 @@
 }
 
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
-    // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead
-    // prefers us crashing.
-    *pApiVersion = VK_MAKE_VERSION(loader_major_version, loader_minor_version, 0);
-    return VK_SUCCESS;
+
+    tls_instance = NULL;
+    LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
+
+    // We know we need to call at least the terminator
+    VkResult res = VK_SUCCESS;
+    VkEnumerateInstanceVersionChain chain_tail = {
+        .header =
+            {
+                .type = VK_CHAIN_TYPE_ENUMERATE_INSTANCE_VERSION,
+                .version = VK_CURRENT_CHAIN_VERSION,
+                .size = sizeof(chain_tail),
+            },
+        .pfnNextLayer = &terminator_EnumerateInstanceVersion,
+        .pNextLink = NULL,
+    };
+    VkEnumerateInstanceVersionChain *chain_head = &chain_tail;
+
+    // Get the implicit layers
+    struct loader_layer_list layers;
+    memset(&layers, 0, sizeof(layers));
+    loader_implicit_layer_scan(NULL, &layers);
+
+    // We'll need to save the dl handles so we can close them later
+    loader_platform_dl_handle *libs = malloc(sizeof(loader_platform_dl_handle) * layers.count);
+    if (libs == NULL) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    size_t lib_count = 0;
+
+    // Prepend layers onto the chain if they implment this entry point
+    for (uint32_t i = 0; i < layers.count; ++i) {
+        if (!loader_is_implicit_layer_enabled(NULL, layers.list + i) ||
+            layers.list[i].pre_instance_functions.enumerate_instance_version[0] == '\0') {
+            continue;
+        }
+
+        loader_platform_dl_handle layer_lib = loader_platform_open_library(layers.list[i].lib_name);
+        libs[lib_count++] = layer_lib;
+        void *pfn = loader_platform_get_proc_address(layer_lib,
+                                                     layers.list[i].pre_instance_functions.enumerate_instance_version);
+        if (pfn == NULL) {
+            loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+                       "%s: Unable to resolve symbol \"%s\" in implicit layer library \"%s\"", __FUNCTION__,
+                       layers.list[i].pre_instance_functions.enumerate_instance_version, layers.list[i].lib_name);
+            continue;
+        }
+
+        VkEnumerateInstanceVersionChain *chain_link = malloc(sizeof(VkEnumerateInstanceVersionChain));
+        if (chain_link == NULL) {
+            res = VK_ERROR_OUT_OF_HOST_MEMORY;
+            break;
+        }
+
+        chain_link->header.type = VK_CHAIN_TYPE_ENUMERATE_INSTANCE_VERSION;
+        chain_link->header.version = VK_CURRENT_CHAIN_VERSION;
+        chain_link->header.size = sizeof(*chain_link);
+        chain_link->pfnNextLayer = pfn;
+        chain_link->pNextLink = chain_head;
+
+        chain_head = chain_link;
+    }
+
+    // Call down the chain
+    if (res == VK_SUCCESS) {
+        res = chain_head->pfnNextLayer(chain_head->pNextLink, pApiVersion);
+    }
+
+    // Free up the layers
+    loader_delete_layer_properties(NULL, &layers);
+
+    // Tear down the chain
+    while (chain_head != &chain_tail) {
+        VkEnumerateInstanceVersionChain *holder = chain_head;
+        chain_head = (VkEnumerateInstanceVersionChain *)chain_head->pNextLink;
+        free(holder);
+    }
+
+    // Close the dl handles
+    for (size_t i = 0; i < lib_count; ++i) {
+        loader_platform_close_library(libs[i]);
+    }
+    free(libs);
+
+    return res;
 }
 
 LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo,