From 149733f2c6deb517b95cbab8d86066ee7394418c Mon Sep 17 00:00:00 2001 From: Ewen Cheslack-Postava Date: Tue, 22 Mar 2022 14:27:55 -0700 Subject: [PATCH] Support loading dynamic libraries from multiple paths and try more paths in default loader --- vulkano/src/instance/loader.rs | 83 ++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/vulkano/src/instance/loader.rs b/vulkano/src/instance/loader.rs index 55b5647efa..b157288e70 100644 --- a/vulkano/src/instance/loader.rs +++ b/vulkano/src/instance/loader.rs @@ -79,31 +79,49 @@ pub struct DynamicLibraryLoader { } impl DynamicLibraryLoader { - /// Tries to load the dynamic library at the given path, and tries to - /// load `vkGetInstanceProcAddr` in it. + /// Tries to load the dynamic library at the given paths, using the first successfully loaded, + /// and tries to load `vkGetInstanceProcAddr` in it. /// /// # Safety /// /// - The dynamic library must be a valid Vulkan implementation. /// - pub unsafe fn new

(path: P) -> Result + pub unsafe fn new

(paths: &[P]) -> Result where P: AsRef, { - let vk_lib = shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref())) - .map_err(LoadingError::LibraryLoadFailure)?; - - let get_proc_addr = { - let ptr: *mut c_void = vk_lib - .symbol("vkGetInstanceProcAddr") - .map_err(|_| LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()))?; - mem::transmute(ptr) - }; - - Ok(DynamicLibraryLoader { - vk_lib, - get_proc_addr, - }) + let mut errors = Vec::new(); + let vk_lib = paths.iter().find_map(|path| { + shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref())) + .or_else(|e| { + errors.push(e.clone()); + Err(e) + }) + .ok() + }); + + match vk_lib { + Some(dl) => { + let get_proc_addr = { + let ptr: *mut c_void = dl + .symbol("vkGetInstanceProcAddr") + // Arguably we could continue trying subsequent paths here, but we don't + // expect to find a matching filename without the right contents, so better + // to fail here, especially since an unknown library is now loaded into the + // process. + .map_err(|_| { + LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()) + })?; + mem::transmute(ptr) + }; + + Ok(DynamicLibraryLoader { + vk_lib: dl, + get_proc_addr, + }) + } + None => Err(LoadingError::LibraryLoadFailure(errors.join(" "))), + } } } @@ -237,23 +255,29 @@ pub fn auto_loader() -> Result<&'static FunctionPointers>, Loadi #[cfg(not(target_os = "ios"))] fn def_loader_impl() -> Result, LoadingError> { #[cfg(windows)] - fn get_path() -> &'static Path { - Path::new("vulkan-1.dll") + fn get_paths() -> [&'static Path; 1] { + [&Path::new("vulkan-1.dll")] } #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] - fn get_path() -> &'static Path { - Path::new("libvulkan.so.1") + fn get_paths() -> [&'static Path; 1] { + [&Path::new("libvulkan.so.1")] } #[cfg(target_os = "macos")] - fn get_path() -> &'static Path { - Path::new("libvulkan.1.dylib") + fn get_paths() -> [&'static Path; 5] { + [ + &Path::new("libvulkan.1.dylib"), + &Path::new("libvulkan.dylib"), + &Path::new("vulkan.framework/vulkan"), + &Path::new("MoltenVK.framework/MoltenVK"), + &Path::new("libMoltenVK.dylib"), + ] } #[cfg(target_os = "android")] - fn get_path() -> &'static Path { - Path::new("libvulkan.so") + fn get_paths() -> [&'static Path; 1] { + [&Path::new("libvulkan.so")] } - let loader = unsafe { DynamicLibraryLoader::new(get_path())? }; + let loader = unsafe { DynamicLibraryLoader::new(&get_paths())? }; Ok(Box::new(loader)) } @@ -299,7 +323,7 @@ impl fmt::Display for LoadingError { LoadingError::LibraryLoadFailure(_) => "failed to load the Vulkan shared library", LoadingError::MissingEntryPoint(_) => { "one of the entry points required to be supported by the Vulkan implementation \ - is missing" + is missing" } } ) @@ -314,7 +338,10 @@ mod tests { #[test] fn dl_open_error() { unsafe { - match DynamicLibraryLoader::new("_non_existing_library.void") { + match DynamicLibraryLoader::new(&[ + "_non_existing_library.void", + "_another_non_existing_library.void", + ]) { Err(LoadingError::LibraryLoadFailure(_)) => (), _ => panic!(), }