loader: Use layer manifest files to discovery and query layers

Conflicts:
	layers/CMakeLists.txt
	loader/loader.c
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index b2e655a..7356fe3 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -101,10 +101,10 @@
 add_vk_layer(MemTracker mem_tracker.cpp vk_layer_table.cpp)
 add_vk_layer(ShaderChecker shader_checker.cpp vk_layer_table.cpp)
 #add_vk_layer(Image image.cpp vk_layer_table.cpp)
+#add_vk_layer(ParamChecker param_checker.cpp vk_layer_debug_marker_table.cpp vk_layer_table.cpp)
+#add_vk_layer(ScreenShot screenshot.cpp vk_layer_table.cpp)
 # generated
 #add_vk_layer(Generic generic_layer.cpp vk_layer_table.cpp)
 add_vk_layer(APIDump api_dump.cpp vk_layer_table.cpp)
 add_vk_layer(ObjectTracker object_track.cpp vk_layer_table.cpp)
-#add_vk_layer(ParamChecker param_checker.cpp vk_layer_debug_marker_table.cpp vk_layer_table.cpp)
 add_vk_layer(Threading threading.cpp vk_layer_table.cpp)
-#add_vk_layer(ScreenShot screenshot.cpp vk_layer_table.cpp)
diff --git a/layers/api_dump_config.json b/layers/api_dump_config.json
new file mode 100644
index 0000000..cd1cca2
--- /dev/null
+++ b/layers/api_dump_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "APIDump",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerAPIDump.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG debug layer"
+    }
+}
diff --git a/layers/basic_config.json b/layers/basic_config.json
new file mode 100644
index 0000000..848bca4
--- /dev/null
+++ b/layers/basic_config.json
@@ -0,0 +1,17 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "Basic",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerBasic.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Sample Layer",
+        "device_extensions": [
+             {
+                 "name": "vkLayerExtension1",
+                 "version": "1.0.0"
+             }
+         ]
+    }
+}
diff --git a/layers/draw_state_config.json b/layers/draw_state_config.json
new file mode 100644
index 0000000..dc36e1c
--- /dev/null
+++ b/layers/draw_state_config.json
@@ -0,0 +1,17 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "DrawState",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerDrawState.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer",
+        "device_extensions": [
+             {
+                 "name": "DEBUG_MARKER",
+                 "version": "1.0.0"
+             }
+         ]
+    }
+}
diff --git a/layers/generic_config.json b/layers/generic_config.json
new file mode 100644
index 0000000..7c02016
--- /dev/null
+++ b/layers/generic_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "Generic",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerGeneric.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Sample Layer"
+    }
+}
diff --git a/layers/image_config.json b/layers/image_config.json
new file mode 100644
index 0000000..2f8b5d1
--- /dev/null
+++ b/layers/image_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "Image",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerImage.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/layers/mem_tracker_config.json b/layers/mem_tracker_config.json
new file mode 100644
index 0000000..d8ba59b
--- /dev/null
+++ b/layers/mem_tracker_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "MemTracker",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerMemTracker.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/layers/multi_config.json b/layers/multi_config.json
new file mode 100644
index 0000000..e864d43
--- /dev/null
+++ b/layers/multi_config.json
@@ -0,0 +1,19 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "multi1",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerMulti.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Sample multiple layer per library"
+    },
+    "layer" : {
+        "name": "multi2",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerMulti.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Sample multiple layer per library"
+    }
+}
diff --git a/layers/object_tracker_config.json b/layers/object_tracker_config.json
new file mode 100644
index 0000000..91e80b1
--- /dev/null
+++ b/layers/object_tracker_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "ObjectTracker",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerObjectTracker.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/layers/param_checker_config.json b/layers/param_checker_config.json
new file mode 100644
index 0000000..0917d5c
--- /dev/null
+++ b/layers/param_checker_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "ParamChecker",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerParamChecker.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/layers/screenshot_config.json b/layers/screenshot_config.json
new file mode 100644
index 0000000..b451532
--- /dev/null
+++ b/layers/screenshot_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "ScreenShot",
+        "type": "DEVICE",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerScreenShot.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG image capture layer"
+    }
+}
diff --git a/layers/shader_checker_config.json b/layers/shader_checker_config.json
new file mode 100644
index 0000000..cc18fbd
--- /dev/null
+++ b/layers/shader_checker_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "ShaderChecker",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerShaderChecker.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/layers/threading_config.json b/layers/threading_config.json
new file mode 100644
index 0000000..00dab20
--- /dev/null
+++ b/layers/threading_config.json
@@ -0,0 +1,11 @@
+{
+    "file_format_version" : "0.9.0",
+    "layer" : {
+        "name": "Threading",
+        "type": "GLOBAL",
+        "library_path": "/home/jon/vk/vk/dbuild/layers/libVKLayerThreading.so",
+        "abi_versions": "1.0.0",
+        "implementation_version": "1.0.0",
+        "description": "LunarG Validation Layer"
+    }
+}
diff --git a/loader/loader.c b/loader/loader.c
index f6997e2..d827ce8 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -229,104 +229,6 @@
     return out;
 }
 
