use crate::lazyfn;
use crate::{FnPtr, LinkType};
use std::ffi::CStr;
use std::sync::atomic::Ordering;
use std::{ffi, mem};
extern crate self as dylink;
#[doc(hidden)]
#[repr(transparent)]
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct VkInstance(pub(crate) *mut ffi::c_void);
unsafe impl Sync for VkInstance {}
unsafe impl Send for VkInstance {}
#[doc(hidden)]
#[repr(transparent)]
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct VkDevice(pub(crate) *mut ffi::c_void);
unsafe impl Sync for VkDevice {}
unsafe impl Send for VkDevice {}
#[cfg_attr(windows, crate::dylink(name = "vulkan-1.dll"))]
#[cfg_attr(
all(unix, not(target_os = "macos")),
crate::dylink(any(name = "libvulkan.so.1", name = "libvulkan.so"))
)]
#[cfg_attr(
target_os = "macos",
crate::dylink(any(
name = "libvulkan.dylib",
name = "libvulkan.1.dylib",
name = "libMoltenVK.dylib"
))
)]
extern "system" {
pub(crate) fn vkGetInstanceProcAddr(
instance: VkInstance,
pName: *const ffi::c_char,
) -> Option<FnPtr>;
}
#[allow(non_camel_case_types)]
pub(crate) type PFN_vkGetDeviceProcAddr =
unsafe extern "system" fn(VkDevice, *const ffi::c_char) -> Option<FnPtr>;
#[allow(non_camel_case_types)]
pub(crate) type PFN_vkGetInstanceProcAddr =
unsafe extern "system" fn(VkInstance, *const ffi::c_char) -> Option<FnPtr>;
#[allow(non_snake_case)]
#[inline]
pub(crate) unsafe extern "system" fn vkGetDeviceProcAddr(
device: VkDevice,
name: *const ffi::c_char,
) -> Option<FnPtr> {
unsafe extern "system" fn initial_fn(
device: VkDevice,
name: *const ffi::c_char,
) -> Option<FnPtr> {
DEVICE_PROC_ADDR.once.call_once(|| {
let read_lock = crate::VK_INSTANCE.read().expect("failed to get read lock");
let fn_ptr = read_lock
.iter()
.find_map(|instance| {
vkGetInstanceProcAddr(
*instance,
b"vkGetDeviceProcAddr\0".as_ptr() as *const ffi::c_char,
)
})
.unwrap();
DEVICE_PROC_ADDR.addr.set(mem::transmute_copy(&fn_ptr));
DEVICE_PROC_ADDR
.addr_ptr
.store(DEVICE_PROC_ADDR.addr.as_ptr(), Ordering::Relaxed);
});
DEVICE_PROC_ADDR(device, name)
}
pub(crate) static DEVICE_PROC_ADDR: lazyfn::LazyFn<PFN_vkGetDeviceProcAddr> =
lazyfn::LazyFn::new(
&(initial_fn as PFN_vkGetDeviceProcAddr),
unsafe { CStr::from_bytes_with_nul_unchecked(b"vkGetDeviceProcAddr\0") },
LinkType::General(&[]),
);
DEVICE_PROC_ADDR(device, name)
}