use crate::instance::Instance;
use crate::prelude::*;
use crate::vk;
use crate::RawPtr;
use std::error::Error;
use std::ffi::CStr;
use std::fmt;
use std::mem;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ptr;
#[derive(Clone)]
pub struct EntryCustom<L> {
static_fn: vk::StaticFn,
entry_fn_1_0: vk::EntryFnV1_0,
entry_fn_1_1: vk::EntryFnV1_1,
entry_fn_1_2: vk::EntryFnV1_2,
lib: L,
}
#[allow(non_camel_case_types)]
impl<L> EntryCustom<L> {
pub fn new_custom<Load>(
mut lib: L,
mut load: Load,
) -> std::result::Result<Self, MissingEntryPoint>
where
Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void,
{
let static_fn = vk::StaticFn::load_checked(|name| load(&mut lib, name))?;
let load_fn = |name: &std::ffi::CStr| unsafe {
mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
};
let entry_fn_1_0 = vk::EntryFnV1_0::load(load_fn);
let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
Ok(EntryCustom {
static_fn,
entry_fn_1_0,
entry_fn_1_1,
entry_fn_1_2,
lib,
})
}
pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
&self.entry_fn_1_0
}
pub fn static_fn(&self) -> &vk::StaticFn {
&self.static_fn
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceVersion.html>"]
pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
unsafe {
let mut api_version = 0;
let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
let name = b"vkEnumerateInstanceVersion\0".as_ptr() as *const _;
mem::transmute(
self.static_fn
.get_instance_proc_addr(vk::Instance::null(), name),
)
};
if let Some(enumerate_instance_version) = enumerate_instance_version {
(enumerate_instance_version)(&mut api_version)
.result_with_success(Some(api_version))
} else {
Ok(None)
}
}
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateInstance.html>"]
pub unsafe fn create_instance(
&self,
create_info: &vk::InstanceCreateInfo,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
) -> Result<Instance, InstanceError> {
let mut instance = mem::zeroed();
self.entry_fn_1_0
.create_instance(
create_info,
allocation_callbacks.as_raw_ptr(),
&mut instance,
)
.result()
.map_err(InstanceError::VkError)?;
Ok(Instance::load(&self.static_fn, instance))
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceLayerProperties.html>"]
pub fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
unsafe {
let mut count = 0;
self.entry_fn_1_0
.enumerate_instance_layer_properties(&mut count, ptr::null_mut())
.result()?;
let mut v = Vec::with_capacity(count as usize);
let err_code = self
.entry_fn_1_0
.enumerate_instance_layer_properties(&mut count, v.as_mut_ptr());
v.set_len(count as usize);
err_code.result_with_success(v)
}
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>"]
pub fn enumerate_instance_extension_properties(
&self,
) -> VkResult<Vec<vk::ExtensionProperties>> {
unsafe {
let mut count = 0;
self.entry_fn_1_0
.enumerate_instance_extension_properties(ptr::null(), &mut count, ptr::null_mut())
.result()?;
let mut data = Vec::with_capacity(count as usize);
let err_code = self.entry_fn_1_0.enumerate_instance_extension_properties(
ptr::null(),
&mut count,
data.as_mut_ptr(),
);
data.set_len(count as usize);
err_code.result_with_success(data)
}
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html>"]
pub unsafe fn get_instance_proc_addr(
&self,
instance: vk::Instance,
p_name: *const c_char,
) -> vk::PFN_vkVoidFunction {
self.static_fn.get_instance_proc_addr(instance, p_name)
}
}
#[allow(non_camel_case_types)]
impl<L> EntryCustom<L> {
pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
&self.entry_fn_1_1
}
#[deprecated = "This function is unavailable and therefore panics on Vulkan 1.0, please use `try_enumerate_instance_version` instead"]
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceVersion.html>"]
pub fn enumerate_instance_version(&self) -> VkResult<u32> {
unsafe {
let mut api_version = 0;
self.entry_fn_1_1
.enumerate_instance_version(&mut api_version)
.result_with_success(api_version)
}
}
}
#[allow(non_camel_case_types)]
impl<L> EntryCustom<L> {
pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
&self.entry_fn_1_2
}
}
#[derive(Clone, Debug)]
pub enum InstanceError {
LoadError(Vec<&'static str>),
VkError(vk::Result),
}
impl fmt::Display for InstanceError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InstanceError::LoadError(e) => write!(f, "{}", e.join("; ")),
InstanceError::VkError(e) => write!(f, "{}", e),
}
}
}
impl Error for InstanceError {}
impl vk::StaticFn {
pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
where
F: FnMut(&::std::ffi::CStr) -> *const c_void,
{
static ENTRY_POINT: &[u8] = b"vkGetInstanceProcAddr\0";
Ok(vk::StaticFn {
get_instance_proc_addr: unsafe {
let cname = CStr::from_bytes_with_nul_unchecked(ENTRY_POINT);
let val = _f(cname);
if val.is_null() {
return Err(MissingEntryPoint);
} else {
::std::mem::transmute(val)
}
},
})
}
}
#[derive(Clone, Debug)]
pub struct MissingEntryPoint;
impl std::fmt::Display for MissingEntryPoint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "Cannot load `vkGetInstanceProcAddr` symbol from library")
}
}
impl std::error::Error for MissingEntryPoint {}