-char *loader_get_registry_string(const HKEY hive,
-                                 const LPCTSTR sub_key,
-                                 const char *value)
-{
-    DWORD access_flags = KEY_QUERY_VALUE;
-    DWORD value_type;
-    HKEY key;
-    LONG rtn_value;
-    char *rtn_str = NULL;
-    DWORD rtn_len = 0;
-    size_t allocated_len = 0;
-
-    rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
-    if (rtn_value != ERROR_SUCCESS) {
-        // We didn't find the key.  Try the 32-bit hive (where we've seen the
-        // key end up on some people's systems):
-        access_flags |= KEY_WOW64_32KEY;
-        rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
-        if (rtn_value != ERROR_SUCCESS) {
-            // We still couldn't find the key, so give up:
-            return NULL;
-        }
-    }
-
-    rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
-                                (PVOID) rtn_str, (LPDWORD) &rtn_len);
-    if (rtn_value == ERROR_SUCCESS) {
-        // If we get to here, we found the key, and need to allocate memory
-        // large enough for rtn_str, and query again:
-        allocated_len = rtn_len + 4;
-        rtn_str = malloc(allocated_len);
-        rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
-                                    (PVOID) rtn_str, (LPDWORD) &rtn_len);
-        if (rtn_value == ERROR_SUCCESS) {
-            // We added 4 extra bytes to rtn_str, so that we can ensure that
-            // the string is NULL-terminated (albeit, in a brute-force manner):
-            rtn_str[allocated_len-1] = '\0';
-        } else {
-            // This should never occur, but in case it does, clean up:
-            free(rtn_str);
-            rtn_str = NULL;
-        }
-    } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
-
-    // Close the registry key that was opened:
-    RegCloseKey(key);
-
-    return rtn_str;
-}
-
-
-// For ICD developers, look in the registry, and look for an environment
-// variable for a path(s) where to find the ICD(s):
-static char *loader_get_registry_and_env(const char *env_var,
-                                         const char *registry_value)
-{
-    char *env_str = getenv(env_var);
-    size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
-    char *registry_str = NULL;
-    size_t registry_len = 0;
-    char *rtn_str = NULL;
-    size_t rtn_len;
-
-    registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
-                                              "Software\\Vulkan",
-                                              registry_value);
-    registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
-
-    rtn_len = env_len + registry_len + 1;
-    if (rtn_len <= 2) {
-        // We found neither the desired registry value, nor the environment
-        // variable; return NULL:
-        return NULL;
-    } else {
-        // We found something, and so we need to allocate memory for the string
-        // to return:
-        rtn_str = malloc(rtn_len);
-    }
-
-    if (registry_len == 0) {
-        // We didn't find the desired registry value, and so we must have found
-        // only the environment variable:
-        _snprintf(rtn_str, rtn_len, "%s", env_str);
-    } else if (env_str != NULL) {
-        // We found both the desired registry value and the environment
-        // variable, so concatenate them both:
-        _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
-    } else {
-        // We must have only found the desired registry value:
-        _snprintf(rtn_str, rtn_len, "%s", registry_str);
-    }
-
-    if (registry_str) {
-      free(registry_str);
-    }
-
-    return(rtn_str);
-}
 #endif // WIN32
 
 bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
@@ -334,7 +236,7 @@
     return strcmp(op1->extName, op2->extName) == 0 ? true : false;
 }
 
-/*
+/**
  * Search the given ext_array for an extension
  * matching the given vk_ext_prop
  */
@@ -350,7 +252,7 @@
     return false;
 }
 
-/*
+/**
  * Search the given ext_list for an extension
  * matching the given vk_ext_prop
  */
