use crate::raw::bindings::*;
use std::ffi::c_void;
use std::sync::Arc;
pub struct VulkanLibrary {
_library: Arc<libloading::Library>,
get_instance_proc_addr: unsafe extern "system" fn(*mut c_void, *const i8) -> *mut c_void,
}
impl VulkanLibrary {
pub fn new() -> Result<Self, libloading::Error> {
let library = unsafe {
#[cfg(windows)]
let lib = libloading::Library::new("vulkan-1.dll")?;
#[cfg(unix)]
let lib = libloading::Library::new("libvulkan.so.1")?;
Arc::new(lib)
};
let get_instance_proc_addr = unsafe {
*library.get::<unsafe extern "system" fn(*mut c_void, *const i8) -> *mut c_void>(
b"vkGetInstanceProcAddr\0",
)?
};
Ok(Self {
_library: library,
get_instance_proc_addr,
})
}
pub unsafe fn load_entry(&self) -> VkEntryDispatchTable {
let gipa = self.get_instance_proc_addr;
unsafe {
VkEntryDispatchTable::load(|name| (gipa)(std::ptr::null_mut(), name.as_ptr().cast()))
}
}
pub unsafe fn load_instance(&self, instance: VkInstance) -> VkInstanceDispatchTable {
let gipa = self.get_instance_proc_addr;
unsafe {
VkInstanceDispatchTable::load(|name| (gipa)(instance.cast(), name.as_ptr().cast()))
}
}
pub unsafe fn load_device(
&self,
instance: VkInstance,
device: VkDevice,
) -> VkDeviceDispatchTable {
let gipa = self.get_instance_proc_addr;
let gdpa_name = c"vkGetDeviceProcAddr";
let gdpa_ptr = unsafe { (gipa)(instance.cast(), gdpa_name.as_ptr().cast()) };
if !gdpa_ptr.is_null() {
let gdpa: unsafe extern "system" fn(*mut c_void, *const i8) -> *mut c_void =
unsafe { std::mem::transmute(gdpa_ptr) };
unsafe {
VkDeviceDispatchTable::load(|name| (gdpa)(device.cast(), name.as_ptr().cast()))
}
} else {
unsafe {
VkDeviceDispatchTable::load(|name| (gipa)(instance.cast(), name.as_ptr().cast()))
}
}
}
}