Skip to content

Relative path ICD is not deterministic, can return duplicate entry #2017

Description

@hmaarrfk

Describe the bug
I am helping conda-forge in integrating other directories for ICDs so that we can have:

  1. THe system ICDs
  2. The conda-forge installed ICDs

However, the problem is that the ubuntu ICD loader reads:

/usr/share/vulkan/icd.d $ cat intel_icd.json
{
    "ICD": {
        "api_version": "1.4.318",
        "library_path": "libvulkan_intel.so"
    },
    "file_format_version": "1.0.1"
}

With conda installing its own libvulkan_intel.so this will eventually resolve to conda's version. My claim is that we can't do anything about this other than ask ubuntu to use the full path for ICD libraries (which they likely won't do)

Conda will also install its own icd.json file, to its own ${CONDA_PREFIX}/share/vulkan/icd.d, and thus the same library will appear twice.

I think we should filter it out, just to keep the output less confusing.

Environment (please complete the following information):

  • OS: ubuntu 24 + conda(-forge)
  • Bitdepth: 64bit
  • GPU: intel (well anything really)
  • Graphics Driver: mesa 26
  • SDK or header version if building from repo: 1.4.357.0
  • Enabled layers:

To Reproduce

diff --git a/loader/loader.c b/loader/loader.c
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -2145,6 +2145,31 @@
         goto out;
     }
 
+    // Skip a driver we have already scanned.  Two different manifests can name the same
+    // library: a distribution manifest using a bare "library_path" resolved through the
+    // dynamic linker search path, and one using an absolute path, can both end up at the
+    // same file.  The duplicate checks elsewhere in the loader only compare path strings,
+    // so nothing catches this and the driver is scanned twice, which reports every
+    // physical device it owns twice from vkEnumeratePhysicalDevices.
+    //
+    // dlopen/LoadLibrary returns the same handle for an object that is already loaded, so
+    // comparing handles identifies the duplicate exactly, without resolving paths or
+    // stat()ing anything.  Keep the entry already in the list: the search order puts the
+    // more specific manifest first.
+    for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
+        if (icd_tramp_list->scanned_list[i].handle == handle) {
+            loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+                       "loader_scanned_icd_add: Driver %s is the same library as already loaded driver %s, skipping duplicate",
+                       filename, icd_tramp_list->scanned_list[i].lib_name);
+            // Release the reference the open above took; the existing entry owns the one
+            // that loader_scanned_icd_clear will release.
+            loader_platform_close_library(handle);
+            handle = NULL;
+            res = VK_SUCCESS;
+            goto out;
+        }
+    }
+
     // Try to load the driver's exported vk_icdNegotiateLoaderICDInterfaceVersion
     fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
 

VK_LOADER_DEBUG output
Attach output when running with the environment variable VK_LOADER_DEBUG=all

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions