vulkan: Add vkGetGlobalExtensionInfo entrypoint
authorJon Ashburn <jon@lunarg.com>
Fri, 10 Apr 2015 20:33:07 +0000 (14:33 -0600)
committerChia-I Wu <olv@lunarg.com>
Thu, 16 Apr 2015 09:48:19 +0000 (17:48 +0800)
have loader use it to enumerate all extensions from layers and drivers.
Non-gode_gen layers also updated to include vkGetGlobalExtensionInfo

Includes verion info as part of GetExtensionSupport return data.

TODO: vk-layer-generate needs work

v2: do not check for non-existing ENABLE_WSI_X11 (olv)

13 files changed:
icd/nulldrv/VK_nulldrv.def
icd/nulldrv/nulldrv.c
include/vkLayer.h
include/vulkan.h
layers/basic.cpp
layers/draw_state.cpp
layers/mem_tracker.cpp
layers/multi.cpp
layers/param_checker.cpp
loader/loader.c
vk-generate.py
vk-layer-generate.py
vulkan.py

index 792fe6d..a2d0167 100644 (file)
@@ -30,6 +30,7 @@ EXPORTS
    vkCreateInstance
    vkEnumerateGpus
    vkDestroyInstance
+   vkGetGlobalExtensionInfo
    xcbCreateWindow
    xcbDestroyWindow
    xcbGetMessage
index 4d72b51..5dc99de 100644 (file)
@@ -1353,8 +1353,41 @@ ICD_EXPORT VkResult VKAPI vkGetGpuInfo(
     return VK_SUCCESS;
 }
 
+ICD_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = 0;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = 0;
+            if (pData == NULL)
+                return VK_SUCCESS;
+            else
+                return VK_ERROR_INVALID_EXTENSION;
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 ICD_EXPORT VkResult VKAPI vkGetExtensionSupport(
-    VkPhysicalGpu                            gpu_,
+    VkPhysicalGpu                               gpu_,
     const char*                                 pExtName)
 {
     NULLDRV_LOG_FUNC;
index 97c9b37..e58ccdc 100644 (file)
@@ -34,6 +34,7 @@ typedef struct VkLayerDispatchTable_
     PFN_vkGetGpuInfo GetGpuInfo;
     PFN_vkCreateDevice CreateDevice;
     PFN_vkDestroyDevice DestroyDevice;
+    PFN_vkGetGlobalExtensionInfo GetGlobalExtensionInfo;
     PFN_vkGetExtensionSupport GetExtensionSupport;
     PFN_vkEnumerateLayers EnumerateLayers;
     PFN_vkGetDeviceQueue GetDeviceQueue;
index bf581f2..0c85cb1 100644 (file)
@@ -89,6 +89,7 @@ VK_DEFINE_SUBCLASS_HANDLE(VkRenderPass, VkObject)
 
 #define VK_MAX_PHYSICAL_GPUS       16
 #define VK_MAX_PHYSICAL_GPU_NAME   256
+#define VK_MAX_EXTENSION_NAME      256
 
 #define VK_LOD_CLAMP_NONE       MAX_FLOAT
 #define VK_LAST_MIP_OR_SLICE    0xffffffff
@@ -670,6 +671,15 @@ typedef enum VkPhysicalGpuInfoType_
     VK_MAX_ENUM(VkPhysicalGpuInfoType)
 } VkPhysicalGpuInfoType;
 
+typedef enum VkExtensionInfoType_
+{
+    // Info type for vkGetGlobalExtensionInfo() and vkGetPhysicalDeviceExtensionInfo()
+    VK_EXTENSION_INFO_TYPE_COUNT                            = 0x00000000,
+    VK_EXTENSION_INFO_TYPE_PROPERTIES                       = 0x00000001,
+
+    //VK_ENUM_RANGE(EXTENSION_INFO_TYPE, COUNT, PROPERTIES)
+} VkExtensionInfoType;
+
 typedef enum VkFormatInfoType_
 {
     // Info type for vkGetFormatInfo()
@@ -1369,6 +1379,12 @@ typedef struct VkGpuCompatibilityInfo_
     VkFlags                                     compatibilityFlags; // VkGpuCompatibilityFlags
 } VkGpuCompatibilityInfo;
 
+typedef struct VkExtensionProperties_
+{
+    char                                        extName[VK_MAX_EXTENSION_NAME];     // extension name
+    uint32_t                                    version;                            // version of the extension specification
+} VkExtensionProperties;
+
 typedef struct VkApplicationInfo_
 {
     VkStructureType                             sType;              // Type of structure. Should be VK_STRUCTURE_TYPE_APPLICATION_INFO
@@ -2274,6 +2290,7 @@ typedef VkResult (VKAPI *PFN_vkGetGpuInfo)(VkPhysicalGpu gpu, VkPhysicalGpuInfoT
 typedef void *   (VKAPI *PFN_vkGetProcAddr)(VkPhysicalGpu gpu, const char * pName);
 typedef VkResult (VKAPI *PFN_vkCreateDevice)(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice);
 typedef VkResult (VKAPI *PFN_vkDestroyDevice)(VkDevice device);
+typedef VkResult (VKAPI *PFN_vkGetGlobalExtensionInfo)(VkExtensionInfoType infoType, uint32_t extensionIndex, size_t* pDataSize, void* pData);
 typedef VkResult (VKAPI *PFN_vkGetExtensionSupport)(VkPhysicalGpu gpu, const char* pExtName);
 typedef VkResult (VKAPI *PFN_vkEnumerateLayers)(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved);
 typedef VkResult (VKAPI *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueNodeIndex, uint32_t queueIndex, VkQueue* pQueue);
@@ -2420,6 +2437,11 @@ VkResult VKAPI vkDestroyDevice(
     VkDevice                                    device);
 
 // Extension discovery functions
+VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData);
 
 VkResult VKAPI vkGetExtensionSupport(
     VkPhysicalGpu                               gpu,
index 524bd40..d82c6c5 100644 (file)
@@ -61,6 +61,59 @@ VK_LAYER_EXPORT VkResult VKAPI vkLayerExtension1(VkDevice device)
     return VK_SUCCESS;
 }
 
+struct extProps {
+    uint32_t version;
+    const char * const name;
+};
+#define BASIC_LAYER_EXT_ARRAY_SIZE 2
+static const struct extProps basicExts[BASIC_LAYER_EXT_ARRAY_SIZE] = {
+    // TODO what is the version?
+    0x10, "Basic",
+    0x10, "vkLayerExtension1"
+};
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    VkResult result;
+
+    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = BASIC_LAYER_EXT_ARRAY_SIZE;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= BASIC_LAYER_EXT_ARRAY_SIZE)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = basicExts[extensionIndex].version;
+            strncpy(ext_props->extName, basicExts[extensionIndex].name,
+                                        VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)
 {
     VkResult result;
index 58db632..e74fa18 100644 (file)
@@ -1466,6 +1466,58 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
     return result;
 }
 
