pub use self::extensions::InstanceExtensions;
pub use self::layers::layers_list;
pub use self::layers::LayerProperties;
pub use self::layers::LayersListError;
pub use self::loader::LoadingError;
use crate::check_errors;
use crate::device::physical::{init_physical_devices, PhysicalDeviceInfo};
pub use crate::extensions::{
ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
};
pub use crate::fns::InstanceFunctions;
use crate::instance::loader::FunctionPointers;
use crate::instance::loader::Loader;
pub use crate::version::Version;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::ffi::CString;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ptr;
use std::sync::Arc;
pub mod debug;
pub(crate) mod extensions;
mod layers;
pub mod loader;
#[derive(Debug)]
pub struct Instance {
handle: ash::vk::Instance,
fns: InstanceFunctions,
pub(crate) physical_device_infos: Vec<PhysicalDeviceInfo>,
api_version: Version,
enabled_extensions: InstanceExtensions,
enabled_layers: Vec<String>,
function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader>>>,
max_api_version: Version,
}
impl ::std::panic::UnwindSafe for Instance {}
impl ::std::panic::RefUnwindSafe for Instance {}
impl Instance {
pub fn new(create_info: InstanceCreateInfo) -> Result<Arc<Instance>, InstanceCreationError> {
let InstanceCreateInfo {
application_name,
application_version,
enabled_extensions,
enabled_layers,
engine_name,
engine_version,
function_pointers,
max_api_version,
_ne: _,
} = create_info;
let function_pointers = if let Some(function_pointers) = function_pointers {
OwnedOrRef::Owned(function_pointers)
} else {
OwnedOrRef::Ref(loader::auto_loader()?)
};
let (api_version, max_api_version) = {
let api_version = function_pointers.api_version()?;
let max_api_version = if let Some(max_api_version) = max_api_version {
max_api_version
} else if api_version < Version::V1_1 {
api_version
} else {
Version::HEADER_VERSION
};
(std::cmp::min(max_api_version, api_version), max_api_version)
};
assert!(max_api_version >= Version::V1_0);
enabled_extensions.check_requirements(
&InstanceExtensions::supported_by_core_with_loader(&function_pointers)?,
api_version,
)?;
let enabled_layers_cstr: Vec<CString> = enabled_layers
.iter()
.map(|name| CString::new(name.clone()).unwrap())
.collect();
let enabled_layers_ptrs = enabled_layers_cstr
.iter()
.map(|layer| layer.as_ptr())
.collect::<SmallVec<[_; 2]>>();
let enabled_extensions_cstr: Vec<CString> = (&enabled_extensions).into();
let enabled_extensions_ptrs = enabled_extensions_cstr
.iter()
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 2]>>();
let application_name_cstr = application_name.map(|name| CString::new(name).unwrap());
let engine_name_cstr = engine_name.map(|name| CString::new(name).unwrap());
let application_info = ash::vk::ApplicationInfo {
p_application_name: application_name_cstr
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or(ptr::null()),
application_version: application_version
.try_into()
.expect("Version out of range"),
p_engine_name: engine_name_cstr
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or(ptr::null()),
engine_version: engine_version.try_into().expect("Version out of range"),
api_version: max_api_version.try_into().expect("Version out of range"),
..Default::default()
};
let create_info = ash::vk::InstanceCreateInfo {
flags: ash::vk::InstanceCreateFlags::empty(),
p_application_info: &application_info,
enabled_layer_count: enabled_layers_ptrs.len() as u32,
pp_enabled_layer_names: enabled_layers_ptrs.as_ptr(),
enabled_extension_count: enabled_extensions_ptrs.len() as u32,
pp_enabled_extension_names: enabled_extensions_ptrs.as_ptr(),
..Default::default()
};
let handle = unsafe {
let mut output = MaybeUninit::uninit();
let fns = function_pointers.fns();
check_errors(
fns.v1_0
.create_instance(&create_info, ptr::null(), output.as_mut_ptr()),
)?;
output.assume_init()
};
let fns = {
InstanceFunctions::load(|name| {
function_pointers.get_instance_proc_addr(handle, name.as_ptr())
})
};
let mut instance = Instance {
handle,
fns,
physical_device_infos: Vec::new(),
api_version,
enabled_extensions,
enabled_layers,
function_pointers,
max_api_version,
};
instance.physical_device_infos = init_physical_devices(&instance)?;
Ok(Arc::new(instance))
}
#[inline]
pub fn api_version(&self) -> Version {
self.api_version
}
#[inline]
pub fn max_api_version(&self) -> Version {
self.max_api_version
}
#[inline]
pub fn fns(&self) -> &InstanceFunctions {
&self.fns
}
#[inline]
pub fn enabled_extensions(&self) -> &InstanceExtensions {
&self.enabled_extensions
}
#[inline]
pub fn enabled_layers(&self) -> &[String] {
&self.enabled_layers
}
}
impl Drop for Instance {
#[inline]
fn drop(&mut self) {
unsafe {
self.fns.v1_0.destroy_instance(self.handle, ptr::null());
}
}
}
unsafe impl VulkanObject for Instance {
type Object = ash::vk::Instance;
#[inline]
fn internal_object(&self) -> ash::vk::Instance {
self.handle
}
}
impl PartialEq for Instance {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle
}
}
impl Eq for Instance {}
impl Hash for Instance {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle.hash(state);
}
}
#[derive(Debug)]
pub struct InstanceCreateInfo {
pub application_name: Option<String>,
pub application_version: Version,
pub enabled_extensions: InstanceExtensions,
pub enabled_layers: Vec<String>,
pub engine_name: Option<String>,
pub engine_version: Version,
pub function_pointers: Option<FunctionPointers<Box<dyn Loader>>>,
pub max_api_version: Option<Version>,
pub _ne: crate::NonExhaustive,
}
impl Default for InstanceCreateInfo {
#[inline]
fn default() -> Self {
Self {
application_name: None,
application_version: Version::major_minor(0, 0),
enabled_extensions: InstanceExtensions::none(),
enabled_layers: Vec::new(),
engine_name: None,
engine_version: Version::major_minor(0, 0),
function_pointers: None,
max_api_version: None,
_ne: crate::NonExhaustive(()),
}
}
}
impl InstanceCreateInfo {
#[inline]
pub fn application_from_cargo_toml() -> Self {
Self {
application_name: Some(env!("CARGO_PKG_NAME").to_owned()),
application_version: Version {
major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
},
..Default::default()
}
}
}
#[derive(Clone, Debug)]
pub enum InstanceCreationError {
LoadingError(LoadingError),
OomError(OomError),
InitializationFailed,
LayerNotPresent,
ExtensionNotPresent,
IncompatibleDriver,
ExtensionRestrictionNotMet(ExtensionRestrictionError),
}
impl error::Error for InstanceCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
InstanceCreationError::LoadingError(ref err) => Some(err),
InstanceCreationError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for InstanceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
InstanceCreationError::LoadingError(_) => {
write!(fmt, "failed to load the Vulkan shared library")
}
InstanceCreationError::OomError(_) => write!(fmt, "not enough memory available"),
InstanceCreationError::InitializationFailed => write!(fmt, "initialization failed"),
InstanceCreationError::LayerNotPresent => write!(fmt, "layer not present"),
InstanceCreationError::ExtensionNotPresent => write!(fmt, "extension not present"),
InstanceCreationError::IncompatibleDriver => write!(fmt, "incompatible driver"),
InstanceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
}
}
}
impl From<OomError> for InstanceCreationError {
#[inline]
fn from(err: OomError) -> InstanceCreationError {
InstanceCreationError::OomError(err)
}
}
impl From<LoadingError> for InstanceCreationError {
#[inline]
fn from(err: LoadingError) -> InstanceCreationError {
InstanceCreationError::LoadingError(err)
}
}
impl From<ExtensionRestrictionError> for InstanceCreationError {
#[inline]
fn from(err: ExtensionRestrictionError) -> Self {
Self::ExtensionRestrictionNotMet(err)
}
}
impl From<Error> for InstanceCreationError {
#[inline]
fn from(err: Error) -> InstanceCreationError {
match err {
err @ Error::OutOfHostMemory => InstanceCreationError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => InstanceCreationError::OomError(OomError::from(err)),
Error::InitializationFailed => InstanceCreationError::InitializationFailed,
Error::LayerNotPresent => InstanceCreationError::LayerNotPresent,
Error::ExtensionNotPresent => InstanceCreationError::ExtensionNotPresent,
Error::IncompatibleDriver => InstanceCreationError::IncompatibleDriver,
_ => panic!("unexpected error: {:?}", err),
}
}
}
#[derive(Debug)]
enum OwnedOrRef<T: 'static> {
Owned(T),
Ref(&'static T),
}
impl<T> Deref for OwnedOrRef<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
match *self {
OwnedOrRef::Owned(ref v) => v,
OwnedOrRef::Ref(v) => v,
}
}
}
#[cfg(test)]
mod tests {
use crate::device::physical::PhysicalDevice;
#[test]
fn create_instance() {
let _ = instance!();
}
#[test]
fn queue_family_by_id() {
let instance = instance!();
let phys = match PhysicalDevice::enumerate(&instance).next() {
Some(p) => p,
None => return,
};
let queue_family = match phys.queue_families().next() {
Some(q) => q,
None => return,
};
let by_id = phys.queue_family_by_id(queue_family.id()).unwrap();
assert_eq!(by_id.id(), queue_family.id());
}
}