1use crate::instance::Instance;
2use crate::prelude::*;
3use crate::vk;
4use crate::RawPtr;
5use std::ffi::CStr;
6#[cfg(feature = "loaded")]
7use std::ffi::OsStr;
8use std::mem;
9use std::os::raw::c_char;
10use std::os::raw::c_void;
11use std::ptr;
12#[cfg(feature = "loaded")]
13use std::sync::Arc;
14
15#[cfg(feature = "loaded")]
16use libloading::Library;
17
18#[derive(Clone)]
20pub 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>>,
28}
29
30#[allow(non_camel_case_types)]
32impl Entry {
33 #[cfg(feature = "loaded")]
59 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
60 pub unsafe fn load() -> Result<Self, LoadingError> {
61 #[cfg(windows)]
62 const LIB_PATH: &str = "vulkan-1.dll";
63
64 #[cfg(all(
65 unix,
66 not(any(target_os = "macos", target_os = "ios", target_os = "android"))
67 ))]
68 const LIB_PATH: &str = "libvulkan.so.1";
69
70 #[cfg(target_os = "android")]
71 const LIB_PATH: &str = "libvulkan.so";
72
73 #[cfg(any(target_os = "macos", target_os = "ios"))]
74 const LIB_PATH: &str = "libvulkan.dylib";
75
76 Self::load_from(LIB_PATH)
77 }
78
79 #[cfg(feature = "linked")]
105 #[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
106 pub fn linked() -> Self {
107 unsafe {
110 Self::from_static_fn(vk::StaticFn {
111 get_instance_proc_addr: vkGetInstanceProcAddr,
112 })
113 }
114 }
115
116 #[cfg(feature = "loaded")]
122 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
123 pub unsafe fn load_from(path: impl AsRef<OsStr>) -> Result<Self, LoadingError> {
124 let lib = Library::new(path)
125 .map_err(LoadingError::LibraryLoadFailure)
126 .map(Arc::new)?;
127
128 let static_fn = vk::StaticFn::load_checked(|name| {
129 lib.get(name.to_bytes_with_nul())
130 .map(|symbol| *symbol)
131 .unwrap_or(ptr::null_mut())
132 })?;
133
134 Ok(Self {
135 _lib_guard: Some(lib),
136 ..Self::from_static_fn(static_fn)
137 })
138 }
139
140 pub unsafe fn from_static_fn(static_fn: vk::StaticFn) -> Self {
146 let load_fn = |name: &std::ffi::CStr| {
147 mem::transmute((static_fn.get_instance_proc_addr)(
148 vk::Instance::null(),
149 name.as_ptr(),
150 ))
151 };
152 let entry_fn_1_0 = vk::EntryFnV1_0::load(load_fn);
153 let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
154 let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
155 let entry_fn_1_3 = vk::EntryFnV1_3::load(load_fn);
156
157 Self {
158 static_fn,
159 entry_fn_1_0,
160 entry_fn_1_1,
161 entry_fn_1_2,
162 entry_fn_1_3,
163 #[cfg(feature = "loaded")]
164 _lib_guard: None,
165 }
166 }
167
168 pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
169 &self.entry_fn_1_0
170 }
171
172 pub fn static_fn(&self) -> &vk::StaticFn {
173 &self.static_fn
174 }
175
176 pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
194 unsafe {
195 let mut api_version = 0;
196 let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
197 let name = b"vkEnumerateInstanceVersion\0".as_ptr() as *const _;
198 mem::transmute((self.static_fn.get_instance_proc_addr)(
199 vk::Instance::null(),
200 name,
201 ))
202 };
203 if let Some(enumerate_instance_version) = enumerate_instance_version {
204 (enumerate_instance_version)(&mut api_version)
205 .result_with_success(Some(api_version))
206 } else {
207 Ok(None)
208 }
209 }
210 }
211
212 pub unsafe fn create_instance(
219 &self,
220 create_info: &vk::InstanceCreateInfo,
221 allocation_callbacks: Option<&vk::AllocationCallbacks>,
222 ) -> VkResult<Instance> {
223 let mut instance = mem::zeroed();
224 (self.entry_fn_1_0.create_instance)(
225 create_info,
226 allocation_callbacks.as_raw_ptr(),
227 &mut instance,
228 )
229 .result()?;
230 Ok(Instance::load(&self.static_fn, instance))
231 }
232
233 pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
235 unsafe {
236 read_into_uninitialized_vector(|count, data| {
237 (self.entry_fn_1_0.enumerate_instance_layer_properties)(count, data)
238 })
239 }
240 }
241
242 pub fn enumerate_instance_extension_properties(
244 &self,
245 layer_name: Option<&CStr>,
246 ) -> VkResult<Vec<vk::ExtensionProperties>> {
247 unsafe {
248 read_into_uninitialized_vector(|count, data| {
249 (self.entry_fn_1_0.enumerate_instance_extension_properties)(
250 layer_name.map_or(ptr::null(), |str| str.as_ptr()),
251 count,
252 data,
253 )
254 })
255 }
256 }
257
258 pub unsafe fn get_instance_proc_addr(
260 &self,
261 instance: vk::Instance,
262 p_name: *const c_char,
263 ) -> vk::PFN_vkVoidFunction {
264 (self.static_fn.get_instance_proc_addr)(instance, p_name)
265 }
266}
267
268#[allow(non_camel_case_types)]
270impl Entry {
271 pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
272 &self.entry_fn_1_1
273 }
274
275 #[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version()` instead"]
276 pub fn enumerate_instance_version(&self) -> VkResult<u32> {
280 unsafe {
281 let mut api_version = 0;
282 (self.entry_fn_1_1.enumerate_instance_version)(&mut api_version)
283 .result_with_success(api_version)
284 }
285 }
286}
287
288#[allow(non_camel_case_types)]
290impl Entry {
291 pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
292 &self.entry_fn_1_2
293 }
294}
295
296#[allow(non_camel_case_types)]
298impl Entry {
299 pub fn fp_v1_3(&self) -> &vk::EntryFnV1_3 {
300 &self.entry_fn_1_3
301 }
302}
303
304#[cfg(feature = "linked")]
305#[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
306impl Default for Entry {
307 fn default() -> Self {
308 Self::linked()
309 }
310}
311
312impl vk::StaticFn {
313 pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
314 where
315 F: FnMut(&::std::ffi::CStr) -> *const c_void,
316 {
317 static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
319
320 Ok(Self {
321 get_instance_proc_addr: unsafe {
322 let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
323 let val = _f(cname);
324 if val.is_null() {
325 return Err(MissingEntryPoint);
326 } else {
327 ::std::mem::transmute(val)
328 }
329 },
330 })
331 }
332}
333
334#[derive(Clone, Debug)]
335pub struct MissingEntryPoint;
336impl std::fmt::Display for MissingEntryPoint {
337 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
338 write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
339 }
340}
341impl std::error::Error for MissingEntryPoint {}
342
343#[cfg(feature = "linked")]
344extern "system" {
345 fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char)
346 -> vk::PFN_vkVoidFunction;
347}
348
349#[cfg(feature = "loaded")]
350mod loaded {
351 use std::error::Error;
352 use std::fmt;
353
354 use super::*;
355
356 #[derive(Debug)]
357 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
358 pub enum LoadingError {
359 LibraryLoadFailure(libloading::Error),
360 MissingEntryPoint(MissingEntryPoint),
361 }
362
363 impl fmt::Display for LoadingError {
364 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
365 match self {
366 LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
367 LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
368 }
369 }
370 }
371
372 impl Error for LoadingError {
373 fn source(&self) -> Option<&(dyn Error + 'static)> {
374 Some(match self {
375 LoadingError::LibraryLoadFailure(err) => err,
376 LoadingError::MissingEntryPoint(err) => err,
377 })
378 }
379 }
380
381 impl From<MissingEntryPoint> for LoadingError {
382 fn from(err: MissingEntryPoint) -> Self {
383 Self::MissingEntryPoint(err)
384 }
385 }
386}
387#[cfg(feature = "loaded")]
388pub use self::loaded::*;