+struct extProps {
+    uint32_t version;
+    const char * const name;
+};
+#define DRAW_STATE_LAYER_EXT_ARRAY_SIZE 1
+static const struct extProps dsExts[DRAW_STATE_LAYER_EXT_ARRAY_SIZE] = {
+    // TODO what is the version?
+    0x10, "DrawState"
+};
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    VkResult result;
+
+    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = DRAW_STATE_LAYER_EXT_ARRAY_SIZE;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= DRAW_STATE_LAYER_EXT_ARRAY_SIZE)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = dsExts[extensionIndex].version;
+            strncpy(ext_props->extName, dsExts[extensionIndex].name,
+                                        VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)
 {
     VkResult result;
index 86fd02d..e7f1f7e 100644 (file)
@@ -864,6 +864,58 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
     return result;
 }
 
+struct extProps {
+    uint32_t version;
+    const char * const name;
+};
+#define MEM_TRACKER_LAYER_EXT_ARRAY_SIZE 1
+static const struct extProps mtExts[MEM_TRACKER_LAYER_EXT_ARRAY_SIZE] = {
+    // TODO what is the version?
+    0x10, "MemTracker"
+};
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    VkResult result;
+
+    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = MEM_TRACKER_LAYER_EXT_ARRAY_SIZE;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= MEM_TRACKER_LAYER_EXT_ARRAY_SIZE)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = mtExts[extensionIndex].version;
+            strncpy(ext_props->extName, mtExts[extensionIndex].name,
+                                        VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)
 {
     VkResult result;
index 910bc5b..c590620 100644 (file)
@@ -283,6 +283,60 @@ VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLa
     return VK_SUCCESS;
 }
 
+struct extProps {
+    uint32_t version;
+    const char * const name;
+};
+
+#define MULTI_LAYER_EXT_ARRAY_SIZE 2
+static const struct extProps multiExts[MULTI_LAYER_EXT_ARRAY_SIZE] = {
+    // TODO what is the version?
+    0x10, "multi1",
+    0x10, "multi2",
+};
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    VkResult result;
+
+    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = MULTI_LAYER_EXT_ARRAY_SIZE;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= MULTI_LAYER_EXT_ARRAY_SIZE)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = multiExts[extensionIndex].version;
+            strncpy(ext_props->extName, multiExts[extensionIndex].name,
+                                        VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)
 {
     VkResult result;
index 5687a54..e7c7e63 100644 (file)
@@ -257,6 +257,59 @@ VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
     return result;
 }
 
