1 use crate::instance::Instance;
6 #[cfg(feature = "loaded")]
9 use std::os::raw::c_char;
10 use std::os::raw::c_void;
12 #[cfg(feature = "loaded")]
15 #[cfg(feature = "loaded")]
16 use libloading::Library;
18 /// Holds the Vulkan functions independent of a particular instance
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>>,
31 #[allow(non_camel_case_types)]
33 /// Load default Vulkan library for the current platform
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`).
41 /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
42 /// for [`Library::new()`] and [`Library::get()`] apply here.
44 /// No Vulkan functions loaded directly or indirectly from this [`Entry`]
45 /// may be called after it is [dropped][drop()].
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()
57 /// let create_info = vk::InstanceCreateInfo {
58 /// p_application_info: &app_info,
59 /// ..Default::default()
61 /// let instance = unsafe { entry.create_instance(&create_info, None)? };
64 #[cfg(feature = "loaded")]
65 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
66 pub unsafe fn load() -> Result<Self, LoadingError> {
68 const LIB_PATH: &str = "vulkan-1.dll";
72 not(any(target_os = "macos", target_os = "ios", target_os = "android"))
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)
85 /// Load entry points from a Vulkan loader linked at compile time
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
92 /// Note that instance/device functions are still fetched via `vkGetInstanceProcAddr` and
93 /// `vkGetDeviceProcAddr` for maximum performance.
95 /// Any Vulkan function acquired directly or indirectly from this [`Entry`] may be called after it
96 /// is [dropped][drop()].
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()
108 /// let create_info = vk::InstanceCreateInfo {
109 /// p_application_info: &app_info,
110 /// ..Default::default()
112 /// let instance = unsafe { entry.create_instance(&create_info, None)? };
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.
121 Self::from_static_fn(vk::StaticFn {
122 get_instance_proc_addr: vkGetInstanceProcAddr,
127 /// Load Vulkan library at `path`
131 /// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
132 /// for [`Library::new()`] and [`Library::get()`] apply here.
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)
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())
150 _lib_guard: Some(lib),
151 ..Self::from_static_fn(static_fn)
155 /// Load entry points based on an already-loaded [`vk::StaticFn`]
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(),
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);
179 #[cfg(feature = "loaded")]
185 pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
190 pub fn static_fn(&self) -> &vk::StaticFn {
194 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceVersion.html>
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()? {
204 /// Some(version) => {
205 /// let major = vk::version_major(version);
206 /// let minor = vk::version_minor(version);
207 /// let patch = vk::version_patch(version);
215 pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
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",
222 mem::transmute((self.static_fn.get_instance_proc_addr)(
223 vk::Instance::null(),
227 if let Some(enumerate_instance_version) = enumerate_instance_version {
228 (enumerate_instance_version)(&mut api_version)
229 .result_with_success(Some(api_version))
236 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateInstance.html>
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()`].
244 /// [`Instance`] does _not_ implement [drop][drop()] semantics and can only be destroyed via
245 /// [`destroy_instance()`][Instance::destroy_instance()].
247 pub unsafe fn create_instance(
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)(
255 allocation_callbacks.as_raw_ptr(),
259 Ok(Instance::load(&self.static_fn, instance))
262 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceLayerProperties.html>
264 pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
266 read_into_uninitialized_vector(|count, data| {
267 (self.entry_fn_1_0.enumerate_instance_layer_properties)(count, data)
272 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>
274 pub fn enumerate_instance_extension_properties(
276 layer_name: Option<&CStr>,
277 ) -> VkResult<Vec<vk::ExtensionProperties>> {
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()),
289 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html>
291 pub unsafe fn get_instance_proc_addr(
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)
301 #[allow(non_camel_case_types)]
304 pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
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>
311 /// Please use [`try_enumerate_instance_version()`][Self::try_enumerate_instance_version()] instead.
313 pub fn enumerate_instance_version(&self) -> VkResult<u32> {
315 let mut api_version = 0;
316 (self.entry_fn_1_1.enumerate_instance_version)(&mut api_version)
317 .result_with_success(api_version)
323 #[allow(non_camel_case_types)]
326 pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
332 #[allow(non_camel_case_types)]
335 pub fn fp_v1_3(&self) -> &vk::EntryFnV1_3 {
340 #[cfg(feature = "linked")]
341 #[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
342 impl Default for Entry {
344 fn default() -> Self {
350 pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
352 F: FnMut(&::std::ffi::CStr) -> *const c_void,
354 // TODO: Make this a &'static CStr once CStr::from_bytes_with_nul_unchecked is const
355 static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
358 get_instance_proc_addr: unsafe {
359 let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
362 return Err(MissingEntryPoint);
364 ::std::mem::transmute(val)
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")
378 impl std::error::Error for MissingEntryPoint {}
380 #[cfg(feature = "linked")]
382 fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char)
383 -> vk::PFN_vkVoidFunction;
386 #[cfg(feature = "loaded")]
388 use std::error::Error;
394 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
395 pub enum LoadingError {
396 LibraryLoadFailure(libloading::Error),
397 MissingEntryPoint(MissingEntryPoint),
400 impl fmt::Display for LoadingError {
401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
403 Self::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
404 Self::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
409 impl Error for LoadingError {
410 fn source(&self) -> Option<&(dyn Error + 'static)> {
412 Self::LibraryLoadFailure(err) => err,
413 Self::MissingEntryPoint(err) => err,
418 impl From<MissingEntryPoint> for LoadingError {
419 fn from(err: MissingEntryPoint) -> Self {
420 Self::MissingEntryPoint(err)
424 #[cfg(feature = "loaded")]
425 pub use self::loaded::*;