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")]
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";
69
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";
75
76 #[cfg(target_os = "android")]
77 const LIB_PATH: &str = "libvulkan.so";
78
79 #[cfg(any(target_os = "macos", target_os = "ios"))]
80 const LIB_PATH: &str = "libvulkan.dylib";
81
82 Self::load_from(LIB_PATH)
83 }
84
85 #[cfg(feature = "linked")]
116 #[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
117 pub fn linked() -> Self {
118 unsafe {
121 Self::from_static_fn(vk::StaticFn {
122 get_instance_proc_addr: vkGetInstanceProcAddr,
123 })
124 }
125 }
126
127 #[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)?;
142
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 })?;
148
149 Ok(Self {
150 _lib_guard: Some(lib),
151 ..Self::from_static_fn(static_fn)
152 })
153 }
154
155 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);
172
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 }
183
184 #[inline]
185 pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
186 &self.entry_fn_1_0
187 }
188
189 #[inline]
190 pub fn static_fn(&self) -> &vk::StaticFn {
191 &self.static_fn
192 }
193
194 #[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 }
235
236 #[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 }
261
262 #[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 }
271
272 #[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 }
288
289 #[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 }
298}
299
300#[allow(non_camel_case_types)]
302impl Entry {
303 #[inline]
304 pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
305 &self.entry_fn_1_1
306 }
307
308 #[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version()` instead"]
309 #[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 }
320}
321
322#[allow(non_camel_case_types)]
324impl Entry {
325 #[inline]
326 pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
327 &self.entry_fn_1_2
328 }
329}
330
331#[allow(non_camel_case_types)]
333impl Entry {
334 #[inline]
335 pub fn fp_v1_3(&self) -> &vk::EntryFnV1_3 {
336 &self.entry_fn_1_3
337 }
338}
339
340#[cfg(feature = "linked")]
341#[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
342impl Default for Entry {
343 #[inline]
344 fn default() -> Self {
345 Self::linked()
346 }
347}
348
349impl 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 static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
356
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 }
369}
370
371#[derive(Clone, Debug)]
372pub struct MissingEntryPoint;
373impl 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 }
377}
378impl std::error::Error for MissingEntryPoint {}
379
380#[cfg(feature = "linked")]
381extern "system" {
382 fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char)
383 -> vk::PFN_vkVoidFunction;
384}
385
386#[cfg(feature = "loaded")]
387mod loaded {
388 use std::error::Error;
389 use std::fmt;
390
391 use super::*;
392
393 #[derive(Debug)]
394 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
395 pub enum LoadingError {
396 LibraryLoadFailure(libloading::Error),
397 MissingEntryPoint(MissingEntryPoint),
398 }
399
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 }
408
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 }
417
418 impl From<MissingEntryPoint> for LoadingError {
419 fn from(err: MissingEntryPoint) -> Self {
420 Self::MissingEntryPoint(err)
421 }
422 }
423}
424#[cfg(feature = "loaded")]
425pub use self::loaded::*;