+struct extProps {
+    uint32_t version;
+    const char * const name;
+};
+
+#define PARAM_CHECKER_LAYER_EXT_ARRAY_SIZE 1
+static const struct extProps pcExts[PARAM_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
+    // TODO what is the version?
+    0x10, "ParamChecker",
+};
+
+VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
+{
+    VkResult result;
+
+    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
+
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = PARAM_CHECKER_LAYER_EXT_ARRAY_SIZE;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= PARAM_CHECKER_LAYER_EXT_ARRAY_SIZE)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = pcExts[extensionIndex].version;
+            strncpy(ext_props->extName, pcExts[extensionIndex].name,
+                                        VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
+}
+
 VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)
 {
     pCurObj = (VkBaseLayerObject *) gpu;
index dc05376..3ce99f0 100644 (file)
@@ -58,6 +58,12 @@ struct layer_name_pair {
     const char *lib_name;
 };
 
+struct extension_property {
+    char extName[VK_MAX_EXTENSION_NAME];
+    uint32_t version;
+    bool hosted;            // does the extension reside in one driver/layer
+};
+
 struct loader_icd {
     const struct loader_scanned_icds *scanned_icds;
 
@@ -74,15 +80,23 @@ struct loader_icd {
 
 struct loader_scanned_icds {
     loader_platform_dl_handle handle;
+
     PFN_vkGetProcAddr GetProcAddr;
     PFN_vkCreateInstance CreateInstance;
     PFN_vkDestroyInstance DestroyInstance;
     PFN_vkEnumerateGpus EnumerateGpus;
-    PFN_vkGetExtensionSupport GetExtensionSupport;
+    PFN_vkGetGlobalExtensionInfo GetGlobalExtensionInfo;
     VkInstance instance;
     struct loader_scanned_icds *next;
+    uint32_t extension_count;
+    struct extension_property *extensions;
 };
 
+struct loader_scanned_layers {
+    char *name;
+    uint32_t extension_count;
+    struct extension_property *extensions;
+};
 // Note: Since the following is a static structure, all members are initialized
 // to zero.
 static struct {
@@ -92,9 +106,15 @@ static struct {
     bool layer_scanned;
     char *layer_dirs;
     unsigned int scanned_layer_count;
-    char *scanned_layer_names[MAX_LAYER_LIBRARIES];
+    struct loader_scanned_layers scanned_layers[MAX_LAYER_LIBRARIES];
+    size_t scanned_ext_list_capacity;
+    uint32_t scanned_ext_list_count;      // coalesced from all layers/drivers
+    struct extension_property **scanned_ext_list;
 } loader;
 
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
 
 #if defined(WIN32)
 char *loader_get_registry_string(const HKEY hive,
@@ -216,15 +236,145 @@ static void loader_log(VK_DBG_MSG_TYPE msg_type, int32_t msg_code,
     fputc('\n', stderr);
 }
 
-static void
-loader_icd_destroy(struct loader_icd *icd)
+static bool has_extension(struct extension_property *exts, uint32_t count,
+                          const char *name, bool must_be_hosted)
+{
+    uint32_t i;
+    for (i = 0; i < count; i++) {
+        if (!strcmp(name, exts[i].extName) && (!must_be_hosted || exts[i].hosted))
+            return true;
+    }
+    return false;
+}
+
+static void get_global_extensions(PFN_vkGetGlobalExtensionInfo fp_get,
+                                  uint32_t *count_out,
+                                  struct extension_property **props_out)
+{
+    uint32_t i, count, cur;
+    size_t siz = sizeof(count);
+    struct extension_property *ext_props;
+    VkExtensionProperties vk_prop;
+    VkResult res;
+
+    *count_out = 0;
+    *props_out = NULL;
+    res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
+    if (res != VK_SUCCESS) {
+        loader_log(VK_DBG_MSG_WARNING, 0, "Error getting global extension count from ICD");
+        return;
+    }
+    ext_props = (struct extension_property *) malloc(sizeof(struct extension_property) * count);
+    if (ext_props == NULL) {
+        loader_log(VK_DBG_MSG_WARNING, 0, "Out of memory didn't get global extensions from ICD");
+        return;
+    }
+    siz = sizeof(VkExtensionProperties);
+    cur = 0;
+    for (i = 0; i < count; i++) {
+        res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &vk_prop);
+        if (res == VK_SUCCESS) {
+            (ext_props + cur)->hosted = false;
+            (ext_props + cur)->version = vk_prop.version;
+            strncpy((ext_props + cur)->extName, vk_prop.extName, VK_MAX_EXTENSION_NAME);
+            (ext_props + cur)->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            cur++;
+        }
+        *count_out = cur;
+        *props_out = ext_props;
+    }
+    return;
+}
+
+static void loader_init_ext_list()
+{
+    loader.scanned_ext_list_capacity = 256 * sizeof(struct extension_property *);
+    loader.scanned_ext_list = malloc(loader.scanned_ext_list_capacity);
+    memset(loader.scanned_ext_list, 0, loader.scanned_ext_list_capacity);
+    loader.scanned_ext_list_count = 0;
+}
+
+#if 0 // currently no place to call this
+static void loader_destroy_ext_list()
+{
+    free(loader.scanned_ext_list);
+    loader.scanned_ext_list_capacity = 0;
+    loader.scanned_ext_list_count = 0;
+}
+#endif
+
+static void loader_add_to_ext_list(uint32_t count,
+                                   struct extension_property *prop_list)
+{
+    uint32_t i, j;
+    bool duplicate;
+    struct extension_property *cur_ext;
+
+    if (loader.scanned_ext_list == NULL || loader.scanned_ext_list_capacity == 0)
+        loader_init_ext_list();
+
+    if (loader.scanned_ext_list == NULL)
+        return;
+
+    struct extension_property *ext_list, **ext_list_addr;
+
+    for (i = 0; i < count; i++) {
+        cur_ext = prop_list + i;
+
+        // look for duplicates or not
+        duplicate = false;
+        for (j = 0; j < loader.scanned_ext_list_count; j++) {
+            ext_list = loader.scanned_ext_list[j];
+            if (!strcmp(cur_ext->extName, ext_list->extName)) {
+                duplicate = true;
+                ext_list->hosted = false;
+                break;
+            }
+        }
+
+        // add to list at end
+        if (!duplicate) {
+            // check for enough capacity
+            if (loader.scanned_ext_list_count * sizeof(struct extension_property *)
+                            >= loader.scanned_ext_list_capacity) {
+                // double capacity
+                loader.scanned_ext_list_capacity *= 2;
+                loader.scanned_ext_list = realloc(loader.scanned_ext_list,
+                        loader.scanned_ext_list_capacity);
+            }
+            ext_list_addr = &(loader.scanned_ext_list[loader.scanned_ext_list_count++]);
+            *ext_list_addr = cur_ext;
+            cur_ext->hosted = true;
+        }
+
+    }
+}
+
+static void loader_coalesce_extensions()
+{
+    uint32_t i;
+    struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
+
+    // traverse scanned icd list adding non-duplicate extensions to the list
+    while (icd_list != NULL) {
+        loader_add_to_ext_list(icd_list->extension_count, icd_list->extensions);
+        icd_list = icd_list->next;
+    };
+
+    //Traverse layers list adding non-duplicate extensions to the list
+    for (i = 0; i < loader.scanned_layer_count; i++) {
+        loader_add_to_ext_list(loader.scanned_layers[i].extension_count,
+                loader.scanned_layers[i].extensions);
+    }
+}
+
+static void loader_icd_destroy(struct loader_icd *icd)
 {
     loader_platform_close_library(icd->scanned_icds->handle);
     free(icd);
 }
 
-static struct loader_icd *
-loader_icd_create(const struct loader_scanned_icds *scanned)
+static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
 {
     struct loader_icd *icd;
 
@@ -258,7 +408,8 @@ static struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst,
 static void loader_scanned_icd_add(const char *filename)
 {
     loader_platform_dl_handle handle;
-    void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst, *fp_get_extension_support;
+    void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst;
+    void *fp_get_global_ext_info;
     struct loader_scanned_icds *new_node;
 
     // Used to call: dlopen(filename, RTLD_LAZY);
@@ -280,7 +431,7 @@ static void loader_scanned_icd_add(const char *filename)
     LOOKUP(fp_create_inst, CreateInstance);
     LOOKUP(fp_destroy_inst, DestroyInstance);
     LOOKUP(fp_enumerate, EnumerateGpus);
-    LOOKUP(fp_get_extension_support, GetExtensionSupport);
+    LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
 #undef LOOKUP
 
     new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds));
@@ -294,11 +445,21 @@ static void loader_scanned_icd_add(const char *filename)
     new_node->CreateInstance = fp_create_inst;
     new_node->DestroyInstance = fp_destroy_inst;
     new_node->EnumerateGpus = fp_enumerate;
-    new_node->GetExtensionSupport = fp_get_extension_support;
+    new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
+    new_node->extension_count = 0;
+    new_node->extensions = NULL;
     new_node->next = loader.scanned_icd_list;
+
     loader.scanned_icd_list = new_node;
-}
 
+    if (fp_get_global_ext_info) {
+        get_global_extensions((PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
+                       &new_node->extension_count,
+                       &new_node->extensions);
+    } else {
+        loader_log(VK_DBG_MSG_WARNING, 0, "Couldn't get global extensions from ICD");
+    }
+}
 
 /**
  * Try to \c loader_icd_scan VK driver(s).
@@ -401,6 +562,8 @@ static void layer_lib_scan(void)
     struct dirent *dent;
     size_t len, i;
     char temp_str[1024];
+    uint32_t count;
+    PFN_vkGetGlobalExtensionInfo fp_get_ext;
 
 #if defined(WIN32)
     bool must_free_libPaths;
@@ -446,23 +609,27 @@ static void layer_lib_scan(void)
 
     /* cleanup any previously scanned libraries */
     for (i = 0; i < loader.scanned_layer_count; i++) {
-        if (loader.scanned_layer_names[i] != NULL)
-            free(loader.scanned_layer_names[i]);
-        loader.scanned_layer_names[i] = NULL;
+        if (loader.scanned_layers[i].name != NULL)
+            free(loader.scanned_layers[i].name);
+        if (loader.scanned_layers[i].extensions != NULL)
+            free(loader.scanned_layers[i].extensions);
+        loader.scanned_layers[i].name = NULL;
+        loader.scanned_layers[i].extensions = NULL;
     }
     loader.scanned_layer_count = 0;
+    count = 0;
 
     for (p = libPaths; *p; p = next) {
-       next = strchr(p, PATH_SEPERATOR);
-       if (next == NULL) {
-          len = (uint32_t) strlen(p);
-          next = p + len;
-       }
-       else {
-          len = (uint32_t) (next - p);
-          *(char *) next = '\0';
-          next++;
-       }
+        next = strchr(p, PATH_SEPERATOR);
+        if (next == NULL) {
+           len = (uint32_t) strlen(p);
+           next = p + len;
+        }
+        else {
+           len = (uint32_t) (next - p);
+           *(char *) next = '\0';
+           next++;
+        }
 
        curdir = opendir(p);
        if (curdir) {
@@ -481,32 +648,58 @@ static void layer_lib_scan(void)
                               VK_LIBRARY_SUFFIX,
                               VK_LIBRARY_SUFFIX_LEN)) {
                      loader_platform_dl_handle handle;
-                     snprintf(temp_str, sizeof(temp_str), "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
+                     snprintf(temp_str, sizeof(temp_str),
+                              "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
                      // Used to call: dlopen(temp_str, RTLD_LAZY)
                      if ((handle = loader_platform_open_library(temp_str)) == NULL) {
                          dent = readdir(curdir);
                          continue;
                      }
-                     if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
-                         loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
+                     if (count == MAX_LAYER_LIBRARIES) {
+                         loader_log(VK_DBG_MSG_ERROR, 0,
+                                    "%s ignored: max layer libraries exceed",
+                                    temp_str);
                          break;
                      }
-                     if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
+                     fp_get_ext = loader_platform_get_proc_address(handle,
+                                               "vkGetGlobalExtensionInfo");
+
+                     if (!fp_get_ext) {
+                        loader_log(VK_DBG_MSG_WARNING, 0,
+                              "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
+                               temp_str);
+                        dent = readdir(curdir);
+                        loader_platform_close_library(handle);
+                        continue;
+                     }
+
+                     loader.scanned_layers[count].name =
+                                                   malloc(strlen(temp_str) + 1);
+                     if (loader.scanned_layers[count].name == NULL) {
                          loader_log(VK_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
                          break;
                      }
-                     strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
-                     loader.scanned_layer_count++;
-                     loader_platform_close_library(handle);
+
+                     get_global_extensions(fp_get_ext,
+                             &loader.scanned_layers[count].extension_count,
+                             &loader.scanned_layers[count].extensions);
+
+
+                    strcpy(loader.scanned_layers[count].name, temp_str);
+                    count++;
+                    loader_platform_close_library(handle);
                  }
              }
 
              dent = readdir(curdir);
-          }
+          } // while (dir_entry)
+          if (count == MAX_LAYER_LIBRARIES)
+             break;
           closedir(curdir);
-       }
-    }
+       } // if (curdir))
+    } // for (libpaths)
 