@@ -366,8 +268,7 @@
 }
 
 /*
- * Search the given layer list for a layer
- * matching the given layer name
+ * Search the given layer list for a layer matching the given layer name
  */
 static struct loader_layer_properties *get_layer_property(
         const char *name,
@@ -444,94 +345,6 @@
     return;
 }
 
-/* TODO: Need to use loader_heap_alloc or loader_stack_alloc */
-static void loader_add_global_layer_properties(
-        const char *lib_name,
-        const loader_platform_dl_handle lib_handle,
-        struct loader_layer_list *layer_list)
-{
-    uint32_t i, count;
-    VkLayerProperties *layer_properties;
-    PFN_vkGetGlobalExtensionProperties fp_get_ext_props;
-    PFN_vkGetGlobalLayerProperties fp_get_layer_props;
-    VkResult res;
-
-    /*
-     * A layer must export GetGlobalLayerProperties if it has any global extensions.
-     * If a layer does not export a vkGetGlobalLayerProperties then it may
-     * only support vkGetPhysicalDeviceLayerProperties and nothing needs to
-     * be done here.
-     */
-    fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
-    if (!fp_get_layer_props) {
-        loader_log(VK_DBG_REPORT_WARN_BIT, 0,
-                   "Couldn't dlsym vkGetGlobalLayerProperties from library %s",
-                   lib_name);
-        return;
-    }
-
-    fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalExtensionProperties");
-    if (!fp_get_ext_props) {
-        loader_log(VK_DBG_REPORT_WARN_BIT, 0,
-                   "Couldn't dlsym vkGetGlobalExtensionProperties from library %s",
-                   lib_name);
-    }
-
-    res = fp_get_layer_props(&count, NULL);
-    if (res != VK_SUCCESS) {
-        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global layer count from %s", lib_name);
-        return;
-    }
-
-    if (count == 0) {
-        /*
-         * Layer exported vkGetGlobalLayerProperties but didn't have any to report,
-         * nothing to do here.
-         */
-        return;
-    }
-
-    layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
-
-    res = fp_get_layer_props(&count, layer_properties);
-    if (res != VK_SUCCESS) {
-        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d global layer properties from %s. %s line %d",
-                   count, lib_name, __FILE__, __LINE__);
-        return;
-    }
-
-    for (i = 0; i < count; i++) {
-        struct loader_layer_properties layer;
-
-        memset(&layer, 0, sizeof(layer));
-
-        layer.lib_info.lib_name = malloc(strlen(lib_name) + 1);
-        if (layer.lib_info.lib_name == NULL) {
-            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "out of memory: layer library %s: %s line %d",
-                       lib_name, __FILE__, __LINE__);
-            return;
-        }
-
-        strcpy(layer.lib_info.lib_name, lib_name);
-        memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
-        loader_init_ext_list(&layer.instance_extension_list);
-        loader_init_ext_list(&layer.device_extension_list);
-        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for layer %s (%s)",
-                   layer.info.layerName, layer.info.description);
-
-        loader_add_global_extensions(
-                    fp_get_ext_props,
-                    lib_name,
-                    lib_handle,
-                    VK_EXTENSION_ORIGIN_LAYER,
-                    &layer.instance_extension_list);
-
-        loader_add_to_layer_list(layer_list, 1, &layer);
-    }
-
-    return;
-}
-
 static void loader_add_physical_device_extensions(
         PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
         VkPhysicalDevice physical_device,
@@ -632,6 +445,7 @@
         return;
     }
 
+    //TODO get layer properties from manifest file
     for (i = 0; i < count; i++) {
         struct loader_layer_properties layer;
 
@@ -707,8 +521,8 @@
 }
 
 /*
- * Append non-duplicate extension properties defined in prop_list
- * to the given ext_info list
+ * Append non-duplicate extension properties defined in props
+ * to the given ext_list.
  */
 void loader_add_to_ext_list(
         struct loader_extension_list *ext_list,
@@ -837,6 +651,7 @@
     }
 }
 
+#if 0
 /*
  * Add's library indicated by lib_name to list if it
  * implements vkGetGlobalLayerProperties or
@@ -874,7 +689,7 @@
 
     loader_add_to_layer_library_list(list, 1, library_info);
 }
-
+#endif
 /*
  * Search the given layer list for a list
  * matching the given VkLayerProperties
@@ -948,7 +763,7 @@
 
 /*
  * Search the search_list for any layer with
- * a name that matches the given layer_name.
+ * a name that matches the given name.
  * Add all matching layers to the found_list
  * Do not add if found VkLayerProperties is already
  * on the found_list.
@@ -1194,8 +1009,8 @@
     }
 
     /* Find and return global extension list for given layer */
