From eea83cf878188d6601c60339888ac8ac64d5b889 Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis Date: Tue, 1 Dec 2020 17:03:03 +0100 Subject: [PATCH] loader: Do not remove duplicated layers Linux can support multiple ABIs, but Vulkan Layer manifest does not allow to specify different library paths, based on the ABI. As a solution, for ICDs, we can simply create multiple manifests, one per ABI, and the Loader will try them one by one until it finds the library that is compatible with the executable class. Instead, for Vulkan Layers, this method doesn't work because the Loader will discard the manifests that have a duplicated layer name. To add support for multiple ABIs to Vulkan Layers, and to make the behavior similar to the ICDs, with this commit we remove the duplicated layer name check. Instead we add to the output list all the Vulkan Layers that we find, and only when we are actually going to dlopen them, we discard the layers with the same name that we already successfully opened. Fixes: #155 Signed-off-by: Ludovico de Nittis --- loader/loader.c | 95 ++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/loader/loader.c b/loader/loader.c index 7ae228996..b6ba5d89e 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1708,10 +1708,13 @@ static bool loaderInitLayerList(const struct loader_instance *inst, struct loade return true; } -// Search the given layer list for a list matching the given VkLayerProperties -bool loaderListHasLayerProperty(const VkLayerProperties *vk_layer_prop, const struct loader_layer_list *list) { - for (uint32_t i = 0; i < list->count; i++) { - if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) return true; +// Search the given array of layer names for an entry matching the given VkLayerProperties +bool loaderNamesArrayHasLayerProperty(const VkLayerProperties *vk_layer_prop, + uint32_t layer_names_count, char **layer_names) { + for (uint32_t i = 0; i < layer_names_count; i++) { + if (strcmp(vk_layer_prop->layerName, layer_names[i]) == 0) { + return true; + } } return false; } @@ -1727,7 +1730,7 @@ void loaderDestroyLayerList(const struct loader_instance *inst, struct loader_de layer_list->capacity = 0; } -// Append non-duplicate layer properties defined in prop_list to the given layer_info list +// Append layer properties defined in prop_list to the given layer_info list VkResult loaderAddLayerPropertiesToList(const struct loader_instance *inst, struct loader_layer_list *list, uint32_t prop_list_count, const struct loader_layer_properties *props) { uint32_t i; @@ -1744,11 +1747,6 @@ VkResult loaderAddLayerPropertiesToList(const struct loader_instance *inst, stru for (i = 0; i < prop_list_count; i++) { layer = (struct loader_layer_properties *)&props[i]; - // Look for duplicates, and skip - if (loaderListHasLayerProperty(&layer->info, list)) { - continue; - } - // Check for enough capacity if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) { size_t new_capacity = list->capacity * 2; @@ -1771,7 +1769,7 @@ VkResult loaderAddLayerPropertiesToList(const struct loader_instance *inst, stru } // Search the given search_list for any layers in the props list. Add these to the -// output layer_list. Don't add duplicates to the output layer_list. +// output layer_list. static VkResult loaderAddLayerNamesToList(const struct loader_instance *inst, struct loader_layer_list *output_list, struct loader_layer_list *expanded_output_list, uint32_t name_count, const char *const *names, const struct loader_layer_list *source_list) { @@ -1789,17 +1787,10 @@ static VkResult loaderAddLayerNamesToList(const struct loader_instance *inst, st // If not a meta-layer, simply add it. if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { - if (!loaderListHasLayerProperty(&layer_prop->info, output_list)) { - loaderAddLayerPropertiesToList(inst, output_list, 1, layer_prop); - } - if (!loaderListHasLayerProperty(&layer_prop->info, expanded_output_list)) { - loaderAddLayerPropertiesToList(inst, expanded_output_list, 1, layer_prop); - } + loaderAddLayerPropertiesToList(inst, output_list, 1, layer_prop); + loaderAddLayerPropertiesToList(inst, expanded_output_list, 1, layer_prop); } else { - if (!loaderListHasLayerProperty(&layer_prop->info, output_list) || - !loaderListHasLayerProperty(&layer_prop->info, expanded_output_list)) { - loaderAddMetaLayer(inst, layer_prop, output_list, expanded_output_list, source_list); - } + loaderAddMetaLayer(inst, layer_prop, output_list, expanded_output_list, source_list); } } @@ -1903,17 +1894,12 @@ static void loaderAddImplicitLayer(const struct loader_instance *inst, const str if (enable) { if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { - if (!loaderListHasLayerProperty(&prop->info, target_list)) { - loaderAddLayerPropertiesToList(inst, target_list, 1, prop); - } - if (NULL != expanded_target_list && !loaderListHasLayerProperty(&prop->info, expanded_target_list)) { + loaderAddLayerPropertiesToList(inst, target_list, 1, prop); + if (NULL != expanded_target_list) { loaderAddLayerPropertiesToList(inst, expanded_target_list, 1, prop); } } else { - if (!loaderListHasLayerProperty(&prop->info, target_list) || - (NULL != expanded_target_list && !loaderListHasLayerProperty(&prop->info, expanded_target_list))) { - loaderAddMetaLayer(inst, prop, target_list, expanded_target_list, source_list); - } + loaderAddMetaLayer(inst, prop, target_list, expanded_target_list, source_list); } } } @@ -1924,11 +1910,6 @@ bool loaderAddMetaLayer(const struct loader_instance *inst, const struct loader_ const struct loader_layer_list *source_list) { bool found = true; - // If the meta-layer isn't present in the unexpanded list, add it. - if (!loaderListHasLayerProperty(&prop->info, target_list)) { - loaderAddLayerPropertiesToList(inst, target_list, 1, prop); - } - // We need to add all the individual component layers for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) { bool found_comp = false; @@ -1945,11 +1926,8 @@ bool loaderAddMetaLayer(const struct loader_instance *inst, const struct loader_ if (0 != (search_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { found = loaderAddMetaLayer(inst, search_prop, target_list, expanded_target_list, source_list); } else { - // Otherwise, just make sure it hasn't already been added to either list before we add it - if (!loaderListHasLayerProperty(&search_prop->info, target_list)) { - loaderAddLayerPropertiesToList(inst, target_list, 1, search_prop); - } - if (NULL != expanded_target_list && !loaderListHasLayerProperty(&search_prop->info, expanded_target_list)) { + loaderAddLayerPropertiesToList(inst, target_list, 1, search_prop); + if (NULL != expanded_target_list) { loaderAddLayerPropertiesToList(inst, expanded_target_list, 1, search_prop); } } @@ -1965,7 +1943,7 @@ bool loaderAddMetaLayer(const struct loader_instance *inst, const struct loader_ } // Add this layer to the overall target list (not the expanded one) - if (found && !loaderListHasLayerProperty(&prop->info, target_list)) { + if (found) { loaderAddLayerPropertiesToList(inst, target_list, 1, prop); } @@ -1974,7 +1952,6 @@ bool loaderAddMetaLayer(const struct loader_instance *inst, const struct loader_ // Search the source_list for any layer with a name that matches the given name and a type // that matches the given type. Add all matching layers to the target_list. -// Do not add if found loader_layer_properties is already on the target_list. VkResult loaderAddLayerNameToList(const struct loader_instance *inst, const char *name, const enum layer_type_flags type_flags, const struct loader_layer_list *source_list, struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list) { @@ -1985,12 +1962,10 @@ VkResult loaderAddLayerNameToList(const struct loader_instance *inst, const char if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) { // If not a meta-layer, simply add it. if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) { - if (!loaderListHasLayerProperty(&source_prop->info, target_list) && - VK_SUCCESS == loaderAddLayerPropertiesToList(inst, target_list, 1, source_prop)) { + if (VK_SUCCESS == loaderAddLayerPropertiesToList(inst, target_list, 1, source_prop)) { found = true; } - if (!loaderListHasLayerProperty(&source_prop->info, expanded_target_list) && - VK_SUCCESS == loaderAddLayerPropertiesToList(inst, expanded_target_list, 1, source_prop)) { + if (VK_SUCCESS == loaderAddLayerPropertiesToList(inst, expanded_target_list, 1, source_prop)) { found = true; } } else { @@ -5923,6 +5898,7 @@ VKAPI_ATTR void VKAPI_CALL loader_layer_destroy_device(VkDevice device, const Vk VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, struct loader_instance *inst, VkInstance *created_instance) { uint32_t activated_layers = 0; + char ** activated_layer_names = NULL; VkLayerInstanceCreateInfo chain_info; VkLayerInstanceLink *layer_instance_link_info = NULL; VkInstanceCreateInfo loader_create_info; @@ -5951,11 +5927,23 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c return VK_ERROR_OUT_OF_HOST_MEMORY; } + activated_layer_names = loader_stack_alloc(sizeof(char *) * inst->expanded_activated_layer_list.count); + if (!activated_layer_names) { + loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, + "loader_create_instance_chain: Failed to alloc activated layer names array"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + // Create instance chain of enabled layers for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) { struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i]; loader_platform_dl_handle lib_handle; + // Skip it if a Layer with the same name has been already successfully activated + if (loaderNamesArrayHasLayerProperty(&layer_prop->info, activated_layers, activated_layer_names)) { + continue; + } + lib_handle = loaderOpenLayerFile(inst, "instance", layer_prop); if (!lib_handle) { continue; @@ -6043,6 +6031,8 @@ VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, c chain_info.u.pLayerInfo = &layer_instance_link_info[activated_layers]; + activated_layer_names[activated_layers] = layer_prop->info.layerName; + loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Insert instance layer %s (%s)", layer_prop->info.layerName, layer_prop->lib_name); @@ -6118,6 +6108,7 @@ VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCre struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer, PFN_vkGetDeviceProcAddr *layerNextGDPA) { uint32_t activated_layers = 0; + char ** activated_layer_names = NULL; VkLayerDeviceLink *layer_device_link_info; VkLayerDeviceCreateInfo chain_info; VkDeviceCreateInfo loader_create_info; @@ -6179,6 +6170,13 @@ VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCre return VK_ERROR_OUT_OF_HOST_MEMORY; } + activated_layer_names = loader_stack_alloc(sizeof(char *) * inst->expanded_activated_layer_list.count); + if (!activated_layer_names) { + loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, + "loader_create_instance_chain: Failed to alloc activated layer names array"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (dev->expanded_activated_layer_list.count > 0) { chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO; chain_info.function = VK_LAYER_LINK_INFO; @@ -6193,6 +6191,11 @@ VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCre struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i]; loader_platform_dl_handle lib_handle; + // Skip it if a Layer with the same name has been already successfully activated + if (loaderNamesArrayHasLayerProperty(&layer_prop->info, activated_layers, activated_layer_names)) { + continue; + } + lib_handle = loaderOpenLayerFile(inst, "device", layer_prop); if (!lib_handle || done) { continue; @@ -6246,6 +6249,8 @@ VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCre nextGIPA = fpGIPA; nextGDPA = fpGDPA; + activated_layer_names[activated_layers] = layer_prop->info.layerName; + loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Inserted device layer %s (%s)", layer_prop->info.layerName, layer_prop->lib_name);