+    loader.scanned_layer_count = count;
     loader.layer_scanned = true;
 }
 
@@ -578,62 +771,38 @@ static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, s
     }
 }
 
-static VkResult find_layer_extension(struct loader_icd *icd, uint32_t gpu_index, const char *pExtName, const char **lib_name)
+static bool find_layer_extension(struct loader_icd *icd, uint32_t gpu_index, const char *pExtName, const char **lib_name)
 {
-    VkResult err;
     char *search_name;
-    loader_platform_dl_handle handle;
-    PFN_vkGetExtensionSupport fpGetExtensionSupport;
+    uint32_t j;
 
     /*
      * The loader provides the abstraction that make layers and extensions work via
      * the currently defined extension mechanism. That is, when app queries for an extension
-     * via vkGetExtensionSupport, the loader will call both the driver as well as any layers
+     * via vkGetGlobalExtensionInfo, the loader will call both the driver as well as any layers
      * to see who implements that extension. Then, if the app enables the extension during
-     * vkCreateDevice the loader will find and load any layers that implement that extension.
+     * vkCreateInstance the loader will find and load any layers that implement that extension.
      */
 
-    // TODO: What if extension is in multiple places?
+    // TODO: what about GetPhysicalDeviceExtension for device specific layers/extensions
 
-    // TODO: Who should we ask first? Driver or layers? Do driver for now.
-    err = icd->scanned_icds[gpu_index].GetExtensionSupport((VkPhysicalGpu) (icd->gpus[gpu_index].nextObject), pExtName);
-    if (err == VK_SUCCESS) {
+    for (j = 0; j < loader.scanned_layer_count; j++) {
         if (lib_name) {
-            *lib_name = NULL;
+            *lib_name = loader.scanned_layers[j].name;
         }
-        return VK_SUCCESS;
-    }
+        if (has_extension(loader.scanned_layers[j].extensions,
+                          loader.scanned_layers[j].extension_count, pExtName,
+                          true))
 
-    for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
-        search_name = loader.scanned_layer_names[j];
+            return true;
 
-        if ((handle = loader_platform_open_library(search_name)) == NULL)
-            continue;
-
-        fpGetExtensionSupport = loader_platform_get_proc_address(handle, "vkGetExtensionSupport");
-
-        if (fpGetExtensionSupport != NULL) {
-            // Found layer's GetExtensionSupport call
-            err = fpGetExtensionSupport((VkPhysicalGpu) (icd->gpus + gpu_index), pExtName);
-
-            loader_platform_close_library(handle);
-
-            if (err == VK_SUCCESS) {
-                if (lib_name) {
-                    *lib_name = loader.scanned_layer_names[j];
-                }
-                return VK_SUCCESS;
-            }
-        } else {
-            loader_platform_close_library(handle);
-        }
-
-        // No GetExtensionSupport or GetExtensionSupport returned invalid extension
-        // for the layer, so test the layer name as if it is an extension name
-        // use default layer name based on library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
+        // Extension not found in list for the layer, so test the layer name
+        // as if it is an extension name. Use default layer name based on
+        // library name VK_LAYER_LIBRARY_PREFIX<name>.VK_LIBRARY_SUFFIX
         char *pEnd;
         size_t siz;
 
+        search_name = loader.scanned_layers[j].name;
         search_name = basename(search_name);
         search_name += strlen(VK_LAYER_LIBRARY_PREFIX);
         pEnd = strrchr(search_name, '.');
@@ -642,13 +811,13 @@ static VkResult find_layer_extension(struct loader_icd *icd, uint32_t gpu_index,
             continue;
 
         if (strncmp(search_name, pExtName, siz) == 0) {
-            if (lib_name) {
-                *lib_name = loader.scanned_layer_names[j];
-            }
-            return VK_SUCCESS;
+            return true;
         }
     }
-    return VK_ERROR_INVALID_EXTENSION;
+    if (lib_name) {
+       *lib_name = NULL;
+    }
+    return false;
 }
 
 static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames)