-    for (uint32_t i = 0; i < loader.global_layer_list.count; i++) {
-        struct loader_layer_properties *work_layer = &loader.global_layer_list.list[i];
+    for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
+        struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
         if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
             return &work_layer->instance_extension_list;
         }
@@ -1204,9 +1019,9 @@
     return NULL;
 }
 
-static struct loader_layer_list *loader_global_layers()
+static struct loader_layer_list *loader_scanned_layers()
 {
-    return &loader.global_layer_list;
+    return &loader.scanned_layers;
 }
 
 static void loader_physical_device_layers(
@@ -1420,6 +1235,182 @@
 }
 
 /**
+ * Given a cJSON struct (json) of the top level JSON object from layer manifest
+ * file, add entry to the layer_list.
+ * Fill out the layer_properties in this list entry from the input cHJSON object.
+ *
+ * \returns
+ * void
+ * layer_list has a new entry and initialized accordingly.
+ * If the json input object does not have all the required fields no entry
+ * is added to the list.
+ */
+static void loader_add_layer_properties(struct loader_layer_list *layer_list,
+                                        cJSON *json,
+                                        bool is_implicit,
+                                        char *filename)
+{
+    /* Fields in layer manifest file that are required:
+     * (required) “file_format_version”
+     * following are required in the "layer" object:
+     * (required) "name"
+     * (required) "type"
+     * (required) “library_path”
+     * (required) “abi_versions”
+     * (required) “implementation_version”
+     * (required) “description”
+     * (required for implicit layers) “disable_environment”
+     *
+     * First get all required items and if any missing abort
+     */
+
+    cJSON *item, *layer_node, *ext_item;
+    char *temp;
+    char *name, *type, *library_path, *abi_versions;
+    char *implementation_version, *description;
+    cJSON *disable_environment;
+    int i;
+    struct loader_extension_property ext_prop;
+    item = cJSON_GetObjectItem(json, "file_format_version");
+    if (item == NULL) {
+        return;
+    }
+    char *file_vers = cJSON_PrintUnformatted(item);
+    loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
+               filename, file_vers);
+    if (strcmp(file_vers, "\"0.9.0\"") != 0)
+        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
+    free(file_vers);
+
+    //TODO handle multiple layer nodes in the file
+    //TODO handle scanned libraries not one per layer property
+    layer_node = cJSON_GetObjectItem(json, "layer");
+    if (layer_node == NULL) {
+        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
+        return;
+    }
+#define GET_JSON_OBJECT(node, var) {                  \
+        var = cJSON_GetObjectItem(node, #var);        \
+        if (var == NULL)                              \
+            return;                                   \
+        }
+#define GET_JSON_ITEM(node, var) {                    \
+        item = cJSON_GetObjectItem(node, #var);       \
+        if (item == NULL)                             \
+            return;                                   \
+        temp = cJSON_Print(item);                     \
+        temp[strlen(temp) - 1] = '\0';                \
+        var = malloc(strlen(temp) + 1);               \
+        strcpy(var, &temp[1]);                        \
+        free(temp);                                   \
+        }
+    GET_JSON_ITEM(layer_node, name)
+    GET_JSON_ITEM(layer_node, type)
+    GET_JSON_ITEM(layer_node, library_path)
+    GET_JSON_ITEM(layer_node, abi_versions)
+    GET_JSON_ITEM(layer_node, implementation_version)
+    GET_JSON_ITEM(layer_node, description)
+    if (is_implicit) {
+        GET_JSON_OBJECT(layer_node, disable_environment)
+    }
+#undef GET_JSON_ITEM
+#undef GET_JSON_OBJECT
+
+    // add list entry
+    assert((layer_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_list->capacity);
+    struct loader_layer_properties *props = &(layer_list->list[layer_list->count]);
+    strcpy(props->info.layerName, name);
+    //TODO string overflow
+    free(name);
+    if (!strcmp(type, "\"DEVICE\""))
+        props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
+    if (!strcmp(type, "\"INSTANCE\""))
+        props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
+    if (!strcmp(type, "\"GLOBAL\""))
+        props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
+    free(type);
+    //TODO handle relative paths  and filenames in addition to absolute path
+    props->lib_info.lib_name = library_path;
+    //TODO merge the info with the versions
+    props->abi_version = abi_versions;
+    props->impl_version = implementation_version;
+    //TODO string overflow
+    strcpy(props->info.description,description);
+    free(description);
+    if (is_implicit) {
+        props->disable_env_var.name = disable_environment->child->string;
+        props->disable_env_var.value = disable_environment->child->valuestring;
+    }
+    layer_list->count++;
+
+    /**
+     * Now get all optional items and objects and put in list:
+     * functions
+     * instance_extensions
+     * device_extensions
+     * enable_environment (implicit layers only)
+     */
+#define GET_JSON_OBJECT(node, var) {                  \
+        var = cJSON_GetObjectItem(node, #var);        \
+        }
+#define GET_JSON_ITEM(node, var) {                    \
+        item = cJSON_GetObjectItem(node, #var);       \
+        if (item != NULL)                             \
+            temp = cJSON_Print(item);                 \
+        temp[strlen(temp) - 1] = '\0';                \
+        var = malloc(strlen(temp) + 1);               \
+        strcpy(var, &temp[1]);                        \
+        free(temp);                                   \
+        }
+
+    cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
+    char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
+    GET_JSON_OBJECT(layer_node, functions)
+    if (functions != NULL) {
+        GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
+        GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
+        props->functions.str_gipa = vkGetInstanceProcAddr;
+        props->functions.str_gdpa = vkGetDeviceProcAddr;
+    }
+    GET_JSON_OBJECT(layer_node, instance_extensions)
+    if (instance_extensions != NULL) {
+        int count = cJSON_GetArraySize(instance_extensions);
+        for (i = 0; i < count; i++) {
+            ext_item = cJSON_GetArrayItem(instance_extensions, i);
+            GET_JSON_ITEM(ext_item, name)
+            GET_JSON_ITEM(ext_item, version)
+            ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
+            ext_prop.lib_name = library_path;
+            strcpy(ext_prop.info.extName, name);
+            //TODO convert from string to int ext_prop.info.version = version;
+            loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
+        }
+    }
+    GET_JSON_OBJECT(layer_node, device_extensions)
+    if (device_extensions != NULL) {
+        int count = cJSON_GetArraySize(device_extensions);
+        for (i = 0; i < count; i++) {
+            ext_item = cJSON_GetArrayItem(device_extensions, i);
+            GET_JSON_ITEM(ext_item, name);
+            GET_JSON_ITEM(ext_item, version);
+            ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
+            ext_prop.lib_name = library_path;
+            strcpy(ext_prop.info.extName, name);
+            //TODO convert from string to int ext_prop.info.version = version;
+            loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
+        }
+    }
+    if (is_implicit) {
+        GET_JSON_OBJECT(layer_node, enable_environment)
+        props->enable_env_var.name = enable_environment->child->string;
+        props->enable_env_var.value = enable_environment->child->valuestring;
+    }
+#undef GET_JSON_ITEM
+#undef GET_JSON_OBJECT
+
+}
+
+/**
  * Find the Vulkan library manifest files.
  *
  * This function scans the location or env_override directories/files
@@ -1612,18 +1603,30 @@
     // Get a list of manifest files for ICDs
     loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
                               &manifest_files);
+    if (manifest_files.count == 0)
+        return;
     for (uint32_t i = 0; i < manifest_files.count; i++) {
         file_str = manifest_files.filename_list[i];
         if (file_str == NULL)
             continue;
 
-        cJSON *json, *icd_json;
+        cJSON *json;
         json = loader_get_json(file_str);
-        icd_json = cJSON_GetObjectItem(json, "ICD");
-        if (icd_json != NULL) {
-            icd_json = cJSON_GetObjectItem(icd_json, "library_path");
-            if (icd_json != NULL) {
-                char *icd_filename = cJSON_PrintUnformatted(icd_json);
+        cJSON *item;
+        item = cJSON_GetObjectItem(json, "file_format_version");
+        if (item == NULL)
+            return;
+        char *file_vers = cJSON_Print(item);
+        loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
+                   file_str, file_vers);
+        if (strcmp(file_vers, "\"1.0.0\"") != 0)
+            loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
+        free(file_vers);
+        item = cJSON_GetObjectItem(json, "ICD");
+        if (item != NULL) {
+            item = cJSON_GetObjectItem(item, "library_path");
+            if (item != NULL) {
+                char *icd_filename = cJSON_PrintUnformatted(item);
                 char *icd_file = icd_filename;
                 if (icd_filename != NULL) {
                     char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
@@ -1659,57 +1662,19 @@
 
 void loader_layer_scan(void)
 {
-    uint32_t len;
-    const char *p, *next;
-    char *libPaths = NULL;
-    DIR *curdir;
-    struct dirent *dent;
-    char temp_str[1024];
+    char *file_str;
+    struct loader_manifest_files manifest_files;
+    cJSON *json;
+    uint32_t i;
 
-#if defined(WIN32)
-    bool must_free_libPaths;
-    libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
-                                           LAYERS_PATH_REGISTRY_VALUE);
-    if (libPaths != NULL) {
-        must_free_libPaths = true;
-    } else {
-        must_free_libPaths = false;
-        libPaths = DEFAULT_VK_LAYERS_PATH;
-    }
-#else  // WIN32
-    if (geteuid() == getuid()) {
-        /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
-        libPaths = getenv(LAYERS_PATH_ENV);
-    }
-    if (libPaths == NULL) {
-        libPaths = DEFAULT_VK_LAYERS_PATH;
-    }
-#endif // WIN32
-
-    if (libPaths == NULL) {
-        // Have no paths to search:
+    // Get a list of manifest files for layers
+    loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
+                              &manifest_files);
+    if (manifest_files.count == 0)
         return;
-    }
-    len = strlen(libPaths);
-    loader.layer_dirs = malloc(len+1);
-    if (loader.layer_dirs == NULL) {
-        loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
 
-        free(libPaths);
-        return;
-    }
-    // Alloc passed, so we know there is enough space to hold the string
-    strcpy(loader.layer_dirs, libPaths);
-#if defined(WIN32)
-    // Free any allocated memory:
-    if (must_free_libPaths) {
-        free(libPaths);
-        must_free_libPaths = false;
-    }
-#endif // WIN32
-    libPaths = loader.layer_dirs;
-
-    /*
+#if 0
+    /**
      * We need a list of the layer libraries, not just a list of
      * the layer properties (a layer library could expose more than
      * one layer property). This list of scanned layers would be
@@ -1720,63 +1685,61 @@
                    "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
         return;
     }
+#endif
 
-    for (p = libPaths; *p; p = next) {
-        next = strchr(p, PATH_SEPERATOR);
-        if (next == NULL) {
-            len = (uint32_t) strlen(p);
-            next = p + len;
+    // TODO use global_layer add and delete functions instead
+    if (loader.scanned_layers.capacity == 0) {
+        loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
+        if (loader.scanned_layers.list == NULL) {
+            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
+            return;
         }
-        else {
-            len = (uint32_t) (next - p);
-            *(char *) next = '\0';
-            next++;
+        memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
+        loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
+    }
+    else {
+        /* cleanup any previously scanned libraries */
+        //TODO make sure everything is cleaned up properly
+        for (i = 0; i < loader.scanned_layers.count; i++) {
+            if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
+                free(loader.scanned_layers.list[i].lib_info.lib_name);
+            loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
+            loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
+            loader.scanned_layers.list[i].lib_info.lib_name = NULL;
         }
