// 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. //! Communication channel with a physical device. //! //! The `Device` is one of the most important objects of Vulkan. Creating a `Device` is required //! before you can create buffers, textures, shaders, etc. //! //! Basic example: //! //! ```no_run //! use vulkano::{ //! device::{physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo}, //! instance::{Instance, InstanceExtensions}, //! Version, VulkanLibrary, //! }; //! //! // Creating the instance. See the documentation of the `instance` module. //! 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)); //! //! // We just choose the first physical device. In a real application you would choose depending //! // on the capabilities of the physical device and the user's preferences. //! let physical_device = instance //! .enumerate_physical_devices() //! .unwrap_or_else(|err| panic!("Couldn't enumerate physical devices: {:?}", err)) //! .next().expect("No physical device"); //! //! // Here is the device-creating code. //! let device = { //! let features = Features::empty(); //! let extensions = DeviceExtensions::empty(); //! //! match Device::new( //! physical_device, //! DeviceCreateInfo { //! enabled_extensions: extensions, //! enabled_features: features, //! queue_create_infos: vec![QueueCreateInfo { //! queue_family_index: 0, //! ..Default::default() //! }], //! ..Default::default() //! }, //! ) { //! Ok(d) => d, //! Err(err) => panic!("Couldn't build device: {:?}", err) //! } //! }; //! ``` //! //! # Features and extensions //! //! Two of the parameters that you pass to `Device::new` are the list of the features and the list //! of extensions to enable on the newly-created device. //! //! > **Note**: Device extensions are the same as instance extensions, except for the device. //! > Features are similar to extensions, except that they are part of the core Vulkan //! > specifications instead of being separate documents. //! //! Some Vulkan capabilities, such as swapchains (that allow you to render on the screen) or //! geometry shaders for example, require that you enable a certain feature or extension when you //! create the device. Contrary to OpenGL, you can't use the functions provided by a feature or an //! extension if you didn't explicitly enable it when creating the device. //! //! Not all physical devices support all possible features and extensions. For example mobile //! devices tend to not support geometry shaders, because their hardware is not capable of it. You //! can query what is supported with respectively `PhysicalDevice::supported_features` and //! `DeviceExtensions::supported_by_device`. //! //! > **Note**: The fact that you need to manually enable features at initialization also means //! > that you don't need to worry about a capability not being supported later on in your code. //! //! # Queues //! //! Each physical device proposes one or more *queues* that are divided in *queue families*. A //! queue is a thread of execution to which you can submit commands that the GPU will execute. //! //! > **Note**: You can think of a queue like a CPU thread. Each queue executes its commands one //! > after the other, and queues run concurrently. A GPU behaves similarly to the hyper-threading //! > technology, in the sense that queues will only run partially in parallel. //! //! The Vulkan API requires that you specify the list of queues that you are going to use at the //! same time as when you create the device. This is done in vulkano by passing an iterator where //! each element is a tuple containing a queue family and a number between 0.0 and 1.0 indicating //! the priority of execution of the queue relative to the others. //! //! TODO: write better doc here //! //! The `Device::new` function returns the newly-created device, but also the list of queues. //! //! # Extended example //! //! TODO: write use self::physical::PhysicalDevice; pub(crate) use self::{features::FeaturesFfi, properties::PropertiesFfi}; pub use self::{ features::{FeatureRestriction, FeatureRestrictionError, Features}, properties::Properties, queue::{Queue, QueueError, QueueFamilyProperties, QueueFlags, QueueGuard}, }; pub use crate::{ device::extensions::DeviceExtensions, extensions::{ExtensionRestriction, ExtensionRestrictionError}, fns::DeviceFunctions, }; use crate::{ instance::Instance, macros::impl_id_counter, memory::ExternalMemoryHandleType, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, }; use ash::vk::Handle; use parking_lot::Mutex; use smallvec::SmallVec; use std::{ error::Error, ffi::CString, fmt::{Display, Error as FmtError, Formatter}, fs::File, mem::MaybeUninit, num::NonZeroU64, ops::Deref, ptr, sync::{ atomic::{AtomicU32, Ordering}, Arc, }, }; pub(crate) mod extensions; pub(crate) mod features; pub mod physical; pub(crate) mod properties; mod queue; /// Represents a Vulkan context. #[derive(Debug)] pub struct Device { handle: ash::vk::Device, physical_device: Arc, id: NonZeroU64, // The highest version that is supported for this device. // This is the minimum of Instance::max_api_version and PhysicalDevice::api_version. api_version: Version, fns: DeviceFunctions, enabled_extensions: DeviceExtensions, enabled_features: Features, active_queue_family_indices: SmallVec<[u32; 2]>, // This is required for validation in `memory::device_memory`, the count must only be modified // in that module. pub(crate) allocation_count: AtomicU32, fence_pool: Mutex>, semaphore_pool: Mutex>, event_pool: Mutex>, } impl Device { /// Creates a new `Device`. /// /// # Panics /// /// - Panics if `create_info.queues` is empty. /// - Panics if one of the queue families in `create_info.queues` doesn't belong to the given /// physical device. /// - Panics if `create_info.queues` contains multiple elements for the same queue family. /// - Panics if `create_info.queues` contains an element where `queues` is empty. /// - Panics if `create_info.queues` contains an element where `queues` contains a value that is /// not between 0.0 and 1.0 inclusive. pub fn new( physical_device: Arc, create_info: DeviceCreateInfo, ) -> Result<(Arc, impl ExactSizeIterator>), DeviceCreationError> { let DeviceCreateInfo { mut enabled_extensions, mut enabled_features, queue_create_infos, _ne: _, } = create_info; let instance = physical_device.instance(); let fns_i = instance.fns(); let api_version = physical_device.api_version(); /* Queues */ struct QueueToGet { queue_family_index: u32, id: u32, } // VUID-VkDeviceCreateInfo-queueCreateInfoCount-arraylength assert!(!queue_create_infos.is_empty()); let mut queue_create_infos_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(queue_create_infos.len()); let mut active_queue_family_indices: SmallVec<[_; 2]> = SmallVec::with_capacity(queue_create_infos.len()); let mut queues_to_get: SmallVec<[_; 2]> = SmallVec::with_capacity(queue_create_infos.len()); for queue_create_info in &queue_create_infos { let &QueueCreateInfo { queue_family_index, ref queues, _ne: _, } = queue_create_info; // VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381 // TODO: return error instead of panicking? let queue_family_properties = &physical_device.queue_family_properties()[queue_family_index as usize]; // VUID-VkDeviceCreateInfo-queueFamilyIndex-02802 assert!( queue_create_infos .iter() .filter(|qc2| qc2.queue_family_index == queue_family_index) .count() == 1 ); // VUID-VkDeviceQueueCreateInfo-queueCount-arraylength assert!(!queues.is_empty()); // VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383 assert!(queues .iter() .all(|&priority| (0.0..=1.0).contains(&priority))); if queues.len() > queue_family_properties.queue_count as usize { return Err(DeviceCreationError::TooManyQueuesForFamily); } queue_create_infos_vk.push(ash::vk::DeviceQueueCreateInfo { flags: ash::vk::DeviceQueueCreateFlags::empty(), queue_family_index, queue_count: queues.len() as u32, p_queue_priorities: queues.as_ptr(), // borrows from queue_create ..Default::default() }); active_queue_family_indices.push(queue_family_index); queues_to_get.extend((0..queues.len() as u32).map(move |id| QueueToGet { queue_family_index, id, })); } active_queue_family_indices.sort_unstable(); active_queue_family_indices.dedup(); let supported_extensions = physical_device.supported_extensions(); if supported_extensions.khr_portability_subset { enabled_extensions.khr_portability_subset = true; } /* Extensions */ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-03328 // VUID-VkDeviceCreateInfo-pProperties-04451 enabled_extensions.check_requirements( supported_extensions, api_version, instance.enabled_extensions(), )?; let enabled_extensions_strings = Vec::::from(&enabled_extensions); let enabled_extensions_ptrs = enabled_extensions_strings .iter() .map(|extension| extension.as_ptr()) .collect::>(); /* Features */ // TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see // if they can possibly perform out-of-bounds reads and writes. If the user tries // to use a shader that can perform out-of-bounds operations without having // `robust_buffer_access` enabled, an error is returned. // // However for the moment this verification isn't performed. In order to be safe, // we always enable the `robust_buffer_access` feature as it is guaranteed to be // supported everywhere. // // The only alternative (while waiting for shaders introspection to work) is to // make all shaders depend on `robust_buffer_access`. But since usually the // majority of shaders don't need this feature, it would be very annoying to have // to enable it manually when you don't need it. // // Note that if we ever remove this, don't forget to adjust the change in // `Device`'s construction below. enabled_features.robust_buffer_access = true; // VUID-VkDeviceCreateInfo-pNext-04748 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-04476 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02831 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02832 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02833 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02834 // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835 // VUID-VkDeviceCreateInfo-shadingRateImage-04478 // VUID-VkDeviceCreateInfo-shadingRateImage-04479 // VUID-VkDeviceCreateInfo-shadingRateImage-04480 // VUID-VkDeviceCreateInfo-fragmentDensityMap-04481 // VUID-VkDeviceCreateInfo-fragmentDensityMap-04482 // VUID-VkDeviceCreateInfo-fragmentDensityMap-04483 // VUID-VkDeviceCreateInfo-None-04896 // VUID-VkDeviceCreateInfo-None-04897 // VUID-VkDeviceCreateInfo-None-04898 // VUID-VkDeviceCreateInfo-sparseImageFloat32AtomicMinMax-04975 enabled_features.check_requirements( physical_device.supported_features(), api_version, &enabled_extensions, )?; // VUID-VkDeviceCreateInfo-pNext-02829 // VUID-VkDeviceCreateInfo-pNext-02830 // VUID-VkDeviceCreateInfo-pNext-06532 let mut features_ffi = FeaturesFfi::default(); features_ffi.make_chain( api_version, &enabled_extensions, instance.enabled_extensions(), ); features_ffi.write(&enabled_features); // Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be // ignored by the driver. For backwards compatibility, the spec recommends passing the // exact instance layers to the device as well. There's no need to support separate // requests at device creation time for legacy drivers: the spec claims that "[at] the // time of deprecation there were no known device-only layers." // // Because there's no way to query the list of layers enabled for an instance, we need // to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get // the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.) let enabled_layers_cstr: Vec = instance .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::>(); /* Create the device */ let has_khr_get_physical_device_properties2 = instance .enabled_extensions() .khr_get_physical_device_properties2; let mut create_info = ash::vk::DeviceCreateInfo { flags: ash::vk::DeviceCreateFlags::empty(), queue_create_info_count: queue_create_infos_vk.len() as u32, p_queue_create_infos: queue_create_infos_vk.as_ptr(), 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(), p_enabled_features: ptr::null(), ..Default::default() }; // VUID-VkDeviceCreateInfo-pNext-00373 if has_khr_get_physical_device_properties2 { create_info.p_next = features_ffi.head_as_ref() as *const _ as _; } else { create_info.p_enabled_features = &features_ffi.head_as_ref().features; } let handle = unsafe { let mut output = MaybeUninit::uninit(); (fns_i.v1_0.create_device)( physical_device.handle(), &create_info, ptr::null(), output.as_mut_ptr(), ) .result() .map_err(VulkanError::from)?; output.assume_init() }; // loading the function pointers of the newly-created device let fns = DeviceFunctions::load(|name| unsafe { (fns_i.v1_0.get_device_proc_addr)(handle, name.as_ptr()) .map_or(ptr::null(), |func| func as _) }); let device = Arc::new(Device { handle, physical_device, id: Self::next_id(), api_version, fns, enabled_extensions, enabled_features, active_queue_family_indices, allocation_count: AtomicU32::new(0), fence_pool: Mutex::new(Vec::new()), semaphore_pool: Mutex::new(Vec::new()), event_pool: Mutex::new(Vec::new()), }); // Iterator to return the queues let queues_iter = { let device = device.clone(); queues_to_get.into_iter().map( move |QueueToGet { queue_family_index, id, }| unsafe { let fns = device.fns(); let mut output = MaybeUninit::uninit(); (fns.v1_0.get_device_queue)( handle, queue_family_index, id, output.as_mut_ptr(), ); Queue::from_handle(device.clone(), output.assume_init(), queue_family_index, id) }, ) }; Ok((device, queues_iter)) } /// Returns the Vulkan version supported by the device. /// /// This is the lower of the /// [physical device's supported version](crate::device::physical::PhysicalDevice::api_version) /// and the instance's [`max_api_version`](crate::instance::Instance::max_api_version). #[inline] pub fn api_version(&self) -> Version { self.api_version } /// Returns pointers to the raw Vulkan functions of the device. #[inline] pub fn fns(&self) -> &DeviceFunctions { &self.fns } /// Returns the physical device that was used to create this device. #[inline] pub fn physical_device(&self) -> &Arc { &self.physical_device } /// Returns the instance used to create this device. #[inline] pub fn instance(&self) -> &Arc { self.physical_device.instance() } /// Returns the queue family indices that this device uses. #[inline] pub fn active_queue_family_indices(&self) -> &[u32] { &self.active_queue_family_indices } /// Returns the extensions that have been enabled on the device. #[inline] pub fn enabled_extensions(&self) -> &DeviceExtensions { &self.enabled_extensions } /// Returns the features that have been enabled on the device. #[inline] pub fn enabled_features(&self) -> &Features { &self.enabled_features } /// Returns the current number of active [`DeviceMemory`] allocations the device has. /// /// [`DeviceMemory`]: crate::memory::DeviceMemory #[inline] pub fn allocation_count(&self) -> u32 { self.allocation_count.load(Ordering::Acquire) } pub(crate) fn fence_pool(&self) -> &Mutex> { &self.fence_pool } pub(crate) fn semaphore_pool(&self) -> &Mutex> { &self.semaphore_pool } pub(crate) fn event_pool(&self) -> &Mutex> { &self.event_pool } /// Retrieves the properties of an external file descriptor when imported as a given external /// handle type. /// /// An error will be returned if the /// [`khr_external_memory_fd`](DeviceExtensions::khr_external_memory_fd) extension was not /// enabled on the device, or if `handle_type` is [`ExternalMemoryHandleType::OpaqueFd`]. /// /// # Safety /// /// - `file` must be a handle to external memory that was created outside the Vulkan API. #[cfg_attr(not(unix), allow(unused_variables))] #[inline] pub unsafe fn memory_fd_properties( &self, handle_type: ExternalMemoryHandleType, file: File, ) -> Result { if !self.enabled_extensions().khr_external_memory_fd { return Err(MemoryFdPropertiesError::NotSupported); } #[cfg(not(unix))] unreachable!("`khr_external_memory_fd` was somehow enabled on a non-Unix system"); #[cfg(unix)] { use std::os::unix::io::IntoRawFd; // VUID-vkGetMemoryFdPropertiesKHR-handleType-parameter handle_type.validate_device(self)?; // VUID-vkGetMemoryFdPropertiesKHR-handleType-00674 if handle_type == ExternalMemoryHandleType::OpaqueFd { return Err(MemoryFdPropertiesError::InvalidExternalHandleType); } let mut memory_fd_properties = ash::vk::MemoryFdPropertiesKHR::default(); let fns = self.fns(); (fns.khr_external_memory_fd.get_memory_fd_properties_khr)( self.handle, handle_type.into(), file.into_raw_fd(), &mut memory_fd_properties, ) .result() .map_err(VulkanError::from)?; Ok(MemoryFdProperties { memory_type_bits: memory_fd_properties.memory_type_bits, }) } } /// Assigns a human-readable name to `object` for debugging purposes. /// /// If `object_name` is `None`, a previously set object name is removed. /// /// # Panics /// - If `object` is not owned by this device. pub fn set_debug_utils_object_name( &self, object: &T, object_name: Option<&str>, ) -> Result<(), OomError> { assert!(object.device().handle() == self.handle()); let object_name_vk = object_name.map(|object_name| CString::new(object_name).unwrap()); let info = ash::vk::DebugUtilsObjectNameInfoEXT { object_type: T::Handle::TYPE, object_handle: object.handle().as_raw(), p_object_name: object_name_vk.map_or(ptr::null(), |object_name| object_name.as_ptr()), ..Default::default() }; unsafe { let fns = self.instance().fns(); (fns.ext_debug_utils.set_debug_utils_object_name_ext)(self.handle, &info) .result() .map_err(VulkanError::from)?; } Ok(()) } /// Waits until all work on this device has finished. You should never need to call /// this function, but it can be useful for debugging or benchmarking purposes. /// /// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`. /// /// # Safety /// /// This function is not thread-safe. You must not submit anything to any of the queue /// of the device (either explicitly or implicitly, for example with a future's destructor) /// while this function is waiting. #[inline] pub unsafe fn wait_idle(&self) -> Result<(), OomError> { let fns = self.fns(); (fns.v1_0.device_wait_idle)(self.handle) .result() .map_err(VulkanError::from)?; Ok(()) } } impl Drop for Device { #[inline] fn drop(&mut self) { let fns = self.fns(); unsafe { for &raw_fence in self.fence_pool.lock().iter() { (fns.v1_0.destroy_fence)(self.handle, raw_fence, ptr::null()); } for &raw_sem in self.semaphore_pool.lock().iter() { (fns.v1_0.destroy_semaphore)(self.handle, raw_sem, ptr::null()); } for &raw_event in self.event_pool.lock().iter() { (fns.v1_0.destroy_event)(self.handle, raw_event, ptr::null()); } (fns.v1_0.destroy_device)(self.handle, ptr::null()); } } } unsafe impl VulkanObject for Device { type Handle = ash::vk::Device; #[inline] fn handle(&self) -> Self::Handle { self.handle } } impl_id_counter!(Device); /// Error that can be returned when creating a device. #[derive(Copy, Clone, Debug)] pub enum DeviceCreationError { /// Failed to create the device for an implementation-specific reason. InitializationFailed, /// You have reached the limit to the number of devices that can be created from the same /// physical device. TooManyObjects, /// Failed to connect to the device. DeviceLost, /// Some of the requested features are unsupported by the physical device. FeatureNotPresent, /// Some of the requested device extensions are not supported by the physical device. ExtensionNotPresent, /// Tried to create too many queues for a given family. TooManyQueuesForFamily, /// The priority of one of the queues is out of the [0.0; 1.0] range. PriorityOutOfRange, /// There is no memory available on the host (ie. the CPU, RAM, etc.). OutOfHostMemory, /// There is no memory available on the device (ie. video memory). OutOfDeviceMemory, /// A restriction for an extension was not met. ExtensionRestrictionNotMet(ExtensionRestrictionError), /// A restriction for a feature was not met. FeatureRestrictionNotMet(FeatureRestrictionError), } impl Error for DeviceCreationError {} impl Display for DeviceCreationError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match self { Self::InitializationFailed => write!( f, "failed to create the device for an implementation-specific reason", ), Self::OutOfHostMemory => write!(f, "no memory available on the host"), Self::OutOfDeviceMemory => { write!(f, "no memory available on the graphical device") } Self::DeviceLost => write!(f, "failed to connect to the device"), Self::TooManyQueuesForFamily => { write!(f, "tried to create too many queues for a given family") } Self::FeatureNotPresent => write!( f, "some of the requested features are unsupported by the physical device", ), Self::PriorityOutOfRange => write!( f, "the priority of one of the queues is out of the [0.0; 1.0] range", ), Self::ExtensionNotPresent => write!( f, "some of the requested device extensions are not supported by the physical device", ), Self::TooManyObjects => write!( f, "you have reached the limit to the number of devices that can be created from the \ same physical device", ), Self::ExtensionRestrictionNotMet(err) => err.fmt(f), Self::FeatureRestrictionNotMet(err) => err.fmt(f), } } } impl From for DeviceCreationError { fn from(err: VulkanError) -> Self { match err { VulkanError::InitializationFailed => Self::InitializationFailed, VulkanError::OutOfHostMemory => Self::OutOfHostMemory, VulkanError::OutOfDeviceMemory => Self::OutOfDeviceMemory, VulkanError::DeviceLost => Self::DeviceLost, VulkanError::ExtensionNotPresent => Self::ExtensionNotPresent, VulkanError::FeatureNotPresent => Self::FeatureNotPresent, VulkanError::TooManyObjects => Self::TooManyObjects, _ => panic!("Unexpected error value"), } } } impl From for DeviceCreationError { fn from(err: ExtensionRestrictionError) -> Self { Self::ExtensionRestrictionNotMet(err) } } impl From for DeviceCreationError { fn from(err: FeatureRestrictionError) -> Self { Self::FeatureRestrictionNotMet(err) } } /// Parameters to create a new `Device`. #[derive(Clone, Debug)] pub struct DeviceCreateInfo { /// The extensions to enable on the device. /// /// If the [`khr_portability_subset`](DeviceExtensions::khr_portability_subset) extension is /// available, it will be enabled automatically, so you do not have to do this yourself. /// You are responsible for ensuring that your program can work correctly on such devices. /// See [the documentation of the `instance` module](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) /// for more information. /// /// The default value is [`DeviceExtensions::empty()`]. pub enabled_extensions: DeviceExtensions, /// The features to enable on the device. /// /// The default value is [`Features::empty()`]. pub enabled_features: Features, /// The queues to create for the device. /// /// The default value is empty, which must be overridden. pub queue_create_infos: Vec, pub _ne: crate::NonExhaustive, } impl Default for DeviceCreateInfo { #[inline] fn default() -> Self { Self { enabled_extensions: DeviceExtensions::empty(), enabled_features: Features::empty(), queue_create_infos: Vec::new(), _ne: crate::NonExhaustive(()), } } } /// Parameters to create queues in a new `Device`. #[derive(Clone, Debug)] pub struct QueueCreateInfo { /// The index of the queue family to create queues for. /// /// The default value is `0`. pub queue_family_index: u32, /// The queues to create for the given queue family, each with a relative priority. /// /// The relative priority value is an arbitrary number between 0.0 and 1.0. Giving a queue a /// higher priority is a hint to the driver that the queue should be given more processing time. /// As this is only a hint, different drivers may handle this value differently and there are no /// guarantees about its behavior. /// /// The default value is a single queue with a priority of 0.5. pub queues: Vec, pub _ne: crate::NonExhaustive, } impl Default for QueueCreateInfo { #[inline] fn default() -> Self { Self { queue_family_index: 0, queues: vec![0.5], _ne: crate::NonExhaustive(()), } } } /// Implemented on objects that belong to a Vulkan device. /// /// # Safety /// /// - `device()` must return the correct device. pub unsafe trait DeviceOwned { /// Returns the device that owns `Self`. fn device(&self) -> &Arc; } unsafe impl DeviceOwned for T where T: Deref, T::Target: DeviceOwned, { fn device(&self) -> &Arc { (**self).device() } } /// The properties of a Unix file descriptor when it is imported. #[derive(Clone, Debug)] #[non_exhaustive] pub struct MemoryFdProperties { /// A bitmask of the indices of memory types that can be used with the file. pub memory_type_bits: u32, } /// Error that can happen when calling `memory_fd_properties`. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum MemoryFdPropertiesError { /// No memory available on the host. OutOfHostMemory, RequirementNotMet { required_for: &'static str, requires_one_of: RequiresOneOf, }, /// The provided external handle was not valid. InvalidExternalHandle, /// The provided external handle type was not valid. InvalidExternalHandleType, /// The `khr_external_memory_fd` extension was not enabled on the device. NotSupported, } impl Error for MemoryFdPropertiesError {} impl Display for MemoryFdPropertiesError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match self { Self::OutOfHostMemory => write!(f, "no memory available on the host"), Self::RequirementNotMet { required_for, requires_one_of, } => write!( f, "a requirement was not met for: {}; requires one of: {}", required_for, requires_one_of, ), Self::InvalidExternalHandle => { write!(f, "the provided external handle was not valid") } Self::InvalidExternalHandleType => { write!(f, "the provided external handle type was not valid") } Self::NotSupported => write!( f, "the `khr_external_memory_fd` extension was not enabled on the device", ), } } } impl From for MemoryFdPropertiesError { fn from(err: VulkanError) -> Self { match err { VulkanError::OutOfHostMemory => Self::OutOfHostMemory, VulkanError::InvalidExternalHandle => Self::InvalidExternalHandle, _ => panic!("Unexpected error value"), } } } impl From for MemoryFdPropertiesError { fn from(err: RequirementNotMet) -> Self { Self::RequirementNotMet { required_for: err.required_for, requires_one_of: err.requires_one_of, } } } #[cfg(test)] mod tests { use crate::device::{ Device, DeviceCreateInfo, DeviceCreationError, FeatureRestriction, FeatureRestrictionError, Features, QueueCreateInfo, }; use std::sync::Arc; #[test] fn one_ref() { let (mut device, _) = gfx_dev_and_queue!(); assert!(Arc::get_mut(&mut device).is_some()); } #[test] fn too_many_queues() { let instance = instance!(); let physical_device = match instance.enumerate_physical_devices().unwrap().next() { Some(p) => p, None => return, }; let queue_family_index = 0; let queue_family_properties = &physical_device.queue_family_properties()[queue_family_index as usize]; let queues = (0..queue_family_properties.queue_count + 1) .map(|_| (0.5)) .collect(); match Device::new( physical_device, DeviceCreateInfo { queue_create_infos: vec![QueueCreateInfo { queue_family_index, queues, ..Default::default() }], ..Default::default() }, ) { Err(DeviceCreationError::TooManyQueuesForFamily) => (), // Success _ => panic!(), }; } #[test] fn unsupported_features() { let instance = instance!(); let physical_device = match instance.enumerate_physical_devices().unwrap().next() { Some(p) => p, None => return, }; let features = Features::all(); // In the unlikely situation where the device supports everything, we ignore the test. if physical_device.supported_features().contains(&features) { return; } match Device::new( physical_device, DeviceCreateInfo { enabled_features: features, queue_create_infos: vec![QueueCreateInfo { queue_family_index: 0, ..Default::default() }], ..Default::default() }, ) { Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError { restriction: FeatureRestriction::NotSupported, .. })) => (), // Success _ => panic!(), }; } #[test] fn priority_out_of_range() { let instance = instance!(); let physical_device = match instance.enumerate_physical_devices().unwrap().next() { Some(p) => p, None => return, }; assert_should_panic!({ Device::new( physical_device.clone(), DeviceCreateInfo { queue_create_infos: vec![QueueCreateInfo { queue_family_index: 0, queues: vec![1.4], ..Default::default() }], ..Default::default() }, ) }); assert_should_panic!({ Device::new( physical_device, DeviceCreateInfo { queue_create_infos: vec![QueueCreateInfo { queue_family_index: 0, queues: vec![-0.2], ..Default::default() }], ..Default::default() }, ) }); } }