• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::instance::Instance;
2 use crate::prelude::*;
3 use crate::vk;
4 use crate::RawPtr;
5 use std::error::Error;
6 use std::ffi::CStr;
7 use std::fmt;
8 use std::mem;
9 use std::os::raw::c_char;
10 use std::os::raw::c_void;
11 use std::ptr;
12 
13 /// Holds a custom type `L` to load symbols from (usually a handle to a `dlopen`ed library),
14 /// the [`vkGetInstanceProcAddr`][vk::StaticFn::get_instance_proc_addr()] loader function from
15 /// this library (in [`vk::StaticFn`]), and Vulkan's "entry point" functions (resolved with `NULL`
16 /// `instance`) as listed in [`vkGetInstanceProcAddr`'s description].
17 ///
18 /// [`vkGetInstanceProcAddr`'s description]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html#_description
19 #[derive(Clone)]
20 pub struct EntryCustom<L> {
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     lib: L,
26 }
27 
28 /// Vulkan core 1.0
29 #[allow(non_camel_case_types)]
30 impl<L> EntryCustom<L> {
new_custom<Load>( mut lib: L, mut load: Load, ) -> std::result::Result<Self, MissingEntryPoint> where Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void,31     pub fn new_custom<Load>(
32         mut lib: L,
33         mut load: Load,
34     ) -> std::result::Result<Self, MissingEntryPoint>
35     where
36         Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void,
37     {
38         // Bypass the normal StaticFn::load so we can return an error
39         let static_fn = vk::StaticFn::load_checked(|name| load(&mut lib, name))?;
40         let load_fn = |name: &std::ffi::CStr| unsafe {
41             mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
42         };
43         let entry_fn_1_0 = vk::EntryFnV1_0::load(load_fn);
44         let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
45         let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
46 
47         Ok(EntryCustom {
48             static_fn,
49             entry_fn_1_0,
50             entry_fn_1_1,
51             entry_fn_1_2,
52             lib,
53         })
54     }
55 
fp_v1_0(&self) -> &vk::EntryFnV1_056     pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
57         &self.entry_fn_1_0
58     }
59 
static_fn(&self) -> &vk::StaticFn60     pub fn static_fn(&self) -> &vk::StaticFn {
61         &self.static_fn
62     }
63 
64     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceVersion.html>"]
65     /// ```no_run
66     /// # use ash::{Entry, vk};
67     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
68     /// let entry = unsafe { Entry::new() }?;
69     /// match entry.try_enumerate_instance_version()? {
70     ///     // Vulkan 1.1+
71     ///     Some(version) => {
72     ///         let major = vk::version_major(version);
73     ///         let minor = vk::version_minor(version);
74     ///         let patch = vk::version_patch(version);
75     ///     },
76     ///     // Vulkan 1.0
77     ///     None => {},
78     /// }
79     /// # Ok(()) }
80     /// ```
try_enumerate_instance_version(&self) -> VkResult<Option<u32>>81     pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
82         unsafe {
83             let mut api_version = 0;
84             let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
85                 let name = b"vkEnumerateInstanceVersion\0".as_ptr() as *const _;
86                 mem::transmute(
87                     self.static_fn
88                         .get_instance_proc_addr(vk::Instance::null(), name),
89                 )
90             };
91             if let Some(enumerate_instance_version) = enumerate_instance_version {
92                 (enumerate_instance_version)(&mut api_version)
93                     .result_with_success(Some(api_version))
94             } else {
95                 Ok(None)
96             }
97         }
98     }
99 
100     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateInstance.html>"]
101     ///
102     /// # Safety
103     /// In order for the created [`Instance`] to be valid for the duration of its
104     /// usage, the [`Entry`](Self) this was called on must be dropped later than the
105     /// resulting [`Instance`].
create_instance( &self, create_info: &vk::InstanceCreateInfo, allocation_callbacks: Option<&vk::AllocationCallbacks>, ) -> Result<Instance, InstanceError>106     pub unsafe fn create_instance(
107         &self,
108         create_info: &vk::InstanceCreateInfo,
109         allocation_callbacks: Option<&vk::AllocationCallbacks>,
110     ) -> Result<Instance, InstanceError> {
111         let mut instance = mem::zeroed();
112         self.entry_fn_1_0
113             .create_instance(
114                 create_info,
115                 allocation_callbacks.as_raw_ptr(),
116                 &mut instance,
117             )
118             .result()
119             .map_err(InstanceError::VkError)?;
120         Ok(Instance::load(&self.static_fn, instance))
121     }
122 
123     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceLayerProperties.html>"]
enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>>124     pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
125         unsafe {
126             read_into_uninitialized_vector(|count, data| {
127                 self.entry_fn_1_0
128                     .enumerate_instance_layer_properties(count, data)
129             })
130         }
131     }
132 
133     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>"]
enumerate_instance_extension_properties( &self, ) -> VkResult<Vec<vk::ExtensionProperties>>134     pub fn enumerate_instance_extension_properties(
135         &self,
136     ) -> VkResult<Vec<vk::ExtensionProperties>> {
137         unsafe {
138             read_into_uninitialized_vector(|count, data| {
139                 self.entry_fn_1_0
140                     .enumerate_instance_extension_properties(ptr::null(), count, data)
141             })
142         }
143     }
144 
145     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html>"]
get_instance_proc_addr( &self, instance: vk::Instance, p_name: *const c_char, ) -> vk::PFN_vkVoidFunction146     pub unsafe fn get_instance_proc_addr(
147         &self,
148         instance: vk::Instance,
149         p_name: *const c_char,
150     ) -> vk::PFN_vkVoidFunction {
151         self.static_fn.get_instance_proc_addr(instance, p_name)
152     }
153 }
154 
155 /// Vulkan core 1.1
156 #[allow(non_camel_case_types)]
157 impl<L> EntryCustom<L> {
fp_v1_1(&self) -> &vk::EntryFnV1_1158     pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
159         &self.entry_fn_1_1
160     }
161 
162     #[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version` instead"]
163     #[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceVersion.html>"]
164     ///
165     /// Please use [`Self::try_enumerate_instance_version`] instead.
enumerate_instance_version(&self) -> VkResult<u32>166     pub fn enumerate_instance_version(&self) -> VkResult<u32> {
167         unsafe {
168             let mut api_version = 0;
169             self.entry_fn_1_1
170                 .enumerate_instance_version(&mut api_version)
171                 .result_with_success(api_version)
172         }
173     }
174 }
175 
176 /// Vulkan core 1.2
177 #[allow(non_camel_case_types)]
178 impl<L> EntryCustom<L> {
fp_v1_2(&self) -> &vk::EntryFnV1_2179     pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
180         &self.entry_fn_1_2
181     }
182 }
183 
184 #[derive(Clone, Debug)]
185 pub enum InstanceError {
186     LoadError(Vec<&'static str>),
187     VkError(vk::Result),
188 }
189 
190 impl fmt::Display for InstanceError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result191     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192         match self {
193             InstanceError::LoadError(e) => write!(f, "{}", e.join("; ")),
194             InstanceError::VkError(e) => write!(f, "{}", e),
195         }
196     }
197 }
198 
199 impl Error for InstanceError {}
200 
201 impl vk::StaticFn {
load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint> where F: FnMut(&::std::ffi::CStr) -> *const c_void,202     pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
203     where
204         F: FnMut(&::std::ffi::CStr) -> *const c_void,
205     {
206         // TODO: Make this a &'static CStr once CStr::from_bytes_with_nul_unchecked is const
207         static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
208 
209         Ok(vk::StaticFn {
210             get_instance_proc_addr: unsafe {
211                 let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
212                 let val = _f(cname);
213                 if val.is_null() {
214                     return Err(MissingEntryPoint);
215                 } else {
216                     ::std::mem::transmute(val)
217                 }
218             },
219         })
220     }
221 }
222 
223 #[derive(Clone, Debug)]
224 pub struct MissingEntryPoint;
225 impl std::fmt::Display for MissingEntryPoint {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>226     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
227         write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
228     }
229 }
230 impl std::error::Error for MissingEntryPoint {}
231