+        loader.scanned_layers.count = 0;
+    }
 
-        curdir = opendir(p);
-        if (curdir) {
-            dent = readdir(curdir);
-            while (dent) {
-                /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
-                 * ending with VK_LIBRARY_SUFFIX
-                 */
-                if (!strncmp(dent->d_name,
-                             VK_LAYER_LIBRARY_PREFIX,
-                             VK_LAYER_LIBRARY_PREFIX_LEN)) {
-                    uint32_t nlen = (uint32_t) strlen(dent->d_name);
-                    const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
-                    if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
-                            !strncmp(suf,
-                                     VK_LIBRARY_SUFFIX,
-                                     VK_LIBRARY_SUFFIX_LEN)) {
-                        loader_platform_dl_handle handle;
-                        snprintf(temp_str, sizeof(temp_str),
-                                 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
-                        // Used to call: dlopen(temp_str, RTLD_LAZY)
-                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
-                                   "Attempt to open library: %s", temp_str);
-                        if ((handle = loader_platform_open_library(temp_str)) == NULL) {
-                            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
-                            dent = readdir(curdir);
-                            continue;
-                        }
-                        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
-                                   "Opened library: %s", temp_str);
+    for (i = 0; i < manifest_files.count; i++) {
+        file_str = manifest_files.filename_list[i];
+        if (file_str == NULL)
+            continue;
 
-                        /* TODO: Need instance pointer here */
-                        loader_add_layer_library(NULL, temp_str, handle, &loader.scanned_layer_libraries);
+        // parse file into JSON struct
+        json = loader_get_json(file_str);
+        if (!json) {
+            continue;
+        }
+        // ensure enough room to add an entry
+        if ((loader.scanned_layers.count + 1) * sizeof (struct loader_layer_properties)
+                > loader.scanned_layers.capacity) {
+            loader.scanned_layers.list = realloc(loader.scanned_layers.list,
+                    loader.scanned_layers.capacity * 2);
+            if (loader.scanned_layers.list == NULL) {
+                loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
+                        "realloc failed for scanned layers");
+                break;
+            }
+            loader.scanned_layers.capacity *= 2;
+        }
+        //TODO pass in implicit versus explicit bool
+        loader_add_layer_properties(&loader.scanned_layers, json, false, file_str);
 
-                        loader_add_global_layer_properties(temp_str, handle, &loader.global_layer_list);
+        free(file_str);
+        cJSON_Delete(json);
+    }
+    free(manifest_files.filename_list);
 
-                        loader_platform_close_library(handle);
-                    }
-                }
-
-                dent = readdir(curdir);
-            } // while (dir_entry)
-            closedir(curdir);
-        } // if (curdir))
-    } // for (libpaths)
 }
 
 static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
