// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! API entry point. //! //! The first thing to do after loading the Vulkan library is to create an `Instance` object. //! //! For example: //! //! ```no_run //! use vulkano::{ //! instance::{Instance, InstanceExtensions}, //! Version, VulkanLibrary, //! }; //! //! let library = VulkanLibrary::new() //! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); //! let instance = Instance::new(library, Default::default()) //! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)); //! ``` //! //! Creating an instance initializes everything and allows you to enumerate physical devices, //! ie. all the Vulkan implementations that are available on the system. //! //! ```no_run //! # use vulkano::{ //! # instance::{Instance, InstanceExtensions}, //! # Version, VulkanLibrary, //! # }; //! use vulkano::device::physical::PhysicalDevice; //! //! # let library = VulkanLibrary::new().unwrap(); //! # let instance = Instance::new(library, Default::default()).unwrap(); //! for physical_device in instance.enumerate_physical_devices().unwrap() { //! println!("Available device: {}", physical_device.properties().device_name); //! } //! ``` //! //! # Enumerating physical devices and creating a device //! //! After you have created an instance, the next step is usually to enumerate the physical devices //! that are available on the system with `Instance::enumerate_physical_devices()` (see above). //! //! When choosing which physical device to use, keep in mind that physical devices may or may not //! be able to draw to a certain surface (ie. to a window or a monitor), or may even not be able //! to draw at all. See the `swapchain` module for more information about surfaces. //! //! Once you have chosen a physical device, you can create a `Device` object from it. See the //! `device` module for more info. //! //! # Portability subset devices and the `enumerate_portability` flag //! //! Certain devices, currently those on MacOS and iOS systems, do not fully conform to the Vulkan //! specification. They are usable as normal devices, but they do not implement everything that //! is required; some mandatory parts of Vulkan are missing. These are known as //! "portability subset" devices. //! //! A portability subset device will advertise support for the //! [`khr_portability_subset`](crate::device::DeviceExtensions::khr_portability_subset) device //! extension. This extension must always be enabled when it is supported, and Vulkano will //! automatically enable it when creating the device. When it is enabled, some parts of Vulkan that //! are available in standard Vulkan will not be available by default, but they can be used by //! enabling corresponding features when creating the device, if the device supports them. //! //! Because these devices are non-conformant, Vulkan programs that rely on full compliance may //! not work (crash or have validation errors) when run on them, if they happen to use a part of //! Vulkan that is missing from the non-conformant device. Therefore, Vulkan hides them from //! the user by default when calling `enumerate_physical_devices` on the instance. If there are no //! conformant devices on the system, `Instance::new` will return an `IncompatibleDriver` error. //! //! In order to enumerate portability subset devices, you must set the //! [`InstanceCreateInfo::enumerate_portability`] flag when creating the instance. However, if you //! do this, your program must be prepared to handle the non-conformant aspects of these devices, //! and must enable the appropriate features when creating the `Device` if you intend to use them. use self::debug::{ DebugUtilsMessengerCreateInfo, UserCallback, ValidationFeatureDisable, ValidationFeatureEnable, }; pub use self::{extensions::InstanceExtensions, layers::LayerProperties}; use crate::{ device::physical::PhysicalDevice, instance::debug::trampoline, macros::impl_id_counter, OomError, RequiresOneOf, VulkanError, VulkanLibrary, VulkanObject, }; pub use crate::{ extensions::{ExtensionRestriction, ExtensionRestrictionError}, fns::InstanceFunctions, version::Version, }; use smallvec::SmallVec; use std::{ error::Error, ffi::{c_void, CString}, fmt::{Debug, Display, Error as FmtError, Formatter}, mem::MaybeUninit, num::NonZeroU64, panic::{RefUnwindSafe, UnwindSafe}, ptr, sync::Arc, }; pub mod debug; pub(crate) mod extensions; mod layers; /// An instance of a Vulkan context. This is the main object that should be created by an /// application before everything else. /// /// # Application and engine info /// /// When you create an instance, you have the possibility to set information about your application /// and its engine. /// /// Providing this information allows for example the driver to let the user configure the driver's /// behavior for your application alone through a control panel. /// /// ```no_run /// # #[macro_use] extern crate vulkano; /// # fn main() { /// use vulkano::{ /// instance::{Instance, InstanceCreateInfo, InstanceExtensions}, /// Version, VulkanLibrary, /// }; /// /// let library = VulkanLibrary::new().unwrap(); /// let _instance = Instance::new( /// library, /// InstanceCreateInfo::application_from_cargo_toml(), /// ).unwrap(); /// # } /// ``` /// /// # API versions /// /// Both an `Instance` and a [`Device`](crate::device::Device) have a highest version of the Vulkan /// API that they support. This places a limit on what Vulkan functions and features are available /// to use when used on a particular instance or device. It is possible for the instance and the /// device to support different versions. The supported version for an instance can be queried /// before creation with /// [`VulkanLibrary::api_version`](crate::VulkanLibrary::api_version), /// while for a device it can be retrieved with /// [`PhysicalDevice::api_version`](crate::device::physical::PhysicalDevice::api_version). /// /// When creating an `Instance`, you have to specify a maximum API version that you will use. /// This restricts the API version that is available for the instance and any devices created from /// it. For example, if both instance and device potentially support Vulkan 1.2, but you specify /// 1.1 as the maximum API version when creating the `Instance`, then you can only use Vulkan 1.1 /// functions, even though they could theoretically support a higher version. You can think of it /// as a promise never to use any functionality from a higher version. /// /// The maximum API version is not a _minimum_, so it is possible to set it to a higher version than /// what the instance or device inherently support. The final API version that you are able to use /// on an instance or device is the lower of the supported API version and the chosen maximum API /// version of the `Instance`. /// /// Due to a quirk in how the Vulkan 1.0 specification was written, if the instance only /// supports Vulkan 1.0, then it is not possible to specify a maximum API version higher than 1.0. /// Trying to create an `Instance` will return an `IncompatibleDriver` error. Consequently, it is /// not possible to use a higher device API version with an instance that only supports 1.0. /// /// # Extensions /// /// When creating an `Instance`, you must provide a list of extensions that must be enabled on the /// newly-created instance. Trying to enable an extension that is not supported by the system will /// result in an error. /// /// Contrary to OpenGL, it is not possible to use the features of an extension if it was not /// explicitly enabled. /// /// Extensions are especially important to take into account if you want to render images on the /// screen, as the only way to do so is to use the `VK_KHR_surface` extension. More information /// about this in the `swapchain` module. /// /// For example, here is how we create an instance with the `VK_KHR_surface` and /// `VK_KHR_android_surface` extensions enabled, which will allow us to render images to an /// Android screen. You can compile and run this code on any system, but it is highly unlikely to /// succeed on anything else than an Android-running device. /// /// ```no_run /// use vulkano::{ /// instance::{Instance, InstanceCreateInfo, InstanceExtensions}, /// Version, VulkanLibrary, /// }; /// /// let library = VulkanLibrary::new() /// .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); /// /// let extensions = InstanceExtensions { /// khr_surface: true, /// khr_android_surface: true, /// .. InstanceExtensions::empty() /// }; /// /// let instance = Instance::new( /// library, /// InstanceCreateInfo { /// enabled_extensions: extensions, /// ..Default::default() /// }, /// ) /// .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)); /// ``` /// /// # Layers /// /// When creating an `Instance`, you have the possibility to pass a list of **layers** that will /// be activated on the newly-created instance. The list of available layers can be retrieved by /// calling the [`layer_properties`](crate::VulkanLibrary::layer_properties) method of /// `VulkanLibrary`. /// /// A layer is a component that will hook and potentially modify the Vulkan function calls. /// For example, activating a layer could add a frames-per-second counter on the screen, or it /// could send information to a debugger that will debug your application. /// /// > **Note**: From an application's point of view, layers "just exist". In practice, on Windows /// > and Linux, layers can be installed by third party installers or by package managers and can /// > also be activated by setting the value of the `VK_INSTANCE_LAYERS` environment variable /// > before starting the program. See the documentation of the official Vulkan loader for these /// > platforms. /// /// > **Note**: In practice, the most common use of layers right now is for debugging purposes. /// > To do so, you are encouraged to set the `VK_INSTANCE_LAYERS` environment variable on Windows /// > or Linux instead of modifying the source code of your program. For example: /// > `export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump` on Linux if you installed the Vulkan SDK /// > will print the list of raw Vulkan function calls. /// /// ## Examples /// /// ``` /// # use std::{sync::Arc, error::Error}; /// # use vulkano::{ /// # instance::{Instance, InstanceCreateInfo, InstanceExtensions}, /// # Version, VulkanLibrary, /// # }; /// # fn test() -> Result, Box> { /// let library = VulkanLibrary::new()?; /// /// // For the sake of the example, we activate all the layers that /// // contain the word "foo" in their description. /// let layers: Vec<_> = library.layer_properties()? /// .filter(|l| l.description().contains("foo")) /// .collect(); /// /// let instance = Instance::new( /// library, /// InstanceCreateInfo { /// enabled_layers: layers.iter().map(|l| l.name().to_owned()).collect(), /// ..Default::default() /// }, /// )?; /// # Ok(instance) /// # } /// ``` // TODO: mention that extensions must be supported by layers as well pub struct Instance { handle: ash::vk::Instance, fns: InstanceFunctions, id: NonZeroU64, api_version: Version, enabled_extensions: InstanceExtensions, enabled_layers: Vec, library: Arc, max_api_version: Version, _user_callbacks: Vec>, } // TODO: fix the underlying cause instead impl UnwindSafe for Instance {} impl RefUnwindSafe for Instance {} impl Instance { /// Creates a new `Instance`. /// /// # Panics /// /// - Panics if any version numbers in `create_info` contain a field too large to be converted /// into a Vulkan version number. /// - Panics if `create_info.max_api_version` is not at least `V1_0`. pub fn new( library: Arc, create_info: InstanceCreateInfo, ) -> Result, InstanceCreationError> { unsafe { Self::with_debug_utils_messengers(library, create_info, []) } } /// Creates a new `Instance` with debug messengers to use during the creation and destruction /// of the instance. /// /// The debug messengers are not used at any other time, /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger) should be used for /// that. /// /// If `debug_utils_messengers` is not empty, the `ext_debug_utils` extension must be set in /// `enabled_extensions`. /// /// # Panics /// /// - Panics if the `message_severity` or `message_type` members of any element of /// `debug_utils_messengers` are empty. /// /// # Safety /// /// - The `user_callback` of each element of `debug_utils_messengers` must not make any calls /// to the Vulkan API. pub unsafe fn with_debug_utils_messengers( library: Arc, create_info: InstanceCreateInfo, debug_utils_messengers: impl IntoIterator, ) -> Result, InstanceCreationError> { let InstanceCreateInfo { application_name, application_version, mut enabled_extensions, enabled_layers, engine_name, engine_version, max_api_version, enumerate_portability, enabled_validation_features, disabled_validation_features, _ne: _, } = create_info; let (api_version, max_api_version) = { let api_version = library.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) }; // VUID-VkApplicationInfo-apiVersion-04010 assert!(max_api_version >= Version::V1_0); let supported_extensions = library.supported_extensions_with_layers(enabled_layers.iter().map(String::as_str))?; let mut flags = ash::vk::InstanceCreateFlags::empty(); if enumerate_portability && supported_extensions.khr_portability_enumeration { enabled_extensions.khr_portability_enumeration = true; flags |= ash::vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR; } // Check if the extensions are correct enabled_extensions.check_requirements(&supported_extensions, api_version)?; // FIXME: check whether each layer is supported let enabled_layers_cstr: Vec = 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::>(); let enabled_extensions_cstr: Vec = (&enabled_extensions).into(); let enabled_extensions_ptrs = enabled_extensions_cstr .iter() .map(|extension| extension.as_ptr()) .collect::>(); 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 enable_validation_features_vk: SmallVec<[_; 5]> = enabled_validation_features .iter() .copied() .map(Into::into) .collect(); let disable_validation_features_vk: SmallVec<[_; 8]> = disabled_validation_features .iter() .copied() .map(Into::into) .collect(); let mut create_info_vk = ash::vk::InstanceCreateInfo { flags, 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 mut validation_features_vk = None; if !enabled_validation_features.is_empty() || !disabled_validation_features.is_empty() { if !enabled_extensions.ext_validation_features { return Err(InstanceCreationError::RequirementNotMet { required_for: "`create_info.enabled_validation_features` or \ `create_info.disabled_validation_features` are not empty", requires_one_of: RequiresOneOf { instance_extensions: &["ext_validation_features"], ..Default::default() }, }); } // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02967 assert!( !enabled_validation_features .contains(&ValidationFeatureEnable::GpuAssistedReserveBindingSlot) || enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted) ); // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02968 assert!( !(enabled_validation_features.contains(&ValidationFeatureEnable::DebugPrintf) && enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)) ); let next = validation_features_vk.insert(ash::vk::ValidationFeaturesEXT { enabled_validation_feature_count: enable_validation_features_vk.len() as u32, p_enabled_validation_features: enable_validation_features_vk.as_ptr(), disabled_validation_feature_count: disable_validation_features_vk.len() as u32, p_disabled_validation_features: disable_validation_features_vk.as_ptr(), ..Default::default() }); next.p_next = create_info_vk.p_next; create_info_vk.p_next = next as *const _ as *const _; } // Handle debug messengers let debug_utils_messengers = debug_utils_messengers.into_iter(); let mut debug_utils_messenger_create_infos = Vec::with_capacity(debug_utils_messengers.size_hint().0); let mut user_callbacks = Vec::with_capacity(debug_utils_messengers.size_hint().0); for create_info in debug_utils_messengers { let DebugUtilsMessengerCreateInfo { message_type, message_severity, user_callback, _ne: _, } = create_info; // VUID-VkInstanceCreateInfo-pNext-04926 if !enabled_extensions.ext_debug_utils { return Err(InstanceCreationError::RequirementNotMet { required_for: "`create_info.debug_utils_messengers` is not empty", requires_one_of: RequiresOneOf { instance_extensions: &["ext_debug_utils"], ..Default::default() }, }); } // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter // TODO: message_severity.validate_instance()?; // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask assert!(!message_severity.is_empty()); // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter // TODO: message_type.validate_instance()?; // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask assert!(!message_type.is_empty()); // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769 // Can't be checked, creation is unsafe. let user_callback = Box::new(user_callback); let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT { flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(), message_severity: message_severity.into(), message_type: message_type.into(), pfn_user_callback: Some(trampoline), p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _, ..Default::default() }; debug_utils_messenger_create_infos.push(create_info); user_callbacks.push(user_callback); } for i in 1..debug_utils_messenger_create_infos.len() { debug_utils_messenger_create_infos[i - 1].p_next = &debug_utils_messenger_create_infos[i] as *const _ as *const _; } if let Some(info) = debug_utils_messenger_create_infos.first() { create_info_vk.p_next = info as *const _ as *const _; } // Creating the Vulkan instance. let handle = { let mut output = MaybeUninit::uninit(); let fns = library.fns(); (fns.v1_0.create_instance)(&create_info_vk, ptr::null(), output.as_mut_ptr()) .result() .map_err(VulkanError::from)?; output.assume_init() }; // Loading the function pointers of the newly-created instance. let fns = { InstanceFunctions::load(|name| { library .get_instance_proc_addr(handle, name.as_ptr()) .map_or(ptr::null(), |func| func as _) }) }; Ok(Arc::new(Instance { handle, fns, id: Self::next_id(), api_version, enabled_extensions, enabled_layers, library, max_api_version, _user_callbacks: user_callbacks, })) } /// Returns the Vulkan library used to create this instance. #[inline] pub fn library(&self) -> &Arc { &self.library } /// Returns the Vulkan version supported by the instance. /// /// This is the lower of the /// [driver's supported version](crate::VulkanLibrary::api_version) and /// [`max_api_version`](Instance::max_api_version). #[inline] pub fn api_version(&self) -> Version { self.api_version } /// Returns the maximum Vulkan version that was specified when creating the instance. #[inline] pub fn max_api_version(&self) -> Version { self.max_api_version } /// Returns pointers to the raw Vulkan functions of the instance. #[inline] pub fn fns(&self) -> &InstanceFunctions { &self.fns } /// Returns the extensions that have been enabled on the instance. #[inline] pub fn enabled_extensions(&self) -> &InstanceExtensions { &self.enabled_extensions } /// Returns the layers that have been enabled on the instance. #[inline] pub fn enabled_layers(&self) -> &[String] { &self.enabled_layers } /// Returns an iterator that enumerates the physical devices available. /// /// # Examples /// /// ```no_run /// # use vulkano::{ /// # instance::{Instance, InstanceExtensions}, /// # Version, VulkanLibrary, /// # }; /// /// # let library = VulkanLibrary::new().unwrap(); /// # let instance = Instance::new(library, Default::default()).unwrap(); /// for physical_device in instance.enumerate_physical_devices().unwrap() { /// println!("Available device: {}", physical_device.properties().device_name); /// } /// ``` pub fn enumerate_physical_devices( self: &Arc, ) -> Result>, VulkanError> { let fns = self.fns(); unsafe { let handles = loop { let mut count = 0; (fns.v1_0.enumerate_physical_devices)(self.handle, &mut count, ptr::null_mut()) .result() .map_err(VulkanError::from)?; let mut handles = Vec::with_capacity(count as usize); let result = (fns.v1_0.enumerate_physical_devices)( self.handle, &mut count, handles.as_mut_ptr(), ); match result { ash::vk::Result::SUCCESS => { handles.set_len(count as usize); break handles; } ash::vk::Result::INCOMPLETE => (), err => return Err(VulkanError::from(err)), } }; let physical_devices: SmallVec<[_; 4]> = handles .into_iter() .map(|handle| PhysicalDevice::from_handle(self.clone(), handle)) .collect::>()?; Ok(physical_devices.into_iter()) } } } impl Drop for Instance { #[inline] fn drop(&mut self) { let fns = self.fns(); unsafe { (fns.v1_0.destroy_instance)(self.handle, ptr::null()); } } } unsafe impl VulkanObject for Instance { type Handle = ash::vk::Instance; #[inline] fn handle(&self) -> Self::Handle { self.handle } } impl_id_counter!(Instance); impl Debug for Instance { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { let Self { handle, fns, id: _, api_version, enabled_extensions, enabled_layers, library: function_pointers, max_api_version, _user_callbacks: _, } = self; f.debug_struct("Instance") .field("handle", handle) .field("fns", fns) .field("api_version", api_version) .field("enabled_extensions", enabled_extensions) .field("enabled_layers", enabled_layers) .field("function_pointers", function_pointers) .field("max_api_version", max_api_version) .finish_non_exhaustive() } } /// Parameters to create a new `Instance`. #[derive(Debug)] pub struct InstanceCreateInfo { /// A string of your choice stating the name of your application. /// /// The default value is `None`. pub application_name: Option, /// A version number of your choice specifying the version of your application. /// /// The default value is zero. pub application_version: Version, /// The extensions to enable on the instance. /// /// The default value is [`InstanceExtensions::empty()`]. pub enabled_extensions: InstanceExtensions, /// The layers to enable on the instance. /// /// The default value is empty. pub enabled_layers: Vec, /// A string of your choice stating the name of the engine used to power the application. pub engine_name: Option, /// A version number of your choice specifying the version of the engine used to power the /// application. /// /// The default value is zero. pub engine_version: Version, /// The highest Vulkan API version that the application will use with the instance. /// /// Usually, you will want to leave this at the default. /// /// The default value is [`Version::HEADER_VERSION`], but if the /// supported instance version is 1.0, then it will be 1.0. pub max_api_version: Option, /// Include [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) /// devices when enumerating physical devices. /// /// If you enable this flag, you must ensure that your program is prepared to handle the /// non-conformant aspects of these devices. /// /// If this flag is not enabled, and there are no fully-conformant devices on the system, then /// [`Instance::new`] will return an `IncompatibleDriver` error. /// /// The default value is `false`. /// /// # Notes /// /// If this flag is enabled, and the /// [`khr_portability_enumeration`](crate::instance::InstanceExtensions::khr_portability_enumeration) /// extension is supported, it will be enabled automatically when creating the instance. /// If the extension is not supported, this flag will be ignored. pub enumerate_portability: bool, /// Features of the validation layer to enable. /// /// If not empty, the /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features) /// extension must be enabled on the instance. pub enabled_validation_features: Vec, /// Features of the validation layer to disable. /// /// If not empty, the /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features) /// extension must be enabled on the instance. pub disabled_validation_features: Vec, 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::empty(), enabled_layers: Vec::new(), engine_name: None, engine_version: Version::major_minor(0, 0), max_api_version: None, enumerate_portability: false, enabled_validation_features: Vec::new(), disabled_validation_features: Vec::new(), _ne: crate::NonExhaustive(()), } } } impl InstanceCreateInfo { /// Returns an `InstanceCreateInfo` with the `application_name` and `application_version` set /// from information in your crate's Cargo.toml file. /// /// # Panics /// /// - Panics if the required environment variables are missing, which happens if the project /// wasn't built by Cargo. #[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() } } } /// Error that can happen when creating an instance. #[derive(Clone, Debug)] pub enum InstanceCreationError { /// Not enough memory. OomError(OomError), /// Failed to initialize for an implementation-specific reason. InitializationFailed, /// One of the requested layers is missing. LayerNotPresent, /// One of the requested extensions is not supported by the implementation. ExtensionNotPresent, /// The version requested is not supported by the implementation. IncompatibleDriver, /// A restriction for an extension was not met. ExtensionRestrictionNotMet(ExtensionRestrictionError), RequirementNotMet { required_for: &'static str, requires_one_of: RequiresOneOf, }, } impl Error for InstanceCreationError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { Self::OomError(err) => Some(err), _ => None, } } } impl Display for InstanceCreationError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match self { Self::OomError(_) => write!(f, "not enough memory available"), Self::InitializationFailed => write!(f, "initialization failed"), Self::LayerNotPresent => write!(f, "layer not present"), Self::ExtensionNotPresent => write!(f, "extension not present"), Self::IncompatibleDriver => write!(f, "incompatible driver"), Self::ExtensionRestrictionNotMet(err) => Display::fmt(err, f), Self::RequirementNotMet { required_for, requires_one_of, } => write!( f, "a requirement was not met for: {}; requires one of: {}", required_for, requires_one_of, ), } } } impl From for InstanceCreationError { fn from(err: OomError) -> Self { Self::OomError(err) } } impl From for InstanceCreationError { fn from(err: ExtensionRestrictionError) -> Self { Self::ExtensionRestrictionNotMet(err) } } impl From for InstanceCreationError { fn from(err: VulkanError) -> Self { match err { err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)), err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)), VulkanError::InitializationFailed => Self::InitializationFailed, VulkanError::LayerNotPresent => Self::LayerNotPresent, VulkanError::ExtensionNotPresent => Self::ExtensionNotPresent, VulkanError::IncompatibleDriver => Self::IncompatibleDriver, _ => panic!("unexpected error: {:?}", err), } } } #[cfg(test)] mod tests { #[test] fn create_instance() { let _ = instance!(); } }