@@ -691,7 +860,7 @@ static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index,
             next++;
         }
         name = basename(p);
-        if (find_layer_extension(icd, gpu_index, name, &lib_name) != VK_SUCCESS) {
+        if (!find_layer_extension(icd, gpu_index, name, &lib_name)) {
             p = next;
             continue;
         }
@@ -727,7 +896,7 @@ static uint32_t loader_get_layer_libs(struct loader_icd *icd, uint32_t gpu_index
     for (uint32_t i = 0; i < ext_count; i++) {
         const char *pExtName = ext_names[i];
 
-        if (find_layer_extension(icd, gpu_index, pExtName, &lib_name) == VK_SUCCESS) {
+        if (find_layer_extension(icd, gpu_index, pExtName, &lib_name)) {
             uint32_t len;
 
             /*
@@ -860,8 +1029,6 @@ LOADER_EXPORT VkResult VKAPI vkCreateInstance(
         const VkInstanceCreateInfo*         pCreateInfo,
         VkInstance*                           pInstance)
 {
-    static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
-    static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
     struct loader_instance *ptr_instance = NULL;
     struct loader_scanned_icds *scanned_icds;
     struct loader_icd *icd;
@@ -874,6 +1041,9 @@ LOADER_EXPORT VkResult VKAPI vkCreateInstance(
     /* get layer libraries in a single-threaded manner */
     loader_platform_thread_once(&once_layer, layer_lib_scan);
 
+    /* merge any duplicate extensions */
+    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
+
     ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance));
     if (ptr_instance == NULL) {
         return VK_ERROR_OUT_OF_MEMORY;
@@ -1060,18 +1230,60 @@ LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName)
     }
 }
 
-#if 0
-LOADER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char *pExtName)
+//TODO make sure createInstance enables extensions that are valid (loader does)
+//TODO make sure CreateDevice enables extensions that are valid (left for layers/drivers to do)
+
+//TODO how is layer extension going to be enabled?
+//Need to call createInstance on the layer or something
+
+LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
+                                               VkExtensionInfoType infoType,
+                                               uint32_t extensionIndex,
+                                               size_t*  pDataSize,
+                                               void*    pData)
 {
-    uint32_t gpu_index;
-    struct loader_icd *icd = loader_get_icd((const VkBaseLayerObject *) gpu, &gpu_index);
+    VkExtensionProperties *ext_props;
+    uint32_t *count;
+    /* Scan/discover all ICD libraries in a single-threaded manner */
+    loader_platform_thread_once(&once_icd, loader_icd_scan);
 
-    if (!icd)
-        return VK_ERROR_UNAVAILABLE;
+    /* get layer libraries in a single-threaded manner */
+    loader_platform_thread_once(&once_layer, layer_lib_scan);
+
+    /* merge any duplicate extensions */
+    loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
+
+
+    if (pDataSize == NULL)
+        return VK_ERROR_INVALID_POINTER;
 
-    return find_layer_extension(icd, gpu_index, pExtName, NULL);
+    switch (infoType) {
+        case VK_EXTENSION_INFO_TYPE_COUNT:
+            *pDataSize = sizeof(uint32_t);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            count = (uint32_t *) pData;
+            *count = loader.scanned_ext_list_count;
+            break;
+        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
+            *pDataSize = sizeof(VkExtensionProperties);
+            if (pData == NULL)
+                return VK_SUCCESS;
+            if (extensionIndex >= loader.scanned_ext_list_count)
+                return VK_ERROR_INVALID_VALUE;
+            ext_props = (VkExtensionProperties *) pData;
+            ext_props->version = loader.scanned_ext_list[extensionIndex]->version;
+            strncpy(ext_props->extName, loader.scanned_ext_list[extensionIndex]->extName
+                                            , VK_MAX_EXTENSION_NAME);
+            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
+            break;
+        default:
+            loader_log(VK_DBG_MSG_WARNING, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
+            return VK_ERROR_INVALID_VALUE;
+    };
+
+    return VK_SUCCESS;
 }
-#endif
 
 LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
 {
@@ -1094,7 +1306,7 @@ LOADER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLaye
          layers[i] = &layer_buf[i][0];
 
     for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
-        lib_name = loader.scanned_layer_names[j];
+        lib_name = loader.scanned_layers[j].name;
         // Used to call: dlopen(*lib_name, RTLD_LAZY)
         if ((handle = loader_platform_open_library(lib_name)) == NULL)
             continue;
index af80709..41ead48 100755 (executable)
@@ -33,6 +33,7 @@ def generate_get_proc_addr_check(name):
     return "    if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
            "        return NULL;" % ((name,) * 3)
 
+
 class Subcommand(object):
     def __init__(self, argv):
         self.argv = argv
@@ -42,6 +43,12 @@ class Subcommand(object):
     def run(self):
         print(self.generate())
 
+    def is_dispatchable_object_first_param(self, proto):
+        in_objs = proto.object_in_params()
+        non_dispatch_objs = ["VkInstance"]
+        param0 = proto.params[0]
+        return (len(in_objs) > 0)  and (in_objs[0].ty == param0.ty) and (param0.ty not in non_dispatch_objs)
+
     def generate(self):
         copyright = self.generate_copyright()
         header = self.generate_header()
@@ -100,14 +107,11 @@ class LoaderEntrypointsSubcommand(Subcommand):
     def generate_header(self):
         return "#include \"loader.h\""
 
-    def _is_dispatchable(self, proto):
-        if proto.name in ["GetProcAddr", "DestroyInstance", "EnumerateGpus",
-                "EnumerateLayers", "DbgRegisterMsgCallback",
-                "DbgUnregisterMsgCallback", "DbgSetGlobalOption"]:
-            return False
+    def _is_loader_special_case(self, proto):
+        if proto.name in ["GetProcAddr", "EnumerateGpus", "EnumerateLayers"]:
+            return True
 
-        in_objs = proto.object_in_params()
-        return in_objs and in_objs[0] == proto.params[0]
+        return not self.is_dispatchable_object_first_param(proto)
 
     def _generate_object_setup(self, proto):
         method = "loader_init_data"
@@ -144,7 +148,7 @@ class LoaderEntrypointsSubcommand(Subcommand):
 
         funcs = []
         for proto in self.protos:
-            if not self._is_dispatchable(proto):
+            if self._is_loader_special_case(proto):
                 continue
             func = []
 
@@ -214,7 +218,7 @@ class DispatchTableOpsSubcommand(Subcommand):
             if proto.name == "GetProcAddr":
                 stmts.append("table->%s = gpa; /* direct assignment */" %
                         proto.name)
-            else:
+            elif self.is_dispatchable_object_first_param(proto):
                 stmts.append("table->%s = (PFN_vk%s) gpa(gpu, \"vk%s\");" %
                         (proto.name, proto.name, proto.name))
         stmts.append("#endif")
@@ -237,8 +241,9 @@ class DispatchTableOpsSubcommand(Subcommand):
         for proto in self.protos:
             if 'WsiX11AssociateConnection' == proto.name:
                 lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
-            lookups.append("if (!strcmp(name, \"%s\"))" % (proto.name))
-            lookups.append("    return (void *) table->%s;"
+            if self.is_dispatchable_object_first_param(proto):
+                lookups.append("if (!strcmp(name, \"%s\"))" % (proto.name))
+                lookups.append("    return (void *) table->%s;"
                     % (proto.name))
         lookups.append("#endif")
 
index e95729f..1b7ebd9 100755 (executable)
@@ -194,48 +194,52 @@ class Subcommand(object):
         ur_body.append('}')
         return "\n".join(ur_body)
 
-    def _gen_layer_get_extension_support(self, layer="Generic"):
-        ges_body = []
-        ges_body.append('VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)')
-        ges_body.append('{')
-        ges_body.append('    VkResult result;')
-        ges_body.append('')
-        ges_body.append('    /* This entrypoint is NOT going to init its own dispatch table since loader calls here early */')
-        ges_body.append('    if (!strncmp(pExtName, "%s", strlen("%s")))' % (layer, layer))
-        ges_body.append('    {')
-        ges_body.append('        result = VK_SUCCESS;')
-        ges_body.append('    } else if (nextTable.GetExtensionSupport != NULL)')
-        ges_body.append('    {')
-        ges_body.append('        result = nextTable.GetExtensionSupport(gpu, pExtName);')
-        ges_body.append('    } else')
-        ges_body.append('    {')
-        ges_body.append('        result = VK_ERROR_INVALID_EXTENSION;')
-        ges_body.append('    }')
-        ges_body.append('    return result;')
-        ges_body.append('}')
-        return "\n".join(ges_body)
-
-    def _gen_layer_get_extension_support(self, layer="Generic"):
-        ges_body = []
-        ges_body.append('VK_LAYER_EXPORT VkResult VKAPI vkGetExtensionSupport(VkPhysicalGpu gpu, const char* pExtName)')
-        ges_body.append('{')
-        ges_body.append('    VkResult result;')
-        ges_body.append('    VK_BASE_LAYER_OBJECT* gpuw = (VK_BASE_LAYER_OBJECT *) gpu;')
-        ges_body.append('')
-        ges_body.append('    /* This entrypoint is NOT going to init its own dispatch table since loader calls here early */')
-        ges_body.append('    if (!strncmp(pExtName, "%s", strlen("%s")))' % (layer, layer))
-        ges_body.append('    {')
-        ges_body.append('        result = VK_SUCCESS;')
-        ges_body.append('    } else if (nextTable.GetExtensionSupport != NULL)')
-        ges_body.append('    {')
-        ges_body.append('        result = nextTable.GetExtensionSupport((VkPhysicalGpu)gpuw->nextObject, pExtName);')
-        ges_body.append('    } else')
-        ges_body.append('    {')
-        ges_body.append('        result = VK_ERROR_INVALID_EXTENSION;')
-        ges_body.append('    }')
-        ges_body.append('    return result;')
-        ges_body.append('}')
-        return "\n".join(ges_body)
+    def _gen_layer_get_global_extension_info(self, layer="Generic"):
+        ggei_body = []
+        ggei_body.append('struct extProps {')
+        ggei_body.append('    uint32_t version;')
+        ggei_body.append('    const char * const name;')
+        ggei_body.append('};')
+        ggei_body.append('#define LAYER_EXT_ARRAY_SIZE 1')
+        ggei_body.append('static const struct extProps layerExts[LAYER_EXT_ARRAY_SIZE] = {')
+        ggei_body.append('    // TODO what is the version?')
+        ggei_body.append('    {0x10, "%s"}' % layer)
+        ggei_body.append('};')
+        ggei_body.append('')
+        ggei_body.append('VK_LAYER_EXPORT VK_RESULT VKAPI vkGetGlobalExtensionInfo(VkExtensionInfoType infoType, uint32_t extensionIndex, size_t* pDataSize, void* pData)')
+        ggei_body.append('{')
+        ggei_body.append('    VkExtensionProperties *ext_props;')
+        ggei_body.append('    uint32_t *count;')
+        ggei_body.append('')
+        ggei_body.append('    if (pDataSize == NULL)')
+        ggei_body.append('        return VK_ERROR_INVALID_POINTER;')
+        ggei_body.append('')
+        ggei_body.append('    switch (infoType) {')
+        ggei_body.append('        case VK_EXTENSION_INFO_TYPE_COUNT:')
+        ggei_body.append('            *pDataSize = sizeof(uint32_t);')
+        ggei_body.append('            if (pData == NULL)')
+        ggei_body.append('                return VK_SUCCESS;')
+        ggei_body.append('            count = (uint32_t *) pData;')
+        ggei_body.append('            *count = LAYER_EXT_ARRAY_SIZE;')
+        ggei_body.append('            break;')
+        ggei_body.append('        case VK_EXTENSION_INFO_TYPE_PROPERTIES:')
+        ggei_body.append('            *pDataSize = sizeof(VkExtensionProperties);')
+        ggei_body.append('            if (pData == NULL)')
+        ggei_body.append('                return VK_SUCCESS;')
+        ggei_body.append('            if (extensionIndex >= LAYER_EXT_ARRAY_SIZE)')
+        ggei_body.append('                return VK_ERROR_INVALID_VALUE;')
+        ggei_body.append('            ext_props = (VkExtensionProperties *) pData;')
+        ggei_body.append('            ext_props->version = layerExts[extensionIndex].version;')
+        ggei_body.append('            strncpy(ext_props->extName, layerExts[extensionIndex].name,')
+        ggei_body.append('                                        VK_MAX_EXTENSION_NAME);')
+        ggei_body.append("            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\\0';")
+        ggei_body.append('            break;')
+        ggei_body.append('        default:')
+        ggei_body.append('            return VK_ERROR_INVALID_VALUE;')
+        ggei_body.append('    };')
+        ggei_body.append('    return VK_SUCCESS;')
+        ggei_body.append('}')
+        return "\n".join(ggei_body)
 
     def _generate_dispatch_entrypoints(self, qual=""):
         if qual:
@@ -254,6 +258,8 @@ class Subcommand(object):
                         intercept = self._gen_layer_dbg_callback_unregister()
                     elif 'GetExtensionSupport' == proto.name:
                         funcs.append(self._gen_layer_get_extension_support(self.layer_name))
+                    elif 'GetGlobalExtensionInfo' == proto.name:
+                        funcs.append(self._gen_layer_get_global_extension_info(self.layer_name))
                 if intercept is not None:
                     funcs.append(intercept)
                     intercepted.append(proto)
@@ -269,6 +275,17 @@ class Subcommand(object):
             if 'WsiX11' in proto.name:
                 lookups.append("#endif")
 
+        prefix="vk"
+        lookups = []
+        for proto in intercepted:
+            if 'WsiX11' in proto.name:
+                lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)")
+            lookups.append("if (!strcmp(name, \"%s\"))" % proto.name)
+            lookups.append("    return (void*) %s%s;" %
+                    (prefix, proto.name))
+            if 'WsiX11' in proto.name:
+                lookups.append("#endif")
+
         # add customized layer_intercept_proc
         body = []
         body.append("static inline void* layer_intercept_proc(const char *name)")
@@ -432,7 +449,7 @@ class GenericLayerSubcommand(Subcommand):
         return '#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include "loader_platform.h"\n#include "vkLayer.h"\n//The following is #included again to catch certain OS-specific functions being used:\n#include "loader_platform.h"\n\n#include "layers_config.h"\n#include "layers_msg.h"\n\nstatic VkLayerDispatchTable nextTable;\nstatic VkBaseLayerObject *pCurObj;\n\nstatic LOADER_PLATFORM_THREAD_ONCE_DECLARATION(tabOnce);'
 
     def generate_intercept(self, proto, qual):
-        if proto.name in [ 'DbgRegisterMsgCallback', 'DbgUnregisterMsgCallback' , 'GetExtensionSupport']:
+        if proto.name in [ 'DbgRegisterMsgCallback', 'DbgUnregisterMsgCallback' , 'GetExtensionSupport', 'GetGlobalExtensionInfo']:
             # use default version
             return None
         decl = proto.c_func(prefix="vk", attr="VKAPI")
@@ -619,8 +636,9 @@ class APIDumpSubcommand(Subcommand):
         return "\n".join(func_body)
 
     def generate_intercept(self, proto, qual):
+        if proto.name in [ 'GetGlobalExtensionInfo']:
+            return None
         decl = proto.c_func(prefix="vk", attr="VKAPI")
-        param0_name = proto.params[0].name
         ret_val = ''
         stmt = ''
         funcs = []
@@ -666,6 +684,20 @@ class APIDumpSubcommand(Subcommand):
                 else:
                     prev_count_name = p.name
             else:
+                log_func_no_addr += '%s = " << %s << ", ' % (p.name, pfi)
+            if prev_count_name != '' and (prev_count_name.replace('Count', '')[1:] in p.name or 'slotCount' == prev_count_name):
+                sp_param_dict[pindex] = prev_count_name
+            elif 'pDescriptorSets' == p.name and proto.params[-1].name == 'pCount':
+                sp_param_dict[pindex] = '*pCount'
+            elif 'Wsi' not in proto.name and vk_helper.is_type(p.ty.strip('*').replace('const ', ''), 'struct'):
+                sp_param_dict[pindex] = 'index'
+            pindex += 1
+            if p.name.endswith('Count'):
+                if '*' in p.ty:
+                    prev_count_name = "*%s" % p.name
+                else:
+                    prev_count_name = p.name
+            else:
                 prev_count_name = ''
         log_func = log_func.strip(', ')
         log_func_no_addr = log_func_no_addr.strip(', ')
@@ -1268,7 +1300,7 @@ class ObjectTrackerSubcommand(Subcommand):
         return "\n".join(header_txt)
 
     def generate_intercept(self, proto, qual):
-        if proto.name in [ 'DbgRegisterMsgCallback', 'DbgUnregisterMsgCallback' ]:
+        if proto.name in [ 'DbgRegisterMsgCallback', 'DbgUnregisterMsgCallback', 'GetGlobalExtensionInfo' ]:
             # use default version
             return None
         obj_type_mapping = {base_t : base_t.replace("VK_", "VK_OBJECT_TYPE_") for base_t in vulkan.object_type_list}
@@ -1283,7 +1315,7 @@ class ObjectTrackerSubcommand(Subcommand):
         destroy_line = ''
         funcs = []
         # Special cases for API funcs that don't use an object as first arg
-        if True in [no_use_proto in proto.name for no_use_proto in ['GlobalOption', 'CreateInstance', 'QueueSubmit', 'QueueAddMemReference', 'QueueRemoveMemReference', 'QueueWaitIdle', 'CreateDevice', 'GetGpuInfo', 'QueueSignalSemaphore', 'QueueWaitSemaphore', 'WsiX11QueuePresent']]:
+        if True in [no_use_proto in proto.name for no_use_proto in ['GlobalOption', 'CreateInstance', 'QueueSubmit', 'QueueAddMemReference', 'QueueRemoveMemReference', 'QueueWaitIdle', 'GetGlobalExtensionInfo', 'CreateDevice', 'GetGpuInfo', 'QueueSignalSemaphore', 'QueueWaitSemaphore', 'WsiX11QueuePresent']]:
             using_line = ''
         else:
             using_line = '    loader_platform_thread_lock_mutex(&objLock);\n'
index ff62e8e..7069928 100755 (executable)
--- a/vulkan.py
+++ b/vulkan.py
@@ -182,6 +182,7 @@ class Extension(object):
 core = Extension(
     name="VK_CORE",
     headers=["vulkan.h", "vkDbg.h"],
+
     objects=[
         "VkInstance",
         "VkPhysicalGpu",
@@ -248,6 +249,12 @@ core = Extension(
         Proto("VkResult", "DestroyDevice",
             [Param("VkDevice", "device")]),
 
+        Proto("VkResult", "GetGlobalExtensionInfo",
+            [Param("VkExtensionInfoType", "infoType"),
+             Param("uint32_t", "extensionIndex"),
+             Param("size_t*", "pDataSize"),
+             Param("void*", "pData")]),
+
         Proto("VkResult", "GetExtensionSupport",
             [Param("VkPhysicalGpu", "gpu"),
              Param("const char*", "pExtName")]),