Bug 1874684 - Part 10: Replace BigInt with Int128 in RoundNumberToIncrement. r=mgaudet
[gecko.git] / third_party / rust / ash / src / entry.rs
blob7df62e7863f0d9a7eb6bd651a708db7713f56dc3
1 use crate::instance::Instance;
2 use crate::prelude::*;
3 use crate::vk;
4 use crate::RawPtr;
5 use std::ffi::CStr;
6 #[cfg(feature = "loaded")]
7 use std::ffi::OsStr;
8 use std::mem;
9 use std::os::raw::c_char;
10 use std::os::raw::c_void;
11 use std::ptr;
12 #[cfg(feature = "loaded")]
13 use std::sync::Arc;
15 #[cfg(feature = "loaded")]
16 use libloading::Library;
18 /// Holds the Vulkan functions independent of a particular instance
19 #[derive(Clone)]
20 pub struct Entry {
21     static_fn: vk::StaticFn,
22     entry_fn_1_0: vk::EntryFnV1_0,
23     entry_fn_1_1: vk::EntryFnV1_1,
24     entry_fn_1_2: vk::EntryFnV1_2,
25     entry_fn_1_3: vk::EntryFnV1_3,
26     #[cfg(feature = "loaded")]
27     _lib_guard: Option<Arc<Library>>,
30 /// Vulkan core 1.0
31 #[allow(non_camel_case_types)]
32 impl Entry {
33     /// Load default Vulkan library for the current platform
34     ///
35     /// Prefer this over [`linked`](Self::linked) when your application can gracefully handle
36     /// environments that lack Vulkan support, and when the build environment might not have Vulkan
37     /// development packages installed (e.g. the Vulkan SDK, or Ubuntu's `libvulkan-dev`).
38     ///
39     /// # Safety
40     ///
41     /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
42     /// for [`Library::new()`] and [`Library::get()`] apply here.
43     ///
44     /// No Vulkan functions loaded directly or indirectly from this [`Entry`]
45     /// may be called after it is [dropped][drop()].
46     ///
47     /// # Example
48     ///
49     /// ```no_run
50     /// use ash::{vk, Entry};
51     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
52     /// let entry = unsafe { Entry::load()? };
53     /// let app_info = vk::ApplicationInfo {
54     ///     api_version: vk::make_api_version(0, 1, 0, 0),
55     ///     ..Default::default()
56     /// };
57     /// let create_info = vk::InstanceCreateInfo {
58     ///     p_application_info: &app_info,
59     ///     ..Default::default()
60     /// };
61     /// let instance = unsafe { entry.create_instance(&create_info, None)? };
62     /// # Ok(()) }
63     /// ```
64     #[cfg(feature = "loaded")]
65     #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
66     pub unsafe fn load() -> Result<Self, LoadingError> {
67         #[cfg(windows)]
68         const LIB_PATH: &str = "vulkan-1.dll";
70         #[cfg(all(
71             unix,
72             not(any(target_os = "macos", target_os = "ios", target_os = "android"))
73         ))]
74         const LIB_PATH: &str = "libvulkan.so.1";
76         #[cfg(target_os = "android")]
77         const LIB_PATH: &str = "libvulkan.so";
79         #[cfg(any(target_os = "macos", target_os = "ios"))]
80         const LIB_PATH: &str = "libvulkan.dylib";
82         Self::load_from(LIB_PATH)
83     }
85     /// Load entry points from a Vulkan loader linked at compile time
86     ///
87     /// Compared to [`load`](Self::load), this is infallible, but requires that the build
88     /// environment have Vulkan development packages installed (e.g. the Vulkan SDK, or Ubuntu's
89     /// `libvulkan-dev`), and prevents the resulting binary from starting in environments that do not
90     /// support Vulkan.
91     ///
92     /// Note that instance/device functions are still fetched via `vkGetInstanceProcAddr` and
93     /// `vkGetDeviceProcAddr` for maximum performance.
94     ///
95     /// Any Vulkan function acquired directly or indirectly from this [`Entry`] may be called after it
96     /// is [dropped][drop()].
97     ///
98     /// # Example
99     ///
100     /// ```no_run
101     /// use ash::{vk, Entry};
102     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
103     /// let entry = Entry::linked();
104     /// let app_info = vk::ApplicationInfo {
105     ///     api_version: vk::make_api_version(0, 1, 0, 0),
106     ///     ..Default::default()
107     /// };
108     /// let create_info = vk::InstanceCreateInfo {
109     ///     p_application_info: &app_info,
110     ///     ..Default::default()
111     /// };
112     /// let instance = unsafe { entry.create_instance(&create_info, None)? };
113     /// # Ok(()) }
114     /// ```
115     #[cfg(feature = "linked")]
116     #[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
117     pub fn linked() -> Self {
118         // Sound because we're linking to Vulkan, which provides a vkGetInstanceProcAddr that has
119         // defined behavior in this use.
120         unsafe {
121             Self::from_static_fn(vk::StaticFn {
122                 get_instance_proc_addr: vkGetInstanceProcAddr,
123             })
124         }
125     }
127     /// Load Vulkan library at `path`
128     ///
129     /// # Safety
130     ///
131     /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
132     /// for [`Library::new()`] and [`Library::get()`] apply here.
133     ///
134     /// No Vulkan functions loaded directly or indirectly from this [`Entry`]
135     /// may be called after it is [dropped][drop()].
136     #[cfg(feature = "loaded")]
137     #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
138     pub unsafe fn load_from(path: impl AsRef<OsStr>) -> Result<Self, LoadingError> {
139         let lib = Library::new(path)
140             .map_err(LoadingError::LibraryLoadFailure)
141             .map(Arc::new)?;
143         let static_fn = vk::StaticFn::load_checked(|name| {
144             lib.get(name.to_bytes_with_nul())
145                 .map(|symbol| *symbol)
146                 .unwrap_or(ptr::null_mut())
147         })?;
149         Ok(Self {
150             _lib_guard: Some(lib),
151             ..Self::from_static_fn(static_fn)
152         })
153     }
155     /// Load entry points based on an already-loaded [`vk::StaticFn`]
156     ///
157     /// # Safety
158     ///
159     /// `static_fn` must contain valid function pointers that comply with the semantics specified
160     /// by Vulkan 1.0, which must remain valid for at least the lifetime of the returned [`Entry`].
161     pub unsafe fn from_static_fn(static_fn: vk::StaticFn) -> Self {
162         let load_fn = |name: &std::ffi::CStr| {
163             mem::transmute((static_fn.get_instance_proc_addr)(
164                 vk::Instance::null(),
165                 name.as_ptr(),
166             ))
167         };
168         let entry_fn_1_0 = vk::EntryFnV1_0::load(load_fn);
169         let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
170         let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
171         let entry_fn_1_3 = vk::EntryFnV1_3::load(load_fn);
173         Self {
174             static_fn,
175             entry_fn_1_0,
176             entry_fn_1_1,
177             entry_fn_1_2,
178             entry_fn_1_3,
179             #[cfg(feature = "loaded")]
180             _lib_guard: None,
181         }
182     }
184     #[inline]
185     pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
186         &self.entry_fn_1_0
187     }
189     #[inline]
190     pub fn static_fn(&self) -> &vk::StaticFn {
191         &self.static_fn
192     }
194     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html>
195     ///
196     /// # Example
197     ///
198     /// ```no_run
199     /// # use ash::{Entry, vk};
200     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
201     /// let entry = Entry::linked();
202     /// match entry.try_enumerate_instance_version()? {
203     ///     // Vulkan 1.1+
204     ///     Some(version) => {
205     ///         let major = vk::version_major(version);
206     ///         let minor = vk::version_minor(version);
207     ///         let patch = vk::version_patch(version);
208     ///     },
209     ///     // Vulkan 1.0
210     ///     None => {},
211     /// }
212     /// # Ok(()) }
213     /// ```
214     #[inline]
215     pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
216         unsafe {
217             let mut api_version = 0;
218             let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
219                 let name = ::std::ffi::CStr::from_bytes_with_nul_unchecked(
220                     b"vkEnumerateInstanceVersion\0",
221                 );
222                 mem::transmute((self.static_fn.get_instance_proc_addr)(
223                     vk::Instance::null(),
224                     name.as_ptr(),
225                 ))
226             };
227             if let Some(enumerate_instance_version) = enumerate_instance_version {
228                 (enumerate_instance_version)(&mut api_version)
229                     .result_with_success(Some(api_version))
230             } else {
231                 Ok(None)
232             }
233         }
234     }
236     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateInstance.html>
237     ///
238     /// # Safety
239     ///
240     /// The resulting [`Instance`] and any function-pointer objects (e.g. [`Device`][crate::Device]
241     /// and [extensions][crate::extensions]) loaded from it may not be used after this [`Entry`]
242     /// object is dropped, unless it was crated using [`Entry::linked()`].
243     ///
244     /// [`Instance`] does _not_ implement [drop][drop()] semantics and can only be destroyed via
245     /// [`destroy_instance()`][Instance::destroy_instance()].
246     #[inline]
247     pub unsafe fn create_instance(
248         &self,
249         create_info: &vk::InstanceCreateInfo,
250         allocation_callbacks: Option<&vk::AllocationCallbacks>,
251     ) -> VkResult<Instance> {
252         let mut instance = mem::zeroed();
253         (self.entry_fn_1_0.create_instance)(
254             create_info,
255             allocation_callbacks.as_raw_ptr(),
256             &mut instance,
257         )
258         .result()?;
259         Ok(Instance::load(&self.static_fn, instance))
260     }
262     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceLayerProperties.html>
263     #[inline]
264     pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
265         unsafe {
266             read_into_uninitialized_vector(|count, data| {
267                 (self.entry_fn_1_0.enumerate_instance_layer_properties)(count, data)
268             })
269         }
270     }
272     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>
273     #[inline]
274     pub fn enumerate_instance_extension_properties(
275         &self,
276         layer_name: Option<&CStr>,
277     ) -> VkResult<Vec<vk::ExtensionProperties>> {
278         unsafe {
279             read_into_uninitialized_vector(|count, data| {
280                 (self.entry_fn_1_0.enumerate_instance_extension_properties)(
281                     layer_name.map_or(ptr::null(), |str| str.as_ptr()),
282                     count,
283                     data,
284                 )
285             })
286         }
287     }
289     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html>
290     #[inline]
291     pub unsafe fn get_instance_proc_addr(
292         &self,
293         instance: vk::Instance,
294         p_name: *const c_char,
295     ) -> vk::PFN_vkVoidFunction {
296         (self.static_fn.get_instance_proc_addr)(instance, p_name)
297     }
300 /// Vulkan core 1.1
301 #[allow(non_camel_case_types)]
302 impl Entry {
303     #[inline]
304     pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
305         &self.entry_fn_1_1
306     }
308     #[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version()` instead"]
309     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html>
310     ///
311     /// Please use [`try_enumerate_instance_version()`][Self::try_enumerate_instance_version()] instead.
312     #[inline]
313     pub fn enumerate_instance_version(&self) -> VkResult<u32> {
314         unsafe {
315             let mut api_version = 0;
316             (self.entry_fn_1_1.enumerate_instance_version)(&mut api_version)
317                 .result_with_success(api_version)
318         }
319     }
322 /// Vulkan core 1.2
323 #[allow(non_camel_case_types)]
324 impl Entry {
325     #[inline]
326     pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
327         &self.entry_fn_1_2
328     }
331 /// Vulkan core 1.3
332 #[allow(non_camel_case_types)]
333 impl Entry {
334     #[inline]
335     pub fn fp_v1_3(&self) -> &vk::EntryFnV1_3 {
336         &self.entry_fn_1_3
337     }
340 #[cfg(feature = "linked")]
341 #[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
342 impl Default for Entry {
343     #[inline]
344     fn default() -> Self {
345         Self::linked()
346     }
349 impl vk::StaticFn {
350     pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
351     where
352         F: FnMut(&::std::ffi::CStr) -> *const c_void,
353     {
354         // TODO: Make this a &'static CStr once CStr::from_bytes_with_nul_unchecked is const
355         static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
357         Ok(Self {
358             get_instance_proc_addr: unsafe {
359                 let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
360                 let val = _f(cname);
361                 if val.is_null() {
362                     return Err(MissingEntryPoint);
363                 } else {
364                     ::std::mem::transmute(val)
365                 }
366             },
367         })
368     }
371 #[derive(Clone, Debug)]
372 pub struct MissingEntryPoint;
373 impl std::fmt::Display for MissingEntryPoint {
374     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
375         write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
376     }
378 impl std::error::Error for MissingEntryPoint {}
380 #[cfg(feature = "linked")]
381 extern "system" {
382     fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char)
383         -> vk::PFN_vkVoidFunction;
386 #[cfg(feature = "loaded")]
387 mod loaded {
388     use std::error::Error;
389     use std::fmt;
391     use super::*;
393     #[derive(Debug)]
394     #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
395     pub enum LoadingError {
396         LibraryLoadFailure(libloading::Error),
397         MissingEntryPoint(MissingEntryPoint),
398     }
400     impl fmt::Display for LoadingError {
401         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402             match self {
403                 Self::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
404                 Self::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
405             }
406         }
407     }
409     impl Error for LoadingError {
410         fn source(&self) -> Option<&(dyn Error + 'static)> {
411             Some(match self {
412                 Self::LibraryLoadFailure(err) => err,
413                 Self::MissingEntryPoint(err) => err,
414             })
415         }
416     }
418     impl From<MissingEntryPoint> for LoadingError {
419         fn from(err: MissingEntryPoint) -> Self {
420             Self::MissingEntryPoint(err)
421         }
422     }
424 #[cfg(feature = "loaded")]
425 pub use self::loaded::*;