use std::sync::atomic::{Ordering, AtomicPtr};
use std::{ffi, mem};
use crate::FnPtr;
use crate::lazyfn;
extern crate self as dylink;
#[doc(hidden)]
#[repr(transparent)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct VkInstance(pub(crate) *const ffi::c_void);
unsafe impl Sync for VkInstance {}
unsafe impl Send for VkInstance {}
#[doc(hidden)]
#[repr(transparent)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct VkDevice(pub(crate) *const 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)]
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();
let addr_ptr = DEVICE_PROC_ADDR.addr.get();
addr_ptr.write(Some(mem::transmute_copy(&fn_ptr)));
DEVICE_PROC_ADDR.addr_ptr.store(mem::transmute(addr_ptr), Ordering::Relaxed);
});
DEVICE_PROC_ADDR(device, name)
}
pub(crate) static DEVICE_PROC_ADDR: lazyfn::LazyFn<PFN_vkGetDeviceProcAddr> = lazyfn::LazyFn::new(
AtomicPtr::new(unsafe {std::mem::transmute(&(initial_fn as PFN_vkGetDeviceProcAddr))})
);
DEVICE_PROC_ADDR(device, name)
}