@@ -1922,6 +1885,12 @@
     loader.loaded_layer_lib_list = new_layer_lib_list;
 }
 
+
+/**
+ * Go through the search_list and find any layers which match type. If layer
+ * type match is found in then add it to ext_list.
+ */
+//TODO need to handle implict layer enable env var and disable env var
 static void loader_add_layer_implicit(
                 const enum layer_type type,
                 struct loader_layer_list *list,
@@ -2002,20 +1971,20 @@
     loader_add_layer_implicit(
                                 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
                                 &inst->activated_layer_list,
-                                &loader.global_layer_list);
+                                &loader.scanned_layers);
 
-    /* Add any layers specified via environment variable first */
+    /* Add any layers specified via environment variable next */
     loader_add_layer_env(
                             "VK_INSTANCE_LAYERS",
                             &inst->activated_layer_list,
-                            &loader.global_layer_list);
+                            &loader.scanned_layers);
 
     /* Add layers specified by the application */
     err = loader_add_layer_names_to_list(
                 &inst->activated_layer_list,
                 pCreateInfo->layerCount,
                 pCreateInfo->ppEnabledLayerNames,
-                &loader.global_layer_list);
+                &loader.scanned_layers);
 
     return err;
 }
@@ -2273,7 +2242,7 @@
         /* Not in global list, search layer extension lists */
         for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
             layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
