loader: Call down chain for vkEnumerateDeviceExtensionProperties

This allows layers to filter device extensions.
diff --git a/loader/loader.c b/loader/loader.c
index c348419..4363fd7 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -536,9 +536,44 @@
     return;
 }
 
+/*
+ * Initialize ext_list with the physical device extensions.
+ * The extension properties are passed as inputs in count and ext_props.
+ */
+static VkResult loader_init_physical_device_extensions(
+        const struct loader_instance *inst,
+        struct loader_physical_device *phys_dev,
+        uint32_t count,
+        VkExtensionProperties *ext_props,
+        struct loader_extension_list *ext_list)
+{
+    VkResult res;
+    uint32_t i;
+
+    if (!loader_init_ext_list(inst, ext_list)) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+
+    for (i = 0; i < count; i++) {
+        char spec_version[64];
+
+        snprintf(spec_version, sizeof (spec_version), "%d.%d.%d",
+                VK_MAJOR(ext_props[i].specVersion),
+                VK_MINOR(ext_props[i].specVersion),
+                VK_PATCH(ext_props[i].specVersion));
+        loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
+                "PhysicalDevice Extension: %s (%s) version %s",
+                ext_props[i].extensionName, phys_dev->this_icd->this_icd_lib->lib_name, spec_version);
+        res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
+        if (res != VK_SUCCESS)
+            return res;
+    }
+
+    return VK_SUCCESS;
+}
+
 static VkResult loader_add_physical_device_extensions(
         const struct loader_instance *inst,
-        PFN_vkEnumerateDeviceExtensionProperties get_phys_dev_ext_props,
         VkPhysicalDevice physical_device,
         const char *lib_name,
         struct loader_extension_list *ext_list)
@@ -547,35 +582,32 @@
     VkResult res;
     VkExtensionProperties *ext_props;
 
-    if (!get_phys_dev_ext_props) {
-        /* No EnumerateDeviceExtensionProperties defined */
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-        res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
-        if (res == VK_SUCCESS && count > 0) {
-            ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
-
-            res = get_phys_dev_ext_props(physical_device, NULL, &count, ext_props);
-            for (i = 0; i < count; i++) {
-                char spec_version[64];
-
-                snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
-                         VK_MAJOR(ext_props[i].specVersion),
-                         VK_MINOR(ext_props[i].specVersion),
-                         VK_PATCH(ext_props[i].specVersion));
-                loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
-                           "PhysicalDevice Extension: %s (%s) version %s",
-
-                           ext_props[i].extensionName, lib_name, spec_version);
-                res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
-                if (!res)
-                    return res;
-            }
-        } else {
-            loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from library %s", lib_name);
+    res = loader_EnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
+    if (res == VK_SUCCESS && count > 0) {
+        ext_props = loader_stack_alloc(count * sizeof (VkExtensionProperties));
+        if (!ext_props)
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        res = loader_EnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
+        if (res != VK_SUCCESS)
             return res;
+        for (i = 0; i < count; i++) {
+            char spec_version[64];
+
+            snprintf(spec_version, sizeof (spec_version), "%d.%d.%d",
+                    VK_MAJOR(ext_props[i].specVersion),
+                    VK_MINOR(ext_props[i].specVersion),
+                    VK_PATCH(ext_props[i].specVersion));
+            loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
+                    "PhysicalDevice Extension: %s (%s) version %s",
+                    ext_props[i].extensionName, lib_name, spec_version);
+            res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
+            if (res != VK_SUCCESS)
+                return res;
         }
+    } else {
+        loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from library %s", lib_name);
+        return res;
+    }
 
     return VK_SUCCESS;
 }
@@ -2784,30 +2816,8 @@
                 inst_phys_devs[idx].this_instance = ptr_instance;
                 inst_phys_devs[idx].this_icd = icd;
                 inst_phys_devs[idx].phys_dev = phys_devs[i].phys_devs[j];
+                memset(&inst_phys_devs[idx].device_extension_cache, 0, sizeof(struct loader_extension_list));
 
