summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ash/src/entry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/ash/src/entry.rs')
-rw-r--r--third_party/rust/ash/src/entry.rs402
1 files changed, 402 insertions, 0 deletions
diff --git a/third_party/rust/ash/src/entry.rs b/third_party/rust/ash/src/entry.rs
new file mode 100644
index 0000000000..67e6c9a739
--- /dev/null
+++ b/third_party/rust/ash/src/entry.rs
@@ -0,0 +1,402 @@
+use crate::instance::Instance;
+use crate::prelude::*;
+use crate::vk;
+use crate::RawPtr;
+use std::ffi::CStr;
+#[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;
+
+#[cfg(feature = "loaded")]
+use libloading::Library;
+
+/// Holds the Vulkan functions independent of a particular instance
+#[derive(Clone)]
+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,
+ entry_fn_1_3: vk::EntryFnV1_3,
+ #[cfg(feature = "loaded")]
+ _lib_guard: Option<Arc<Library>>,
+}
+
+/// Vulkan core 1.0
+#[allow(non_camel_case_types)]
+impl Entry {
+ /// Load default Vulkan library for the current platform
+ ///
+ /// Prefer this over [`linked`](Self::linked) when your application can gracefully handle
+ /// environments that lack Vulkan support, and when the build environment might not have Vulkan
+ /// development packages installed (e.g. the Vulkan SDK, or Ubuntu's `libvulkan-dev`).
+ ///
+ /// # 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<dyn std::error::Error>> {
+ /// 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<Self, LoadingError> {
+ #[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 entry points from a Vulkan loader linked at compile time
+ ///
+ /// Compared to [`load`](Self::load), this is infallible, but requires that the build
+ /// environment have Vulkan development packages installed (e.g. the Vulkan SDK, or Ubuntu's
+ /// `libvulkan-dev`), and prevents the resulting binary from starting in environments that do not
+ /// support Vulkan.
+ ///
+ /// 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<dyn std::error::Error>> {
+ /// let entry = Entry::linked();
+ /// 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 linked() -> 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 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<OsStr>) -> Result<Self, LoadingError> {
+ 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| {
+ mem::transmute((static_fn.get_instance_proc_addr)(
+ vk::Instance::null(),
+ name.as_ptr(),
+ ))
+ };
+ let entry_fn_1_0 = vk::EntryFnV1_0::load(load_fn);
+ let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
+ let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
+ let entry_fn_1_3 = vk::EntryFnV1_3::load(load_fn);
+
+ Self {
+ static_fn,
+ entry_fn_1_0,
+ entry_fn_1_1,
+ entry_fn_1_2,
+ entry_fn_1_3,
+ #[cfg(feature = "loaded")]
+ _lib_guard: None,
+ }
+ }
+
+ #[inline]
+ pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
+ &self.entry_fn_1_0
+ }
+
+ #[inline]
+ pub fn static_fn(&self) -> &vk::StaticFn {
+ &self.static_fn
+ }
+
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html>
+ /// ```no_run
+ /// # use ash::{Entry, vk};
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// let entry = Entry::linked();
+ /// match entry.try_enumerate_instance_version()? {
+ /// // Vulkan 1.1+
+ /// Some(version) => {
+ /// let major = vk::version_major(version);
+ /// let minor = vk::version_minor(version);
+ /// let patch = vk::version_patch(version);
+ /// },
+ /// // Vulkan 1.0
+ /// None => {},
+ /// }
+ /// # Ok(()) }
+ /// ```
+ #[inline]
+ pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
+ unsafe {
+ let mut api_version = 0;
+ let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
+ let name = ::std::ffi::CStr::from_bytes_with_nul_unchecked(
+ b"vkEnumerateInstanceVersion\0",
+ );
+ mem::transmute((self.static_fn.get_instance_proc_addr)(
+ vk::Instance::null(),
+ name.as_ptr(),
+ ))
+ };
+ if let Some(enumerate_instance_version) = enumerate_instance_version {
+ (enumerate_instance_version)(&mut api_version)
+ .result_with_success(Some(api_version))
+ } else {
+ Ok(None)
+ }
+ }
+ }
+
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateInstance.html>
+ ///
+ /// # Safety
+ /// In order for the created [`Instance`] to be valid for the duration of its
+ /// usage, the [`Entry`](Self) this was called on must be dropped later than the
+ /// resulting [`Instance`].
+ #[inline]
+ pub unsafe fn create_instance(
+ &self,
+ create_info: &vk::InstanceCreateInfo,
+ allocation_callbacks: Option<&vk::AllocationCallbacks>,
+ ) -> VkResult<Instance> {
+ let mut instance = mem::zeroed();
+ (self.entry_fn_1_0.create_instance)(
+ create_info,
+ allocation_callbacks.as_raw_ptr(),
+ &mut instance,
+ )
+ .result()?;
+ Ok(Instance::load(&self.static_fn, instance))
+ }
+
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceLayerProperties.html>
+ #[inline]
+ pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
+ unsafe {
+ read_into_uninitialized_vector(|count, data| {
+ (self.entry_fn_1_0.enumerate_instance_layer_properties)(count, data)
+ })
+ }
+ }
+
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>
+ #[inline]
+ pub fn enumerate_instance_extension_properties(
+ &self,
+ layer_name: Option<&CStr>,
+ ) -> VkResult<Vec<vk::ExtensionProperties>> {
+ unsafe {
+ read_into_uninitialized_vector(|count, data| {
+ (self.entry_fn_1_0.enumerate_instance_extension_properties)(
+ layer_name.map_or(ptr::null(), |str| str.as_ptr()),
+ count,
+ data,
+ )
+ })
+ }
+ }
+
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html>
+ #[inline]
+ pub unsafe fn get_instance_proc_addr(
+ &self,
+ instance: vk::Instance,
+ p_name: *const c_char,
+ ) -> vk::PFN_vkVoidFunction {
+ (self.static_fn.get_instance_proc_addr)(instance, p_name)
+ }
+}
+
+/// Vulkan core 1.1
+#[allow(non_camel_case_types)]
+impl Entry {
+ #[inline]
+ pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
+ &self.entry_fn_1_1
+ }
+
+ #[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version()` instead"]
+ /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html>
+ ///
+ /// Please use [`try_enumerate_instance_version()`][Self::try_enumerate_instance_version()] instead.
+ #[inline]
+ pub fn enumerate_instance_version(&self) -> VkResult<u32> {
+ unsafe {
+ let mut api_version = 0;
+ (self.entry_fn_1_1.enumerate_instance_version)(&mut api_version)
+ .result_with_success(api_version)
+ }
+ }
+}
+
+/// Vulkan core 1.2
+#[allow(non_camel_case_types)]
+impl Entry {
+ #[inline]
+ pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
+ &self.entry_fn_1_2
+ }
+}
+
+/// Vulkan core 1.3
+#[allow(non_camel_case_types)]
+impl Entry {
+ #[inline]
+ pub fn fp_v1_3(&self) -> &vk::EntryFnV1_3 {
+ &self.entry_fn_1_3
+ }
+}
+
+#[cfg(feature = "linked")]
+#[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
+impl Default for Entry {
+ #[inline]
+ fn default() -> Self {
+ Self::linked()
+ }
+}
+
+impl vk::StaticFn {
+ pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
+ where
+ F: FnMut(&::std::ffi::CStr) -> *const c_void,
+ {
+ // TODO: Make this a &'static CStr once CStr::from_bytes_with_nul_unchecked is const
+ static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
+
+ Ok(Self {
+ get_instance_proc_addr: unsafe {
+ let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
+ let val = _f(cname);
+ if val.is_null() {
+ return Err(MissingEntryPoint);
+ } else {
+ ::std::mem::transmute(val)
+ }
+ },
+ })
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct MissingEntryPoint;
+impl std::fmt::Display for MissingEntryPoint {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
+ write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
+ }
+}
+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 {
+ Self::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
+ Self::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
+ }
+ }
+ }
+
+ impl Error for LoadingError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Some(match self {
+ Self::LibraryLoadFailure(err) => err,
+ Self::MissingEntryPoint(err) => err,
+ })
+ }
+ }
+
+ impl From<MissingEntryPoint> for LoadingError {
+ fn from(err: MissingEntryPoint) -> Self {
+ Self::MissingEntryPoint(err)
+ }
+ }
+}
+#[cfg(feature = "loaded")]
+pub use self::loaded::*;