1use crate::instance::Instance;
2#[cfg(doc)]
3use crate::khr;
4use crate::prelude::*;
5use crate::vk;
6use crate::RawPtr;
7use alloc::vec::Vec;
8use core::ffi;
9use core::fmt;
10use core::mem;
11use core::ptr;
12
13#[cfg(feature = "loaded")]
14use libloading::Library;
15
16#[derive(Clone)]
18pub struct Entry {
19 static_fn: crate::StaticFn,
20 entry_fn_1_0: crate::EntryFnV1_0,
21 entry_fn_1_1: crate::EntryFnV1_1,
22 #[cfg(feature = "loaded")]
23 _lib_guard: Option<alloc::sync::Arc<Library>>,
24}
25
26impl Entry {
28 #[cfg(feature = "loaded")]
60 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
61 pub unsafe fn load() -> Result<Self, LoadingError> {
62 #[cfg(windows)]
63 const LIB_PATH: &str = "vulkan-1.dll";
64
65 #[cfg(all(
66 unix,
67 not(any(
68 target_os = "macos",
69 target_os = "ios",
70 target_os = "android",
71 target_os = "fuchsia"
72 ))
73 ))]
74 const LIB_PATH: &str = "libvulkan.so.1";
75
76 #[cfg(any(target_os = "android", target_os = "fuchsia"))]
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(crate::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<std::ffi::OsStr>) -> Result<Self, LoadingError> {
139 let lib = Library::new(path)
140 .map_err(LoadingError::LibraryLoadFailure)
141 .map(alloc::sync::Arc::new)?;
142
143 let static_fn = crate::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: crate::StaticFn) -> Self {
162 let load_fn = move |name: &ffi::CStr| {
163 mem::transmute((static_fn.get_instance_proc_addr)(
164 vk::Instance::null(),
165 name.as_ptr(),
166 ))
167 };
168
169 Self::from_parts_1_1(
170 static_fn,
171 crate::EntryFnV1_0::load(load_fn),
172 crate::EntryFnV1_1::load(load_fn),
173 )
174 }
175
176 #[inline]
177 pub fn from_parts_1_1(
178 static_fn: crate::StaticFn,
179 entry_fn_1_0: crate::EntryFnV1_0,
180 entry_fn_1_1: crate::EntryFnV1_1,
181 ) -> Self {
182 Self {
183 static_fn,
184 entry_fn_1_0,
185 entry_fn_1_1,
186 #[cfg(feature = "loaded")]
187 _lib_guard: None,
188 }
189 }
190
191 #[inline]
192 pub fn fp_v1_0(&self) -> &crate::EntryFnV1_0 {
193 &self.entry_fn_1_0
194 }
195
196 #[inline]
197 pub fn static_fn(&self) -> &crate::StaticFn {
198 &self.static_fn
199 }
200
201 #[inline]
222 pub unsafe fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
223 let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
224 let name = ffi::CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0");
225 mem::transmute((self.static_fn.get_instance_proc_addr)(
226 vk::Instance::null(),
227 name.as_ptr(),
228 ))
229 };
230 if let Some(enumerate_instance_version) = enumerate_instance_version {
231 let mut api_version = mem::MaybeUninit::uninit();
232 (enumerate_instance_version)(api_version.as_mut_ptr())
233 .assume_init_on_success(api_version)
234 .map(Some)
235 } else {
236 Ok(None)
237 }
238 }
239
240 #[inline]
252 pub unsafe fn create_instance(
253 &self,
254 create_info: &vk::InstanceCreateInfo<'_>,
255 allocation_callbacks: Option<&vk::AllocationCallbacks<'_>>,
256 ) -> VkResult<Instance> {
257 let mut instance = mem::MaybeUninit::uninit();
258 let instance = (self.entry_fn_1_0.create_instance)(
259 create_info,
260 allocation_callbacks.as_raw_ptr(),
261 instance.as_mut_ptr(),
262 )
263 .assume_init_on_success(instance)?;
264 Ok(Instance::load(&self.static_fn, instance))
265 }
266
267 #[inline]
269 pub unsafe fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
270 read_into_uninitialized_vector(|count, data| {
271 (self.entry_fn_1_0.enumerate_instance_layer_properties)(count, data)
272 })
273 }
274
275 #[inline]
277 pub unsafe fn enumerate_instance_extension_properties(
278 &self,
279 layer_name: Option<&ffi::CStr>,
280 ) -> VkResult<Vec<vk::ExtensionProperties>> {
281 read_into_uninitialized_vector(|count, data| {
282 (self.entry_fn_1_0.enumerate_instance_extension_properties)(
283 layer_name.map_or(ptr::null(), |str| str.as_ptr()),
284 count,
285 data,
286 )
287 })
288 }
289
290 #[inline]
292 pub unsafe fn get_instance_proc_addr(
293 &self,
294 instance: vk::Instance,
295 p_name: *const ffi::c_char,
296 ) -> vk::PFN_vkVoidFunction {
297 (self.static_fn.get_instance_proc_addr)(instance, p_name)
298 }
299}
300
301impl Entry {
303 #[inline]
304 pub fn fp_v1_1(&self) -> &crate::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 unsafe fn enumerate_instance_version(&self) -> VkResult<u32> {
314 let mut api_version = mem::MaybeUninit::uninit();
315 (self.entry_fn_1_1.enumerate_instance_version)(api_version.as_mut_ptr())
316 .assume_init_on_success(api_version)
317 }
318}
319
320#[cfg(feature = "linked")]
321#[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
322impl Default for Entry {
323 #[inline]
324 fn default() -> Self {
325 Self::linked()
326 }
327}
328
329impl crate::StaticFn {
330 pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
331 where
332 F: FnMut(&ffi::CStr) -> *const ffi::c_void,
333 {
334 Ok(Self {
335 get_instance_proc_addr: unsafe {
336 let cname = ffi::CStr::from_bytes_with_nul_unchecked(b"vkGetInstanceProcAddr\0");
337 let val = _f(cname);
338 if val.is_null() {
339 return Err(MissingEntryPoint);
340 } else {
341 mem::transmute(val)
342 }
343 },
344 })
345 }
346}
347
348#[derive(Clone, Debug)]
349pub struct MissingEntryPoint;
350impl fmt::Display for MissingEntryPoint {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
353 }
354}
355#[cfg(feature = "std")] impl std::error::Error for MissingEntryPoint {}
357
358#[cfg(feature = "linked")]
359extern "system" {
360 fn vkGetInstanceProcAddr(
361 instance: vk::Instance,
362 name: *const ffi::c_char,
363 ) -> vk::PFN_vkVoidFunction;
364}
365
366#[cfg(feature = "loaded")]
367mod loaded {
368
369 use super::*;
370
371 #[derive(Debug)]
372 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
373 pub enum LoadingError {
374 LibraryLoadFailure(libloading::Error),
375 MissingEntryPoint(MissingEntryPoint),
376 }
377
378 impl fmt::Display for LoadingError {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 match self {
381 Self::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
382 Self::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
383 }
384 }
385 }
386
387 #[cfg(feature = "std")]
388 impl std::error::Error for LoadingError {
389 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
390 Some(match self {
391 Self::LibraryLoadFailure(err) => err,
392 Self::MissingEntryPoint(err) => err,
393 })
394 }
395 }
396
397 impl From<MissingEntryPoint> for LoadingError {
398 fn from(err: MissingEntryPoint) -> Self {
399 Self::MissingEntryPoint(err)
400 }
401 }
402}
403#[cfg(feature = "loaded")]
404pub use self::loaded::*;