-                // convenient time to init this ICDs device extension list
-                if (!loader_init_ext_list(ptr_instance, &inst_phys_devs[idx].device_extension_cache)) {
-                    ptr_instance->total_gpu_count -= phys_devs[i].count - j;
-                    return VK_ERROR_OUT_OF_HOST_MEMORY;
-                }
-
-                res = loader_add_physical_device_extensions(
-                                ptr_instance,
-                                icd->EnumerateDeviceExtensionProperties,
-                                phys_devs[i].phys_devs[j],
-                                icd->this_icd_lib->lib_name,
-                                &inst_phys_devs[idx].device_extension_cache);
-
-                if (res != VK_SUCCESS) {
-                    /* clean up any extension lists previously created before this request failed */
-                    for (uint32_t k = 0; k < j; k++) {
-                        loader_destroy_ext_list(
-                                ptr_instance,
-                                &inst_phys_devs[idx - k - 1].device_extension_cache);
-                    }
-
-                    return res;
-                }
                 idx++;
             }
         } else
@@ -2970,6 +2980,20 @@
         }
     }
 
+    /* Get the physical device extensions if they haven't been retrieved yet */
+    if (phys_dev->device_extension_cache.capacity == 0) {
+        if (!loader_init_ext_list(inst, &phys_dev->device_extension_cache)) {
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+        res = loader_add_physical_device_extensions(
+                            inst, physicalDevice,
+                            phys_dev->this_icd->this_icd_lib->lib_name,
+                            &phys_dev->device_extension_cache);
+        if (res != VK_SUCCESS) {
+            return res;
+        }
+    }
+    /* make sure requested extensions to be enabled are supported */
     res = loader_validate_device_extensions(phys_dev, &inst->device_layer_list, pCreateInfo);
     if (res != VK_SUCCESS) {
         return res;
@@ -3260,7 +3284,17 @@
         }
     }
     else {
-        dev_ext_list = &phys_dev->device_extension_cache;
+        /* this case is during the call down the instance chain */
+        struct loader_icd *icd = phys_dev->this_icd;
+        VkResult res;
+        res = icd->EnumerateDeviceExtensionProperties(phys_dev->phys_dev, NULL, pPropertyCount, pProperties);
+        if (pProperties != NULL  && res == VK_SUCCESS) {
+            /* initialize dev_extension list within the physicalDevice object */
+            res = loader_init_physical_device_extensions(phys_dev->this_instance,
+                               phys_dev, *pPropertyCount, pProperties,
+                               &phys_dev->device_extension_cache);
+        }
+        return res;
     }
 
     count = (dev_ext_list == NULL) ? 0: dev_ext_list->count;
diff --git a/loader/loader.h b/loader/loader.h
index addfc01..829b2d1 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -185,8 +185,7 @@
     VkPhysicalDevice phys_dev;          // object from ICD
     /*
      * Fill in the cache of available device extensions from
-     * this physical device. This cache will be used to satisfy
-     * calls to EnumerateDeviceExtensionProperties
+     * this physical device. This cache can be used during CreateDevice
      */
     struct loader_extension_list device_extension_cache;
 };
diff --git a/loader/trampoline.c b/loader/trampoline.c
index b2ba34c..9f053c6 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -304,8 +304,20 @@
     VkResult res;
 
     loader_platform_thread_lock_mutex(&loader_lock);
-    //TODO convert over to using instance chain dispatch
-    res = loader_EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pPropertyCount, pProperties);
+
+    /* If pLayerName == NULL, then querying ICD extensions, pass this call
+       down the instance chain which will terminate in the ICD. This allows
+       layers to filter the extensions coming back up the chain.
+       If pLayerName != NULL then get layer extensions from manifest file.  */
+    if (pLayerName == NULL  || strlen(pLayerName) == 0) {
+        const VkLayerInstanceDispatchTable *disp;
+
+        disp = loader_get_instance_dispatch(physicalDevice);
+        res = disp->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pPropertyCount, pProperties);
+    } else {
+        res = loader_EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pPropertyCount, pProperties);
+    }
+
     loader_platform_thread_unlock_mutex(&loader_lock);
     return res;
 }
@@ -318,7 +330,9 @@
     VkResult res;
 
     loader_platform_thread_lock_mutex(&loader_lock);
-    //TODO convert over to using instance chain dispatch
+
+    /* Don't dispatch this call down the instance chain, want all device layers
+       enumerated and instance chain may not contain all device layers */
     res = loader_EnumerateDeviceLayerProperties(physicalDevice, pPropertyCount, pProperties);
     loader_platform_thread_unlock_mutex(&loader_lock);
     return res;