use crate::core as vk;
use crate::load::{
CallError, Capabilities, CommandSupport, CreatedHandle, Entry, InitializationFailure, LoadError,
};
use libloading::Library;
use std::sync::Arc;
pub struct Instance {
handle: vk::InstanceHandle,
fp: vk::FnInstance,
pub(super) gipa: unsafe extern "system" fn(
vk::InstanceHandle,
*const std::ffi::c_char,
) -> vk::PFN_vkVoidFunction,
pub(crate) library: Option<Arc<Library>>,
pub(crate) capabilities: Option<Capabilities>,
}
impl Instance {
pub unsafe fn new_from_handle(
entry: &Entry,
handle: vk::InstanceHandle,
) -> Result<Self, LoadError> {
if handle.is_null() {
return Err(LoadError::NullHandle("instance"));
}
let fp = unsafe { vk::FnInstance::new_from_resolver(entry.gipa, handle) };
if fp.destroy_instance.is_none() {
return Err(LoadError::MissingSymbol("vkDestroyInstance"));
}
Ok(Self {
handle,
fp,
gipa: entry.gipa,
library: entry.library.clone(),
capabilities: None,
})
}
pub unsafe fn new_from_handle_with_capabilities(
entry: &Entry,
handle: vk::InstanceHandle,
capabilities: Capabilities,
) -> Result<Self, LoadError> {
if capabilities.is_device() {
return Err(LoadError::InvalidMetadata(
"instance import needs instance capabilities",
));
}
let mut instance = unsafe { Self::new_from_handle(entry, handle) }?;
instance
.fp
.retain_enabled(|command| capabilities.support(command) != CommandSupport::Disabled);
instance.capabilities = Some(capabilities);
Ok(instance)
}
pub fn handle(&self) -> vk::InstanceHandle {
self.handle
}
pub fn fp(&self) -> &vk::FnInstance {
&self.fp
}
pub fn capabilities(&self) -> Option<&Capabilities> {
self.capabilities.as_ref()
}
pub unsafe fn destroy(self, allocator: Option<&vk::AllocationCallbacks>) {
unsafe { destroy_instance(self, allocator) };
}
}
pub unsafe fn create_instance(
entry: &Entry,
create_info: &vk::InstanceCreateInfo,
allocator: Option<&vk::AllocationCallbacks>,
) -> Result<Instance, CallError> {
let mut capabilities = unsafe { Capabilities::instance(create_info) }?;
capabilities.limit_instance_version(entry.enumerate_instance_version()?)?;
let allocator_ptr = allocator.map_or(std::ptr::null(), |a| a);
let mut handle = vk::InstanceHandle::NULL;
let result =
unsafe { entry.fp().create_instance.unwrap()(create_info, allocator_ptr, &mut handle) };
if result != vk::Result::SUCCESS {
return Err(CallError::Vulkan(result));
}
if handle.is_null() {
return Err(CallError::InvalidOutput(
"vkCreateInstance returned a null handle",
));
}
let mut fp = unsafe { vk::FnInstance::new_from_resolver(entry.gipa, handle) };
if fp.destroy_instance.is_none() {
let failure = InitializationFailure {
handle: CreatedHandle::Instance(handle),
missing_command: "vkDestroyInstance",
library: entry.library.clone(),
instance: handle,
gipa: entry.gipa,
gdpa: None,
};
return match unsafe { failure.destroy(allocator) } {
Ok(()) => Err(CallError::MissingCommand("vkDestroyInstance")),
Err(failure) => Err(CallError::InitializationFailed(failure)),
};
}
fp.retain_enabled(|command| capabilities.support(command) != CommandSupport::Disabled);
Ok(Instance {
handle,
fp,
gipa: entry.gipa,
library: entry.library.clone(),
capabilities: Some(capabilities),
})
}
impl Instance {
pub unsafe fn new(
entry: &Entry,
create_info: &vk::InstanceCreateInfo,
allocator: Option<&vk::AllocationCallbacks>,
) -> Result<Self, CallError> {
unsafe { create_instance(entry, create_info, allocator) }
}
}
use super::command::commands;
commands! { Instance, instance;
pub unsafe fn get_instance_proc_addr(name: &std::ffi::CStr) -> vk::PFN_vkVoidFunction {
unsafe { (instance.gipa)(instance.handle, name.as_ptr()) }
}
pub unsafe fn enumerate_physical_devices() -> Result<Vec<vk::PhysicalDevice>, CallError> {
let f = instance
.fp
.enumerate_physical_devices
.ok_or(CallError::MissingCommand("vkEnumeratePhysicalDevices"))?;
unsafe { crate::load::enumerate::enumerate(|count, data| f(instance.handle, count, data)) }
}
pub unsafe fn get_physical_device_properties(
physical_device: vk::PhysicalDevice,
) -> Result<vk::PhysicalDeviceProperties, CallError> {
let f = instance
.fp
.get_physical_device_properties
.ok_or(CallError::MissingCommand("vkGetPhysicalDeviceProperties"))?;
let mut props = unsafe { std::mem::zeroed::<vk::PhysicalDeviceProperties>() };
unsafe { f(physical_device, &mut props) };
Ok(props)
}
pub unsafe fn get_physical_device_features(
physical_device: vk::PhysicalDevice,
) -> Result<vk::PhysicalDeviceFeatures, CallError> {
let f = instance
.fp
.get_physical_device_features
.ok_or(CallError::MissingCommand("vkGetPhysicalDeviceFeatures"))?;
let mut features = unsafe { std::mem::zeroed::<vk::PhysicalDeviceFeatures>() };
unsafe { f(physical_device, &mut features) };
Ok(features)
}
pub unsafe fn get_physical_device_queue_family_properties(
physical_device: vk::PhysicalDevice,
) -> Result<Vec<vk::QueueFamilyProperties>, CallError> {
let f = instance
.fp
.get_physical_device_queue_family_properties
.ok_or(CallError::MissingCommand(
"vkGetPhysicalDeviceQueueFamilyProperties",
))?;
unsafe { crate::load::enumerate::enumerate_void(|count, data| f(physical_device, count, data)) }
}
pub unsafe fn enumerate_device_extension_properties(
physical_device: vk::PhysicalDevice,
layer_name: Option<&std::ffi::CStr>,
) -> Result<Vec<vk::ExtensionProperties>, CallError> {
let f = instance
.fp
.enumerate_device_extension_properties
.ok_or(CallError::MissingCommand(
"vkEnumerateDeviceExtensionProperties",
))?;
let layer_ptr = layer_name.map_or(std::ptr::null(), |l| l.as_ptr());
unsafe {
crate::load::enumerate::enumerate(|count, data| f(physical_device, layer_ptr, count, data))
}
}
pub unsafe fn get_physical_device_memory_properties(
physical_device: vk::PhysicalDevice,
) -> Result<vk::PhysicalDeviceMemoryProperties, CallError> {
let f = instance
.fp
.get_physical_device_memory_properties
.ok_or(CallError::MissingCommand(
"vkGetPhysicalDeviceMemoryProperties",
))?;
let mut props = unsafe { std::mem::zeroed::<vk::PhysicalDeviceMemoryProperties>() };
unsafe { f(physical_device, &mut props) };
Ok(props)
}
}
pub unsafe fn destroy_instance(instance: Instance, allocator: Option<&vk::AllocationCallbacks>) {
unsafe {
instance.fp.destroy_instance.unwrap()(
instance.handle,
allocator.map_or(std::ptr::null(), |a| a),
)
};
}