loader: Preload icd libraries

The loader has been slow when calling functions that don't have an
instance (as well as vkCreateInstance) because they have to load the
ICDs each time. This change preloads them when the loader does its
global initialization so that the repeated loading an unloading
generally doesn't happen.

Change-Id: I9de477c4258e78baa8ae9718f83a0498f2d9f3f6
diff --git a/loader/loader.c b/loader/loader.c
index e65b3ba..fc9ca7e 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -93,6 +93,12 @@
 loader_platform_thread_mutex loader_lock;
 loader_platform_thread_mutex loader_json_lock;
 
+// A list of ICDs that gets initialized when the loader does its global initialization. This list should never be used by anything
+// other than loader_initialize() and loader_release(). This list does not change functionality, but the fact that the libraries
+// already been loaded causes any call that needs to load ICD libraries to speed up significantly. This can have a huge impact when
+// making repeated calls to vkEnumerateInstanceExtensionProperties and vkCreateInstance.
+static struct loader_icd_tramp_list scanned_icds;
+
 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)
@@ -1918,6 +1924,22 @@
         .malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
     };
     cJSON_InitHooks(&alloc_fns);
+
+    // Load the ICD libraries that are likely to be needed so we don't repeateldy load/unload them later
+    memset(&scanned_icds, 0, sizeof(scanned_icds));
+    VkResult result = loader_icd_scan(NULL, &scanned_icds);
+    if (result != VK_SUCCESS) {
+        loader_scanned_icd_clear(NULL, &scanned_icds);
+    }
+}
+
+void loader_release() {
+    // Release the ICD libraries that we stored earlier to speed things up
+    loader_scanned_icd_clear(NULL, &scanned_icds);
+
+    // release mutexs
+    loader_platform_thread_delete_mutex(&loader_lock);
+    loader_platform_thread_delete_mutex(&loader_json_lock);
 }
 
 struct loader_manifest_files {
@@ -1925,12 +1947,6 @@
     char **filename_list;
 };
 
-void loader_release() {
-    // release mutexs
-    loader_platform_thread_delete_mutex(&loader_lock);
-    loader_platform_thread_delete_mutex(&loader_json_lock);
-}
-
 // Get next file or dirname given a string list or registry key path
 //
 // \returns