diff options
Diffstat (limited to 'src/instance/loader.rs')
-rw-r--r-- | src/instance/loader.rs | 316 |
1 files changed, 0 insertions, 316 deletions
diff --git a/src/instance/loader.rs b/src/instance/loader.rs deleted file mode 100644 index 7714fd2..0000000 --- a/src/instance/loader.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT -// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! Vulkan implementation loading system. -//! -//! Before vulkano can do anything, it first needs to find an implementation of Vulkan. A Vulkan -//! implementation is defined as a single `vkGetInstanceProcAddr` function, which can be accessed -//! through the `Loader` trait. -//! -//! This module provides various implementations of the `Loader` trait. -//! -//! Once you have a struct that implements `Loader`, you can create a `FunctionPointers` struct -//! from it and use this `FunctionPointers` struct to build an `Instance`. -//! -//! By default vulkano will use the `auto_loader()` function, which tries to automatically load -//! a Vulkan implementation from the system. - -use crate::check_errors; -use crate::fns::EntryFunctions; -use crate::OomError; -use crate::SafeDeref; -use crate::Version; -use lazy_static::lazy_static; -use shared_library; -use std::error; -use std::ffi::CStr; -use std::fmt; -use std::mem; -use std::ops::Deref; -use std::os::raw::c_char; -use std::os::raw::c_void; -use std::path::Path; - -/// Implemented on objects that grant access to a Vulkan implementation. -pub unsafe trait Loader { - /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same. - /// - /// The returned function must stay valid for as long as `self` is alive. - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void; -} - -unsafe impl<T> Loader for T -where - T: SafeDeref, - T::Target: Loader, -{ - #[inline] - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void { - (**self).get_instance_proc_addr(instance, name) - } -} - -/// Implementation of `Loader` that loads Vulkan from a dynamic library. -pub struct DynamicLibraryLoader { - vk_lib: shared_library::dynamic_library::DynamicLibrary, - get_proc_addr: - extern "system" fn(instance: ash::vk::Instance, pName: *const c_char) -> *const c_void, -} - -impl DynamicLibraryLoader { - /// Tries to load the dynamic library at the given path, and tries to - /// load `vkGetInstanceProcAddr` in it. - /// - /// # Safety - /// - /// - The dynamic library must be a valid Vulkan implementation. - /// - pub unsafe fn new<P>(path: P) -> Result<DynamicLibraryLoader, LoadingError> - where - P: AsRef<Path>, - { - 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, - }) - } -} - -unsafe impl Loader for DynamicLibraryLoader { - #[inline] - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void { - (self.get_proc_addr)(instance, name) - } -} - -/// Wraps around a loader and contains function pointers. -pub struct FunctionPointers<L> { - loader: L, - fns: EntryFunctions, -} - -impl<L> FunctionPointers<L> { - /// Loads some global function pointer from the loader. - pub fn new(loader: L) -> FunctionPointers<L> - where - L: Loader, - { - let fns = EntryFunctions::load(|name| unsafe { - mem::transmute(loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr())) - }); - - FunctionPointers { loader, fns } - } - - /// Returns the collection of Vulkan entry points from the Vulkan loader. - #[inline] - pub fn fns(&self) -> &EntryFunctions { - &self.fns - } - - /// Returns the highest Vulkan version that is supported for instances. - pub fn api_version(&self) -> Result<Version, OomError> - where - L: Loader, - { - // Per the Vulkan spec: - // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a - // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion - // to determine the version of Vulkan. - unsafe { - let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0"); - let func = self.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr()); - - if func.is_null() { - Ok(Version { - major: 1, - minor: 0, - patch: 0, - }) - } else { - type Pfn = extern "system" fn(pApiVersion: *mut u32) -> ash::vk::Result; - let func: Pfn = mem::transmute(func); - let mut api_version = 0; - check_errors(func(&mut api_version))?; - Ok(Version::from(api_version)) - } - } - } - - /// Calls `get_instance_proc_addr` on the underlying loader. - #[inline] - pub fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void - where - L: Loader, - { - self.loader.get_instance_proc_addr(instance, name) - } -} - -/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're -/// compiling. -/// -/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr` -/// symbol. -/// -/// This is provided as a macro and not as a regular function, because the macro contains an -/// `extern {}` block. -// TODO: should this be unsafe? -#[macro_export] -macro_rules! statically_linked_vulkan_loader { - () => {{ - extern "C" { - fn vkGetInstanceProcAddr( - instance: ash::vk::Instance, - pName: *const c_char, - ) -> ash::vk::PFN_vkVoidFunction; - } - - struct StaticallyLinkedVulkanLoader; - unsafe impl Loader for StaticallyLinkedVulkanLoader { - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> extern "system" fn() -> () { - unsafe { vkGetInstanceProcAddr(instance, name) } - } - } - - StaticallyLinkedVulkanLoader - }}; -} - -/// Returns the default `FunctionPointers` for this system. -/// -/// This function tries to auto-guess where to find the Vulkan implementation, and loads it in a -/// `lazy_static!`. The content of the lazy_static is then returned, or an error if we failed to -/// load Vulkan. -pub fn auto_loader( -) -> Result<&'static FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> { - #[cfg(target_os = "ios")] - #[allow(non_snake_case)] - fn def_loader_impl() -> Result<Box<Loader + Send + Sync>, LoadingError> { - let loader = statically_linked_vulkan_loader!(); - Ok(Box::new(loader)) - } - - #[cfg(not(target_os = "ios"))] - fn def_loader_impl() -> Result<Box<dyn Loader + Send + Sync>, LoadingError> { - #[cfg(windows)] - fn get_path() -> &'static Path { - 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") - } - #[cfg(target_os = "macos")] - fn get_path() -> &'static Path { - Path::new("libvulkan.1.dylib") - } - #[cfg(target_os = "android")] - fn get_path() -> &'static Path { - Path::new("libvulkan.so") - } - - let loader = unsafe { DynamicLibraryLoader::new(get_path())? }; - - Ok(Box::new(loader)) - } - - lazy_static! { - static ref DEFAULT_LOADER: Result<FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> = - def_loader_impl().map(FunctionPointers::new); - } - - match DEFAULT_LOADER.deref() { - &Ok(ref ptr) => Ok(ptr), - &Err(ref err) => Err(err.clone()), - } -} - -/// Error that can happen when loading the Vulkan loader. -#[derive(Debug, Clone)] -pub enum LoadingError { - /// Failed to load the Vulkan shared library. - LibraryLoadFailure(String), // TODO: meh for error type, but this needs changes in shared_library - - /// One of the entry points required to be supported by the Vulkan implementation is missing. - MissingEntryPoint(String), -} - -impl error::Error for LoadingError { - /*#[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - LoadingError::LibraryLoadFailure(ref err) => Some(err), - _ => None - } - }*/ -} - -impl fmt::Display for LoadingError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - 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" - } - } - ) - } -} - -#[cfg(test)] -mod tests { - use crate::instance::loader::DynamicLibraryLoader; - use crate::instance::loader::LoadingError; - - #[test] - fn dl_open_error() { - unsafe { - match DynamicLibraryLoader::new("_non_existing_library.void") { - Err(LoadingError::LibraryLoadFailure(_)) => (), - _ => panic!(), - } - } - } -} |