From aa7b429f4fce528b842fa9ccc1960e97c4261d95 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Thu, 9 Sep 2021 13:50:34 -0700 Subject: [PATCH] Support linking Vulkan directly (#457) * Mark EntryCustom::new_custom as unsafe Passing a badly-behaved `load` function can invoke undefined behavior. * Document required feature for Entry * Support linking Vulkan directly This is the preferred pattern in most environments when an application cannot function without Vulkan, as it saves the libloading dependency, eliminates an error case, and makes the Vulkan dependency visible to the OS. * Rename libloading feature to "loaded" * Link by default * Guide users towards linking the loader directly * Remove unnecessary error type InstanceError::LoadError was never constructed. * Unify entry types Simplifies the interface and allows a bunch of code to become monomorphic. --- .github/workflows/ci.yml | 4 +- README.md | 5 + ash-window/examples/winit.rs | 2 +- ash-window/src/lib.rs | 6 +- ash/Cargo.toml | 10 +- ash/build.rs | 24 ++ ash/src/entry.rs | 219 ++++++++++++++---- ash/src/entry_libloading.rs | 101 -------- ash/src/extensions/ext/debug_report.rs | 4 +- ash/src/extensions/ext/debug_utils.rs | 4 +- ash/src/extensions/ext/metal_surface.rs | 4 +- ash/src/extensions/ext/tooling_info.rs | 4 +- ash/src/extensions/khr/android_surface.rs | 4 +- ash/src/extensions/khr/display.rs | 4 +- .../khr/get_physical_device_properties2.rs | 4 +- .../khr/pipeline_executable_properties.rs | 4 +- ash/src/extensions/khr/surface.rs | 4 +- ash/src/extensions/khr/timeline_semaphore.rs | 4 +- ash/src/extensions/khr/wayland_surface.rs | 4 +- ash/src/extensions/khr/win32_surface.rs | 4 +- ash/src/extensions/khr/xcb_surface.rs | 4 +- ash/src/extensions/khr/xlib_surface.rs | 4 +- ash/src/extensions/mvk/ios_surface.rs | 4 +- ash/src/extensions/mvk/macos_surface.rs | 4 +- ash/src/extensions/nn/vi_surface.rs | 4 +- ash/src/lib.rs | 20 +- examples/src/lib.rs | 4 +- 27 files changed, 266 insertions(+), 197 deletions(-) create mode 100644 ash/build.rs delete mode 100644 ash/src/entry_libloading.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33bde8e..646d4b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: check - args: --workspace --all-targets + args: --workspace --all-targets --all-features generated: name: Generated @@ -47,6 +47,8 @@ jobs: name: Test Suite runs-on: ubuntu-latest steps: + - name: Install Vulkan loader + run: sudo apt-get install libvulkan-dev - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: diff --git a/README.md b/README.md index 24397ad..9bef027 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,11 @@ pub fn create_command_pool(&self, let pool = device.create_command_pool(&pool_create_info).unwrap(); ``` +### Optional linking + +The default `linked` cargo feature will link your binary with the Vulkan loader directly and expose the infallible `Entry::new`. +If your application can handle Vulkan being missing at runtime, you can instead enable the `loaded` feature to dynamically load Vulkan with `Entry::load`. + ## Example You can find the examples [here](https://github.com/MaikKlein/ash/tree/master/examples). All examples currently require: the LunarG Validation layers and a Vulkan library that is visible in your `PATH`. An easy way to get started is to use the [LunarG Vulkan SDK](https://lunarg.com/vulkan-sdk/) diff --git a/ash-window/examples/winit.rs b/ash-window/examples/winit.rs index 9158f39..0921897 100644 --- a/ash-window/examples/winit.rs +++ b/ash-window/examples/winit.rs @@ -15,7 +15,7 @@ fn main() -> Result<(), Box> { .build(&events_loop)?; unsafe { - let entry = ash::Entry::new()?; + let entry = ash::Entry::new(); let surface_extensions = ash_window::enumerate_required_extensions(&window)?; let instance_extensions = surface_extensions .iter() diff --git a/ash-window/src/lib.rs b/ash-window/src/lib.rs index 83fc84f..1c74435 100644 --- a/ash-window/src/lib.rs +++ b/ash-window/src/lib.rs @@ -1,4 +1,4 @@ -use ash::{extensions::khr, prelude::*, vk, EntryCustom, Instance}; +use ash::{extensions::khr, prelude::*, vk, Entry, Instance}; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use std::ffi::CStr; @@ -14,8 +14,8 @@ use ash::extensions::ext; // portability extensions /// In order for the created [`vk::SurfaceKHR`] to be valid for the duration of its /// usage, the [`Instance`] this was called on must be dropped later than the /// resulting [`vk::SurfaceKHR`]. -pub unsafe fn create_surface( - entry: &EntryCustom, +pub unsafe fn create_surface( + entry: &Entry, instance: &Instance, window_handle: &dyn HasRawWindowHandle, allocation_callbacks: Option<&vk::AllocationCallbacks>, diff --git a/ash/Cargo.toml b/ash/Cargo.toml index 914f217..bda7aa8 100644 --- a/ash/Cargo.toml +++ b/ash/Cargo.toml @@ -14,7 +14,15 @@ edition = "2018" libloading = { version = "0.7", optional = true } [features] -default = ["libloading"] +default = ["linked"] +# Link the Vulkan loader at compile time. +linked = [] +# Support searching for the Vulkan loader manually at runtime. +loaded = ["libloading"] [package.metadata.release] no-dev-version = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/ash/build.rs b/ash/build.rs new file mode 100644 index 0000000..ba6e61d --- /dev/null +++ b/ash/build.rs @@ -0,0 +1,24 @@ +fn main() { + #[cfg(feature = "linked")] + { + use std::env; + + let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); + let target_pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); + + println!("cargo:rerun-if-env-changed=VULKAN_SDK"); + if let Ok(var) = env::var("VULKAN_SDK") { + let suffix = match (&*target_family, &*target_pointer_width) { + ("windows", "32") => "Lib32", + ("windows", "64") => "Lib", + _ => "lib", + }; + println!("cargo:rustc-link-search={}/{}", var, suffix); + } + let lib = match &*target_family { + "windows" => "vulkan-1", + _ => "vulkan", + }; + println!("cargo:rustc-link-lib={}", lib); + } +} diff --git a/ash/src/entry.rs b/ash/src/entry.rs index 280076b..f6f91dd 100644 --- a/ash/src/entry.rs +++ b/ash/src/entry.rs @@ -2,41 +2,137 @@ use crate::instance::Instance; use crate::prelude::*; use crate::vk; use crate::RawPtr; -use std::error::Error; use std::ffi::CStr; -use std::fmt; +#[cfg(feature = "loaded")] +use std::ffi::OsStr; use std::mem; use std::os::raw::c_char; use std::os::raw::c_void; use std::ptr; +#[cfg(feature = "loaded")] +use std::sync::Arc; -/// Holds a custom type `L` to load symbols from (usually a handle to a `dlopen`ed library), -/// the [`vkGetInstanceProcAddr`][vk::StaticFn::get_instance_proc_addr()] loader function from -/// this library (in [`vk::StaticFn`]), and Vulkan's "entry point" functions (resolved with `NULL` -/// `instance`) as listed in [`vkGetInstanceProcAddr`'s description]. -/// -/// [`vkGetInstanceProcAddr`'s description]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html#_description +#[cfg(feature = "loaded")] +use libloading::Library; + +/// Holds the Vulkan functions independent of a particular instance #[derive(Clone)] -pub struct EntryCustom { +pub struct Entry { static_fn: vk::StaticFn, entry_fn_1_0: vk::EntryFnV1_0, entry_fn_1_1: vk::EntryFnV1_1, entry_fn_1_2: vk::EntryFnV1_2, - lib: L, + #[cfg(feature = "loaded")] + _lib_guard: Option>, } /// Vulkan core 1.0 #[allow(non_camel_case_types)] -impl EntryCustom { - pub fn new_custom( - mut lib: L, - mut load: Load, - ) -> std::result::Result - where - Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void, - { - // Bypass the normal StaticFn::load so we can return an error - let static_fn = vk::StaticFn::load_checked(|name| load(&mut lib, name))?; +impl Entry { + /// Load entry points from a Vulkan loader linked at compile time + /// + /// Note that instance/device functions are still fetched via `vkGetInstanceProcAddr` and + /// `vkGetDeviceProcAddr` for maximum performance. + /// + /// ```no_run + /// use ash::{vk, Entry}; + /// # fn main() -> Result<(), Box> { + /// let entry = Entry::new(); + /// let app_info = vk::ApplicationInfo { + /// api_version: vk::make_api_version(0, 1, 0, 0), + /// ..Default::default() + /// }; + /// let create_info = vk::InstanceCreateInfo { + /// p_application_info: &app_info, + /// ..Default::default() + /// }; + /// let instance = unsafe { entry.create_instance(&create_info, None)? }; + /// # Ok(()) } + /// ``` + #[cfg(feature = "linked")] + #[cfg_attr(docsrs, doc(cfg(feature = "linked")))] + pub fn new() -> Self { + // Sound because we're linking to Vulkan, which provides a vkGetInstanceProcAddr that has + // defined behavior in this use. + unsafe { + Self::from_static_fn(vk::StaticFn { + get_instance_proc_addr: vkGetInstanceProcAddr, + }) + } + } + + /// Load default Vulkan library for the current platform + /// + /// # Safety + /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines + /// for [`Library::new()`] and [`Library::get()`] apply here. + /// + /// ```no_run + /// use ash::{vk, Entry}; + /// # fn main() -> Result<(), Box> { + /// let entry = unsafe { Entry::load()? }; + /// let app_info = vk::ApplicationInfo { + /// api_version: vk::make_api_version(0, 1, 0, 0), + /// ..Default::default() + /// }; + /// let create_info = vk::InstanceCreateInfo { + /// p_application_info: &app_info, + /// ..Default::default() + /// }; + /// let instance = unsafe { entry.create_instance(&create_info, None)? }; + /// # Ok(()) } + /// ``` + #[cfg(feature = "loaded")] + #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))] + pub unsafe fn load() -> Result { + #[cfg(windows)] + const LIB_PATH: &str = "vulkan-1.dll"; + + #[cfg(all( + unix, + not(any(target_os = "macos", target_os = "ios", target_os = "android")) + ))] + const LIB_PATH: &str = "libvulkan.so.1"; + + #[cfg(target_os = "android")] + const LIB_PATH: &str = "libvulkan.so"; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + const LIB_PATH: &str = "libvulkan.dylib"; + + Self::load_from(LIB_PATH) + } + + /// Load Vulkan library at `path` + /// + /// # Safety + /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines + /// for [`Library::new()`] and [`Library::get()`] apply here. + #[cfg(feature = "loaded")] + #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))] + pub unsafe fn load_from(path: impl AsRef) -> Result { + let lib = Library::new(path) + .map_err(LoadingError::LibraryLoadFailure) + .map(Arc::new)?; + + let static_fn = vk::StaticFn::load_checked(|name| { + lib.get(name.to_bytes_with_nul()) + .map(|symbol| *symbol) + .unwrap_or(ptr::null_mut()) + })?; + + Ok(Self { + _lib_guard: Some(lib), + ..Self::from_static_fn(static_fn) + }) + } + + /// Load entry points based on an already-loaded [`vk::StaticFn`] + /// + /// # Safety + /// `static_fn` must contain valid function pointers that comply with the semantics specified by + /// Vulkan 1.0, which must remain valid for at least the lifetime of the returned [`Entry`]. + pub unsafe fn from_static_fn(static_fn: vk::StaticFn) -> Self { let load_fn = |name: &std::ffi::CStr| unsafe { mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr())) }; @@ -44,13 +140,14 @@ impl EntryCustom { let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn); let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn); - Ok(EntryCustom { + Self { static_fn, entry_fn_1_0, entry_fn_1_1, entry_fn_1_2, - lib, - }) + #[cfg(feature = "loaded")] + _lib_guard: None, + } } pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 { @@ -65,7 +162,7 @@ impl EntryCustom { /// ```no_run /// # use ash::{Entry, vk}; /// # fn main() -> Result<(), Box> { - /// let entry = unsafe { Entry::new() }?; + /// let entry = Entry::new(); /// match entry.try_enumerate_instance_version()? { /// // Vulkan 1.1+ /// Some(version) => { @@ -107,7 +204,7 @@ impl EntryCustom { &self, create_info: &vk::InstanceCreateInfo, allocation_callbacks: Option<&vk::AllocationCallbacks>, - ) -> Result { + ) -> VkResult { let mut instance = mem::zeroed(); self.entry_fn_1_0 .create_instance( @@ -115,8 +212,7 @@ impl EntryCustom { allocation_callbacks.as_raw_ptr(), &mut instance, ) - .result() - .map_err(InstanceError::VkError)?; + .result()?; Ok(Instance::load(&self.static_fn, instance)) } @@ -154,7 +250,7 @@ impl EntryCustom { /// Vulkan core 1.1 #[allow(non_camel_case_types)] -impl EntryCustom { +impl Entry { pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 { &self.entry_fn_1_1 } @@ -175,29 +271,19 @@ impl EntryCustom { /// Vulkan core 1.2 #[allow(non_camel_case_types)] -impl EntryCustom { +impl Entry { pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 { &self.entry_fn_1_2 } } -#[derive(Clone, Debug)] -pub enum InstanceError { - LoadError(Vec<&'static str>), - VkError(vk::Result), -} - -impl fmt::Display for InstanceError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - InstanceError::LoadError(e) => write!(f, "{}", e.join("; ")), - InstanceError::VkError(e) => write!(f, "{}", e), - } +#[cfg(feature = "linked")] +impl Default for Entry { + fn default() -> Self { + Self::new() } } -impl Error for InstanceError {} - impl vk::StaticFn { pub fn load_checked(mut _f: F) -> Result where @@ -228,3 +314,50 @@ impl std::fmt::Display for MissingEntryPoint { } } impl std::error::Error for MissingEntryPoint {} + +#[cfg(feature = "linked")] +extern "system" { + fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char) + -> vk::PFN_vkVoidFunction; +} + +#[cfg(feature = "loaded")] +mod loaded { + use std::error::Error; + use std::fmt; + + use super::*; + + #[derive(Debug)] + #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))] + pub enum LoadingError { + LibraryLoadFailure(libloading::Error), + MissingEntryPoint(MissingEntryPoint), + } + + impl fmt::Display for LoadingError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f), + LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f), + } + } + } + + impl Error for LoadingError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(match self { + LoadingError::LibraryLoadFailure(err) => err, + LoadingError::MissingEntryPoint(err) => err, + }) + } + } + + impl From for LoadingError { + fn from(err: MissingEntryPoint) -> Self { + LoadingError::MissingEntryPoint(err) + } + } +} +#[cfg(feature = "loaded")] +pub use self::loaded::*; diff --git a/ash/src/entry_libloading.rs b/ash/src/entry_libloading.rs deleted file mode 100644 index 3e9386a..0000000 --- a/ash/src/entry_libloading.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::entry::EntryCustom; -use crate::entry::MissingEntryPoint; -use libloading::Library; -use std::error::Error; -use std::ffi::OsStr; -use std::fmt; -use std::ptr; -use std::sync::Arc; - -#[cfg(windows)] -const LIB_PATH: &str = "vulkan-1.dll"; - -#[cfg(all( - unix, - not(any(target_os = "macos", target_os = "ios", target_os = "android")) -))] -const LIB_PATH: &str = "libvulkan.so.1"; - -#[cfg(target_os = "android")] -const LIB_PATH: &str = "libvulkan.so"; - -#[cfg(any(target_os = "macos", target_os = "ios"))] -const LIB_PATH: &str = "libvulkan.dylib"; - -#[derive(Debug)] -pub enum LoadingError { - LibraryLoadFailure(libloading::Error), - MissingEntryPoint(MissingEntryPoint), -} - -impl fmt::Display for LoadingError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f), - LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f), - } - } -} - -impl Error for LoadingError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(match self { - LoadingError::LibraryLoadFailure(err) => err, - LoadingError::MissingEntryPoint(err) => err, - }) - } -} - -impl From for LoadingError { - fn from(err: MissingEntryPoint) -> Self { - LoadingError::MissingEntryPoint(err) - } -} - -/// Default function loader -pub type Entry = EntryCustom>; - -impl Entry { - /// Load default Vulkan library for the current platform - /// - /// # Safety - /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines - /// for [`Library::new`] and [`Library::get`] apply here. - /// - /// ```no_run - /// use ash::{vk, Entry}; - /// # fn main() -> Result<(), Box> { - /// let entry = unsafe { Entry::new() }?; - /// let app_info = vk::ApplicationInfo { - /// api_version: vk::make_api_version(0, 1, 0, 0), - /// ..Default::default() - /// }; - /// let create_info = vk::InstanceCreateInfo { - /// p_application_info: &app_info, - /// ..Default::default() - /// }; - /// let instance = unsafe { entry.create_instance(&create_info, None)? }; - /// # Ok(()) } - /// ``` - pub unsafe fn new() -> Result { - Self::with_library(LIB_PATH) - } - - /// Load Vulkan library at `path` - /// - /// # Safety - /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines - /// for [`Library::new`] and [`Library::get`] apply here. - pub unsafe fn with_library(path: impl AsRef) -> Result { - let lib = Library::new(path) - .map_err(LoadingError::LibraryLoadFailure) - .map(Arc::new)?; - - Ok(Self::new_custom(lib, |vk_lib, name| { - vk_lib - .get(name.to_bytes_with_nul()) - .map(|symbol| *symbol) - .unwrap_or(ptr::null_mut()) - })?) - } -} diff --git a/ash/src/extensions/ext/debug_report.rs b/ash/src/extensions/ext/debug_report.rs index 3400566..89abb9b 100755 --- a/ash/src/extensions/ext/debug_report.rs +++ b/ash/src/extensions/ext/debug_report.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct DebugReport { } impl DebugReport { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let debug_report_fn = vk::ExtDebugReportFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/ext/debug_utils.rs b/ash/src/extensions/ext/debug_utils.rs index 69ce2e9..9faa401 100755 --- a/ash/src/extensions/ext/debug_utils.rs +++ b/ash/src/extensions/ext/debug_utils.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::{vk, RawPtr}; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -11,7 +11,7 @@ pub struct DebugUtils { } impl DebugUtils { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let debug_utils_fn = vk::ExtDebugUtilsFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/ext/metal_surface.rs b/ash/src/extensions/ext/metal_surface.rs index c76d436..6cf3207 100644 --- a/ash/src/extensions/ext/metal_surface.rs +++ b/ash/src/extensions/ext/metal_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct MetalSurface { } impl MetalSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::ExtMetalSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/ext/tooling_info.rs b/ash/src/extensions/ext/tooling_info.rs index 284a472..0b0c8ae 100644 --- a/ash/src/extensions/ext/tooling_info.rs +++ b/ash/src/extensions/ext/tooling_info.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::vk; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -11,7 +11,7 @@ pub struct ToolingInfo { } impl ToolingInfo { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let tooling_info_fn = vk::ExtToolingInfoFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/android_surface.rs b/ash/src/extensions/khr/android_surface.rs index fef6b7d..354279e 100755 --- a/ash/src/extensions/khr/android_surface.rs +++ b/ash/src/extensions/khr/android_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct AndroidSurface { } impl AndroidSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrAndroidSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/display.rs b/ash/src/extensions/khr/display.rs index 4ae8a34..b24d597 100755 --- a/ash/src/extensions/khr/display.rs +++ b/ash/src/extensions/khr/display.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct Display { } impl Display { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let display_fn = vk::KhrDisplayFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/get_physical_device_properties2.rs b/ash/src/extensions/khr/get_physical_device_properties2.rs index 57609fa..abf2331 100644 --- a/ash/src/extensions/khr/get_physical_device_properties2.rs +++ b/ash/src/extensions/khr/get_physical_device_properties2.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::vk; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; use std::ptr; @@ -12,7 +12,7 @@ pub struct GetPhysicalDeviceProperties2 { } impl GetPhysicalDeviceProperties2 { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let get_physical_device_properties2_fn = vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) diff --git a/ash/src/extensions/khr/pipeline_executable_properties.rs b/ash/src/extensions/khr/pipeline_executable_properties.rs index fd85a76..3662f6f 100644 --- a/ash/src/extensions/khr/pipeline_executable_properties.rs +++ b/ash/src/extensions/khr/pipeline_executable_properties.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::vk; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -11,7 +11,7 @@ pub struct PipelineExecutableProperties { } impl PipelineExecutableProperties { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let pipeline_executable_properties_fn = vk::KhrPipelineExecutablePropertiesFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) diff --git a/ash/src/extensions/khr/surface.rs b/ash/src/extensions/khr/surface.rs index 3c19d22..d5607cd 100755 --- a/ash/src/extensions/khr/surface.rs +++ b/ash/src/extensions/khr/surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct Surface { } impl Surface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/timeline_semaphore.rs b/ash/src/extensions/khr/timeline_semaphore.rs index fca074e..2abb7a2 100644 --- a/ash/src/extensions/khr/timeline_semaphore.rs +++ b/ash/src/extensions/khr/timeline_semaphore.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::vk; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -11,7 +11,7 @@ pub struct TimelineSemaphore { } impl TimelineSemaphore { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let timeline_semaphore_fn = vk::KhrTimelineSemaphoreFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/wayland_surface.rs b/ash/src/extensions/khr/wayland_surface.rs index d4983df..241cdea 100755 --- a/ash/src/extensions/khr/wayland_surface.rs +++ b/ash/src/extensions/khr/wayland_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct WaylandSurface { } impl WaylandSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrWaylandSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/win32_surface.rs b/ash/src/extensions/khr/win32_surface.rs index d037fba..aef2d44 100755 --- a/ash/src/extensions/khr/win32_surface.rs +++ b/ash/src/extensions/khr/win32_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct Win32Surface { } impl Win32Surface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrWin32SurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/xcb_surface.rs b/ash/src/extensions/khr/xcb_surface.rs index c01d2f3..e538ce6 100755 --- a/ash/src/extensions/khr/xcb_surface.rs +++ b/ash/src/extensions/khr/xcb_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct XcbSurface { } impl XcbSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrXcbSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/khr/xlib_surface.rs b/ash/src/extensions/khr/xlib_surface.rs index 0f53c39..5b0de68 100755 --- a/ash/src/extensions/khr/xlib_surface.rs +++ b/ash/src/extensions/khr/xlib_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct XlibSurface { } impl XlibSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::KhrXlibSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/mvk/ios_surface.rs b/ash/src/extensions/mvk/ios_surface.rs index a8491f2..3b12f3a 100755 --- a/ash/src/extensions/mvk/ios_surface.rs +++ b/ash/src/extensions/mvk/ios_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct IOSSurface { } impl IOSSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::MvkIosSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/mvk/macos_surface.rs b/ash/src/extensions/mvk/macos_surface.rs index 31ca0de..b20e3bb 100755 --- a/ash/src/extensions/mvk/macos_surface.rs +++ b/ash/src/extensions/mvk/macos_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct MacOSSurface { } impl MacOSSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::MvkMacosSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/extensions/nn/vi_surface.rs b/ash/src/extensions/nn/vi_surface.rs index e3ade6f..8634d12 100644 --- a/ash/src/extensions/nn/vi_surface.rs +++ b/ash/src/extensions/nn/vi_surface.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::vk; use crate::RawPtr; -use crate::{EntryCustom, Instance}; +use crate::{Entry, Instance}; use std::ffi::CStr; use std::mem; @@ -12,7 +12,7 @@ pub struct ViSurface { } impl ViSurface { - pub fn new(entry: &EntryCustom, instance: &Instance) -> Self { + pub fn new(entry: &Entry, instance: &Instance) -> Self { let surface_fn = vk::NnViSurfaceFn::load(|name| unsafe { mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr())) }); diff --git a/ash/src/lib.rs b/ash/src/lib.rs index c6ca4eb..af1b97e 100644 --- a/ash/src/lib.rs +++ b/ash/src/lib.rs @@ -3,6 +3,7 @@ clippy::missing_safety_doc, clippy::upper_case_acronyms )] +#![cfg_attr(docsrs, feature(doc_cfg))] //! # Vulkan API //! //! @@ -12,7 +13,7 @@ //! ```no_run //! use ash::{vk, Entry}; //! # fn main() -> Result<(), Box> { -//! let entry = unsafe { Entry::new() }?; +//! let entry = Entry::new(); //! let app_info = vk::ApplicationInfo { //! api_version: vk::make_api_version(0, 1, 0, 0), //! ..Default::default() @@ -26,22 +27,19 @@ //! ``` //! //! ## Getting started -//! Load the Vulkan library at the default location using [`Entry::new()`][EntryCustom<_>::new()], -//! or at a custom location using [`Entry::with_library("path/to/vulkan")`][EntryCustom<_>::with_library()]. -//! These loaders use [`libloading`]. If you wish to perform function loading yourself -//! call [`EntryCustom::new_custom()`] with a closure turning function names -//! into function pointers. +//! +//! Load the Vulkan library linked at compile time using [`Entry::new()`], or load it at runtime +//! using [`Entry::load()`], which uses `libloading`. If you want to perform entry point loading +//! yourself, call [`Entry::from_static_fn()`]. pub use crate::device::Device; -pub use crate::entry::{EntryCustom, InstanceError}; -#[cfg(feature = "libloading")] -pub use crate::entry_libloading::{Entry, LoadingError}; +pub use crate::entry::Entry; +#[cfg(feature = "loaded")] +pub use crate::entry::LoadingError; pub use crate::instance::Instance; mod device; mod entry; -#[cfg(feature = "libloading")] -mod entry_libloading; mod instance; pub mod prelude; pub mod util; diff --git a/examples/src/lib.rs b/examples/src/lib.rs index b37b75c..1c37f8b 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -7,7 +7,7 @@ use ash::extensions::{ }; use ash::{vk, Entry}; -pub use ash::{Device, EntryCustom, Instance}; +pub use ash::{Device, Instance}; use std::borrow::Cow; use std::cell::RefCell; use std::default::Default; @@ -204,7 +204,7 @@ impl ExampleBase { )) .build(&events_loop) .unwrap(); - let entry = Entry::new().unwrap(); + let entry = Entry::new(); let app_name = CString::new("VulkanTriangle").unwrap(); let layer_names = [CString::new("VK_LAYER_KHRONOS_validation").unwrap()];