-                                  &loader.global_layer_list);
+                                  &loader.scanned_layers);
 
             if (!layer_prop) {
                 /* Should NOT get here, loader_validate_layers
@@ -2520,9 +2489,9 @@
                                 icd->scanned_icds->lib_name,
                                 &icd->device_extension_cache[i]);
 
-                    for (uint32_t l = 0; l < loader.scanned_layer_libraries.count; l++) {
+                    for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
                         loader_platform_dl_handle lib_handle;
-                        char *lib_name = loader.scanned_layer_libraries.list[l].lib_name;
+                        char *lib_name = loader.scanned_layers.list[l].lib_info.lib_name;
 
                         lib_handle = loader_platform_open_library(lib_name);
                         if (lib_handle == NULL) {
@@ -2717,12 +2686,6 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    /*
-     * TODO: Must filter CreateInfo extension list to only
-     * those extensions supported by the ICD.
-     * TODO: Probably should verify that every extension is
-     * covered by either the ICD or some layer.
-     */
     res = loader_validate_layers(pCreateInfo->layerCount,
                            pCreateInfo->ppEnabledLayerNames,
                            &icd->layer_properties_cache);
@@ -2963,7 +2926,7 @@
     loader_platform_thread_lock_mutex(&loader_lock);
 
     struct loader_layer_list *layer_list;
-    layer_list = loader_global_layers();
+    layer_list = loader_scanned_layers();
 
     if (pProperties == NULL) {
         *pCount = layer_list->count;
diff --git a/loader/loader.h b/loader/loader.h
index 371a306..e240ce8 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -88,6 +88,8 @@
 };
 
 struct loader_layer_functions {
+    char *str_gipa;
+    char *str_gdpa;
     PFN_vkGetInstanceProcAddr get_instance_proc_addr;
     PFN_vkGetDeviceProcAddr get_device_proc_addr;
 };
@@ -95,6 +97,8 @@
 struct loader_layer_properties {
     VkLayerProperties info;
     enum layer_type type;
+    char *abi_version;
+    char *impl_version;
     struct loader_lib_info lib_info;
     struct loader_layer_functions functions;
     struct loader_extension_list instance_extension_list;
@@ -259,8 +263,8 @@
 
     char *layer_dirs;
 
-    struct loader_layer_library_list scanned_layer_libraries;
-    struct loader_layer_list global_layer_list;
+    // TODO use this struct loader_layer_library_list scanned_layer_libraries;
+    struct loader_layer_list scanned_layers;
 
     /* Keep track of all the extensions available via GetGlobalExtensionProperties */
     struct loader_extension_list global_extensions;
diff --git a/loader/trampoline.c b/loader/trampoline.c
index f196194..71943da 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -55,7 +55,7 @@
 
     res = loader_validate_layers(pCreateInfo->layerCount,
                                  pCreateInfo->ppEnabledLayerNames,
-                                 &loader.global_layer_list);
+                                 &loader.scanned_layers);
     if (res != VK_SUCCESS) {
         return res;
     }
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index c763765..0da826f 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -51,15 +51,8 @@
 // TODO: Need to handle different Linux distros
 #define DEFAULT_VK_DRIVERS_INFO "/usr/share/vulkan/icd.d:/etc/vulkan/icd.d"
 #define DEFAULT_VK_DRIVERS_PATH "/usr/lib/i386-linux-gnu/vulkan/icd:/usr/lib/x86_64-linux-gnu/vulkan/icd"
-#define LAYERS_PATH_ENV "LIBVK_LAYERS_PATH"
-#define VK_LAYER_LIBRARY_PREFIX "libVKLayer"
-#define VK_LAYER_LIBRARY_PREFIX_LEN 10
-#define VK_LIBRARY_SUFFIX ".so"
-#define VK_LIBRARY_SUFFIX_LEN 3
-#ifndef DEFAULT_VK_LAYERS_PATH
-// TODO: Are these good default locations?
-#define DEFAULT_VK_LAYERS_PATH ".:/usr/lib/i386-linux-gnu/vk:/usr/lib/x86_64-linux-gnu/vk"
-#endif
+#define DEFAULT_VK_LAYERS_INFO "/usr/share/vulkan/explicit_layer.d:/usr/share/vulkan/implicit_layer.d:/etc/vulkan/explicit_layer.d:/etc/vulkan/implicit_layer.d"
+#define LAYERS_PATH_ENV "VK_LAYER_DIRS"
 
 // C99:
 #define PRINTF_SIZE_T_SPECIFIER    "%zu"
@@ -177,19 +170,8 @@
 #define DEFAULT_VK_DRIVERS_INFO "SOFTWARE\\Khronos\\Vulkan\\Drivers"
 // TODO: Are these the correct paths
 #define DEFAULT_VK_DRIVERS_PATH "C:\\Windows\\System32;C:\\Windows\\SysWow64"
-// TODO/TBD: Is this an appropriate prefix for Windows?
-#define LAYERS_PATH_REGISTRY_VALUE "VK_LAYERS_PATH"
-#define LAYER_NAMES_REGISTRY_VALUE "VK_LAYER_NAMES"
-#define LAYERS_PATH_ENV "VK_LAYERS_PATH"
-// TODO/TBD: Is this an appropriate suffix for Windows?
-#define VK_LAYER_LIBRARY_PREFIX "VKLayer"
-#define VK_LAYER_LIBRARY_PREFIX_LEN 7
-#define VK_LIBRARY_SUFFIX ".dll"
-#define VK_LIBRARY_SUFFIX_LEN 4
-#ifndef DEFAULT_VK_LAYERS_PATH
-// TODO: Is this a good default location?
-#define DEFAULT_VK_LAYERS_PATH "C:\\Windows\\System32;C:\\Windows\\SysWow64"
-#endif //  DEFAULT_VK_LAYERS_PATH
+#define DEFAULT_VK_LAYERS_INFO "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers;SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers"
+#define LAYERS_PATH_ENV "VK_LAYERS_FOLDERS"
 
 // C99:
 // Microsoft didn't implement C99 in Visual Studio; but started adding it with