• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Communication channel with a physical device.
11 //!
12 //! The `Device` is one of the most important objects of Vulkan. Creating a `Device` is required
13 //! before you can create buffers, textures, shaders, etc.
14 //!
15 //! Basic example:
16 //!
17 //! ```no_run
18 //! use vulkano::device::Device;
19 //! use vulkano::device::DeviceExtensions;
20 //! use vulkano::device::Features;
21 //! use vulkano::instance::Instance;
22 //! use vulkano::instance::InstanceExtensions;
23 //! use vulkano::device::physical::PhysicalDevice;
24 //! use vulkano::Version;
25 //!
26 //! // Creating the instance. See the documentation of the `instance` module.
27 //! let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
28 //!     Ok(i) => i,
29 //!     Err(err) => panic!("Couldn't build instance: {:?}", err)
30 //! };
31 //!
32 //! // We just choose the first physical device. In a real application you would choose depending
33 //! // on the capabilities of the physical device and the user's preferences.
34 //! let physical_device = PhysicalDevice::enumerate(&instance).next().expect("No physical device");
35 //!
36 //! // Here is the device-creating code.
37 //! let device = {
38 //!     let queue_family = physical_device.queue_families().next().unwrap();
39 //!     let features = Features::none();
40 //!     let ext = DeviceExtensions::none();
41 //!
42 //!     match Device::new(physical_device, &features, &ext, Some((queue_family, 1.0))) {
43 //!         Ok(d) => d,
44 //!         Err(err) => panic!("Couldn't build device: {:?}", err)
45 //!     }
46 //! };
47 //! ```
48 //!
49 //! # Features and extensions
50 //!
51 //! Two of the parameters that you pass to `Device::new` are the list of the features and the list
52 //! of extensions to enable on the newly-created device.
53 //!
54 //! > **Note**: Device extensions are the same as instance extensions, except for the device.
55 //! > Features are similar to extensions, except that they are part of the core Vulkan
56 //! > specifications instead of being separate documents.
57 //!
58 //! Some Vulkan capabilities, such as swapchains (that allow you to render on the screen) or
59 //! geometry shaders for example, require that you enable a certain feature or extension when you
60 //! create the device. Contrary to OpenGL, you can't use the functions provided by a feature or an
61 //! extension if you didn't explicitly enable it when creating the device.
62 //!
63 //! Not all physical devices support all possible features and extensions. For example mobile
64 //! devices tend to not support geometry shaders, because their hardware is not capable of it. You
65 //! can query what is supported with respectively `PhysicalDevice::supported_features` and
66 //! `DeviceExtensions::supported_by_device`.
67 //!
68 //! > **Note**: The fact that you need to manually enable features at initialization also means
69 //! > that you don't need to worry about a capability not being supported later on in your code.
70 //!
71 //! # Queues
72 //!
73 //! Each physical device proposes one or more *queues* that are divided in *queue families*. A
74 //! queue is a thread of execution to which you can submit commands that the GPU will execute.
75 //!
76 //! > **Note**: You can think of a queue like a CPU thread. Each queue executes its commands one
77 //! > after the other, and queues run concurrently. A GPU behaves similarly to the hyper-threading
78 //! > technology, in the sense that queues will only run partially in parallel.
79 //!
80 //! The Vulkan API requires that you specify the list of queues that you are going to use at the
81 //! same time as when you create the device. This is done in vulkano by passing an iterator where
82 //! each element is a tuple containing a queue family and a number between 0.0 and 1.0 indicating
83 //! the priority of execution of the queue relative to the others.
84 //!
85 //! TODO: write better doc here
86 //!
87 //! The `Device::new` function returns the newly-created device, but also the list of queues.
88 //!
89 //! # Extended example
90 //!
91 //! TODO: write
92 
93 pub(crate) use self::features::FeaturesFfi;
94 pub use self::features::{FeatureRestriction, FeatureRestrictionError, Features};
95 pub use self::properties::Properties;
96 pub(crate) use self::properties::PropertiesFfi;
97 pub use crate::autogen::DeviceExtensions;
98 use crate::check_errors;
99 use crate::command_buffer::pool::StandardCommandPool;
100 use crate::descriptor_set::pool::StdDescriptorPool;
101 use crate::device::physical::PhysicalDevice;
102 use crate::device::physical::QueueFamily;
103 pub use crate::extensions::{
104     ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
105 };
106 use crate::fns::DeviceFunctions;
107 use crate::format::Format;
108 use crate::image::ImageCreateFlags;
109 use crate::image::ImageFormatProperties;
110 use crate::image::ImageTiling;
111 use crate::image::ImageType;
112 use crate::image::ImageUsage;
113 use crate::instance::Instance;
114 use crate::memory::pool::StdMemoryPool;
115 use crate::Error;
116 use crate::OomError;
117 use crate::SynchronizedVulkanObject;
118 use crate::Version;
119 use crate::VulkanObject;
120 use ash::vk::Handle;
121 use fnv::FnvHasher;
122 use smallvec::SmallVec;
123 use std::collections::hash_map::Entry;
124 use std::collections::HashMap;
125 use std::error;
126 use std::ffi::CStr;
127 use std::ffi::CString;
128 use std::fmt;
129 use std::hash::BuildHasherDefault;
130 use std::hash::Hash;
131 use std::hash::Hasher;
132 use std::mem;
133 use std::mem::MaybeUninit;
134 use std::ops::Deref;
135 use std::ptr;
136 use std::sync::Arc;
137 use std::sync::Mutex;
138 use std::sync::MutexGuard;
139 use std::sync::Weak;
140 
141 pub(crate) mod extensions;
142 pub(crate) mod features;
143 pub mod physical;
144 pub(crate) mod properties;
145 
146 /// Represents a Vulkan context.
147 pub struct Device {
148     instance: Arc<Instance>,
149     physical_device: usize,
150     device: ash::vk::Device,
151 
152     // The highest version that is supported for this device.
153     // This is the minimum of Instance::max_api_version and PhysicalDevice::api_version.
154     api_version: Version,
155 
156     fns: DeviceFunctions,
157     standard_pool: Mutex<Weak<StdMemoryPool>>,
158     standard_descriptor_pool: Mutex<Weak<StdDescriptorPool>>,
159     standard_command_pools:
160         Mutex<HashMap<u32, Weak<StandardCommandPool>, BuildHasherDefault<FnvHasher>>>,
161     features: Features,
162     extensions: DeviceExtensions,
163     active_queue_families: SmallVec<[u32; 8]>,
164     allocation_count: Mutex<u32>,
165     fence_pool: Mutex<Vec<ash::vk::Fence>>,
166     semaphore_pool: Mutex<Vec<ash::vk::Semaphore>>,
167     event_pool: Mutex<Vec<ash::vk::Event>>,
168 }
169 
170 // The `StandardCommandPool` type doesn't implement Send/Sync, so we have to manually reimplement
171 // them for the device itself.
172 unsafe impl Send for Device {}
173 unsafe impl Sync for Device {}
174 
175 impl Device {
176     /// Builds a new Vulkan device for the given physical device.
177     ///
178     /// You must pass two things when creating a logical device:
179     ///
180     /// - A list of optional Vulkan features that must be enabled on the device. Note that if a
181     ///   feature is not enabled at device creation, you can't use it later even it it's supported
182     ///   by the physical device.
183     ///
184     /// - An iterator to a list of queues to create. Each element of the iterator must indicate
185     ///   the family whose queue belongs to and a priority between 0.0 and 1.0 to assign to it.
186     ///   A queue with a higher value indicates that the commands will execute faster than on a
187     ///   queue with a lower value. Note however that no guarantee can be made on the way the
188     ///   priority value is handled by the implementation.
189     ///
190     /// # Panic
191     ///
192     /// - Panics if one of the queue families doesn't belong to the given device.
193     ///
194     // TODO: return Arc<Queue> and handle synchronization in the Queue
195     // TODO: should take the PhysicalDevice by value
new<'a, I>( physical_device: PhysicalDevice, requested_features: &Features, requested_extensions: &DeviceExtensions, queue_families: I, ) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError> where I: IntoIterator<Item = (QueueFamily<'a>, f32)>,196     pub fn new<'a, I>(
197         physical_device: PhysicalDevice,
198         requested_features: &Features,
199         requested_extensions: &DeviceExtensions,
200         queue_families: I,
201     ) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
202     where
203         I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
204     {
205         let instance = physical_device.instance();
206         let fns_i = instance.fns();
207         let api_version = physical_device.api_version();
208 
209         // Check if the extensions are correct
210         requested_extensions.check_requirements(
211             physical_device.supported_extensions(),
212             api_version,
213             instance.enabled_extensions(),
214         )?;
215 
216         let mut requested_features = requested_features.clone();
217 
218         // TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see
219         //       if they can possibly perform out-of-bounds reads and writes. If the user tries
220         //       to use a shader that can perform out-of-bounds operations without having
221         //       `robust_buffer_access` enabled, an error is returned.
222         //
223         //       However for the moment this verification isn't performed. In order to be safe,
224         //       we always enable the `robust_buffer_access` feature as it is guaranteed to be
225         //       supported everywhere.
226         //
227         //       The only alternative (while waiting for shaders introspection to work) is to
228         //       make all shaders depend on `robust_buffer_access`. But since usually the
229         //       majority of shaders don't need this feature, it would be very annoying to have
230         //       to enable it manually when you don't need it.
231         //
232         //       Note that if we ever remove this, don't forget to adjust the change in
233         //       `Device`'s construction below.
234         requested_features.robust_buffer_access = true;
235 
236         // Check if the features are correct
237         requested_features.check_requirements(
238             physical_device.supported_features(),
239             api_version,
240             requested_extensions,
241         )?;
242 
243         // device creation
244         let (device, queues) = unsafe {
245             // each element of `queues` is a `(queue_family, priorities)`
246             // each queue family must only have one entry in `queues`
247             let mut queues: Vec<(u32, Vec<f32>)> =
248                 Vec::with_capacity(physical_device.queue_families().len());
249 
250             // this variable will contain the queue family ID and queue ID of each requested queue
251             let mut output_queues: SmallVec<[(u32, u32); 8]> = SmallVec::new();
252 
253             for (queue_family, priority) in queue_families {
254                 // checking the parameters
255                 assert_eq!(
256                     queue_family.physical_device().internal_object(),
257                     physical_device.internal_object()
258                 );
259                 if priority < 0.0 || priority > 1.0 {
260                     return Err(DeviceCreationError::PriorityOutOfRange);
261                 }
262 
263                 // adding to `queues` and `output_queues`
264                 if let Some(q) = queues.iter_mut().find(|q| q.0 == queue_family.id()) {
265                     output_queues.push((queue_family.id(), q.1.len() as u32));
266                     q.1.push(priority);
267                     if q.1.len() > queue_family.queues_count() {
268                         return Err(DeviceCreationError::TooManyQueuesForFamily);
269                     }
270                     continue;
271                 }
272                 queues.push((queue_family.id(), vec![priority]));
273                 output_queues.push((queue_family.id(), 0));
274             }
275 
276             // turning `queues` into an array of `vkDeviceQueueCreateInfo` suitable for Vulkan
277             let queues = queues
278                 .iter()
279                 .map(
280                     |&(queue_id, ref priorities)| ash::vk::DeviceQueueCreateInfo {
281                         flags: ash::vk::DeviceQueueCreateFlags::empty(),
282                         queue_family_index: queue_id,
283                         queue_count: priorities.len() as u32,
284                         p_queue_priorities: priorities.as_ptr(),
285                         ..Default::default()
286                     },
287                 )
288                 .collect::<SmallVec<[_; 16]>>();
289 
290             let mut features_ffi = FeaturesFfi::default();
291             features_ffi.make_chain(
292                 api_version,
293                 requested_extensions,
294                 instance.enabled_extensions(),
295             );
296             features_ffi.write(&requested_features);
297 
298             // Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be
299             // ignored by the driver. For backwards compatibility, the spec recommends passing the
300             // exact instance layers to the device as well. There's no need to support separate
301             // requests at device creation time for legacy drivers: the spec claims that "[at] the
302             // time of deprecation there were no known device-only layers."
303             //
304             // Because there's no way to query the list of layers enabled for an instance, we need
305             // to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get
306             // the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.)
307             let layers_ptrs = instance
308                 .enabled_layers()
309                 .map(|layer| layer.as_ptr())
310                 .collect::<SmallVec<[_; 16]>>();
311 
312             let extensions_strings: Vec<CString> = requested_extensions.into();
313             let extensions_ptrs = extensions_strings
314                 .iter()
315                 .map(|extension| extension.as_ptr())
316                 .collect::<SmallVec<[_; 16]>>();
317 
318             let has_khr_get_physical_device_properties2 = instance
319                 .enabled_extensions()
320                 .khr_get_physical_device_properties2;
321 
322             let infos = ash::vk::DeviceCreateInfo {
323                 p_next: if has_khr_get_physical_device_properties2 {
324                     features_ffi.head_as_ref() as *const _ as _
325                 } else {
326                     ptr::null()
327                 },
328                 flags: ash::vk::DeviceCreateFlags::empty(),
329                 queue_create_info_count: queues.len() as u32,
330                 p_queue_create_infos: queues.as_ptr(),
331                 enabled_layer_count: layers_ptrs.len() as u32,
332                 pp_enabled_layer_names: layers_ptrs.as_ptr(),
333                 enabled_extension_count: extensions_ptrs.len() as u32,
334                 pp_enabled_extension_names: extensions_ptrs.as_ptr(),
335                 p_enabled_features: if has_khr_get_physical_device_properties2 {
336                     ptr::null()
337                 } else {
338                     &features_ffi.head_as_ref().features
339                 },
340                 ..Default::default()
341             };
342 
343             let mut output = MaybeUninit::uninit();
344             check_errors(fns_i.v1_0.create_device(
345                 physical_device.internal_object(),
346                 &infos,
347                 ptr::null(),
348                 output.as_mut_ptr(),
349             ))?;
350 
351             (output.assume_init(), output_queues)
352         };
353 
354         // loading the function pointers of the newly-created device
355         let fns = DeviceFunctions::load(|name| unsafe {
356             mem::transmute(fns_i.v1_0.get_device_proc_addr(device, name.as_ptr()))
357         });
358 
359         let mut active_queue_families: SmallVec<[u32; 8]> = SmallVec::new();
360         for (queue_family, _) in queues.iter() {
361             if let None = active_queue_families
362                 .iter()
363                 .find(|&&qf| qf == *queue_family)
364             {
365                 active_queue_families.push(*queue_family);
366             }
367         }
368 
369         let device = Arc::new(Device {
370             instance: physical_device.instance().clone(),
371             physical_device: physical_device.index(),
372             device: device,
373             api_version,
374             fns,
375             standard_pool: Mutex::new(Weak::new()),
376             standard_descriptor_pool: Mutex::new(Weak::new()),
377             standard_command_pools: Mutex::new(Default::default()),
378             features: Features {
379                 // Always enabled ; see above
380                 robust_buffer_access: true,
381                 ..requested_features.clone()
382             },
383             extensions: requested_extensions.clone(),
384             active_queue_families,
385             allocation_count: Mutex::new(0),
386             fence_pool: Mutex::new(Vec::new()),
387             semaphore_pool: Mutex::new(Vec::new()),
388             event_pool: Mutex::new(Vec::new()),
389         });
390 
391         // Iterator for the produced queues.
392         let queues = QueuesIter {
393             next_queue: 0,
394             device: device.clone(),
395             families_and_ids: queues,
396         };
397 
398         Ok((device, queues))
399     }
400 
401     /// Returns the Vulkan version supported by the device.
402     ///
403     /// This is the lower of the
404     /// [physical device's supported version](crate::instance::PhysicalDevice::api_version) and
405     /// the instance's [`max_api_version`](crate::instance::Instance::max_api_version).
406     #[inline]
api_version(&self) -> Version407     pub fn api_version(&self) -> Version {
408         self.api_version
409     }
410 
411     /// Grants access to the Vulkan functions of the device.
412     #[inline]
fns(&self) -> &DeviceFunctions413     pub fn fns(&self) -> &DeviceFunctions {
414         &self.fns
415     }
416 
417     /// Waits until all work on this device has finished. You should never need to call
418     /// this function, but it can be useful for debugging or benchmarking purposes.
419     ///
420     /// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`.
421     ///
422     /// # Safety
423     ///
424     /// This function is not thread-safe. You must not submit anything to any of the queue
425     /// of the device (either explicitly or implicitly, for example with a future's destructor)
426     /// while this function is waiting.
427     ///
wait(&self) -> Result<(), OomError>428     pub unsafe fn wait(&self) -> Result<(), OomError> {
429         check_errors(self.fns.v1_0.device_wait_idle(self.device))?;
430         Ok(())
431     }
432 
433     /// Returns the instance used to create this device.
434     #[inline]
instance(&self) -> &Arc<Instance>435     pub fn instance(&self) -> &Arc<Instance> {
436         &self.instance
437     }
438 
439     /// Returns the physical device that was used to create this device.
440     #[inline]
physical_device(&self) -> PhysicalDevice441     pub fn physical_device(&self) -> PhysicalDevice {
442         PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
443     }
444 
445     /// Returns an iterator to the list of queues families that this device uses.
446     ///
447     /// > **Note**: Will return `-> impl ExactSizeIterator<Item = QueueFamily>` in the future.
448     // TODO: ^
449     #[inline]
active_queue_families<'a>( &'a self, ) -> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a>450     pub fn active_queue_families<'a>(
451         &'a self,
452     ) -> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a> {
453         let physical_device = self.physical_device();
454         Box::new(
455             self.active_queue_families
456                 .iter()
457                 .map(move |&id| physical_device.queue_family_by_id(id).unwrap()),
458         )
459     }
460 
461     /// Returns the features that have been enabled on the device.
462     #[inline]
enabled_features(&self) -> &Features463     pub fn enabled_features(&self) -> &Features {
464         &self.features
465     }
466 
467     /// Returns the extensions that have been enabled on the device.
468     #[inline]
enabled_extensions(&self) -> &DeviceExtensions469     pub fn enabled_extensions(&self) -> &DeviceExtensions {
470         &self.extensions
471     }
472 
473     /// Returns the standard memory pool used by default if you don't provide any other pool.
standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool>474     pub fn standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool> {
475         let mut pool = me.standard_pool.lock().unwrap();
476 
477         if let Some(p) = pool.upgrade() {
478             return p;
479         }
480 
481         // The weak pointer is empty, so we create the pool.
482         let new_pool = StdMemoryPool::new(me.clone());
483         *pool = Arc::downgrade(&new_pool);
484         new_pool
485     }
486 
487     /// Returns the standard descriptor pool used by default if you don't provide any other pool.
standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool>488     pub fn standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool> {
489         let mut pool = me.standard_descriptor_pool.lock().unwrap();
490 
491         if let Some(p) = pool.upgrade() {
492             return p;
493         }
494 
495         // The weak pointer is empty, so we create the pool.
496         let new_pool = Arc::new(StdDescriptorPool::new(me.clone()));
497         *pool = Arc::downgrade(&new_pool);
498         new_pool
499     }
500 
501     /// Returns the standard command buffer pool used by default if you don't provide any other
502     /// pool.
503     ///
504     /// # Panic
505     ///
506     /// - Panics if the device and the queue family don't belong to the same physical device.
507     ///
standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool>508     pub fn standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool> {
509         let mut standard_command_pools = me.standard_command_pools.lock().unwrap();
510 
511         match standard_command_pools.entry(queue.id()) {
512             Entry::Occupied(mut entry) => {
513                 if let Some(pool) = entry.get().upgrade() {
514                     return pool;
515                 }
516 
517                 let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
518                 *entry.get_mut() = Arc::downgrade(&new_pool);
519                 new_pool
520             }
521             Entry::Vacant(entry) => {
522                 let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
523                 entry.insert(Arc::downgrade(&new_pool));
524                 new_pool
525             }
526         }
527     }
528 
529     /// Used to track the number of allocations on this device.
530     ///
531     /// To ensure valid usage of the Vulkan API, we cannot call `vkAllocateMemory` when
532     /// `maxMemoryAllocationCount` has been exceeded. See the Vulkan specs:
533     /// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#vkAllocateMemory
534     ///
535     /// Warning: You should never modify this value, except in `device_memory` module
allocation_count(&self) -> &Mutex<u32>536     pub(crate) fn allocation_count(&self) -> &Mutex<u32> {
537         &self.allocation_count
538     }
539 
fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>>540     pub(crate) fn fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>> {
541         &self.fence_pool
542     }
543 
semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>>544     pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>> {
545         &self.semaphore_pool
546     }
547 
event_pool(&self) -> &Mutex<Vec<ash::vk::Event>>548     pub(crate) fn event_pool(&self) -> &Mutex<Vec<ash::vk::Event>> {
549         &self.event_pool
550     }
551 
552     /// Assigns a human-readable name to `object` for debugging purposes.
553     ///
554     /// # Panics
555     /// * If `object` is not owned by this device.
set_object_name<T: VulkanObject + DeviceOwned>( &self, object: &T, name: &CStr, ) -> Result<(), OomError>556     pub fn set_object_name<T: VulkanObject + DeviceOwned>(
557         &self,
558         object: &T,
559         name: &CStr,
560     ) -> Result<(), OomError> {
561         assert!(object.device().internal_object() == self.internal_object());
562         unsafe {
563             self.set_object_name_raw(T::Object::TYPE, object.internal_object().as_raw(), name)
564         }
565     }
566 
567     /// Assigns a human-readable name to `object` for debugging purposes.
568     ///
569     /// # Safety
570     /// `object` must be a Vulkan handle owned by this device, and its type must be accurately described by `ty`.
set_object_name_raw( &self, ty: ash::vk::ObjectType, object: u64, name: &CStr, ) -> Result<(), OomError>571     pub unsafe fn set_object_name_raw(
572         &self,
573         ty: ash::vk::ObjectType,
574         object: u64,
575         name: &CStr,
576     ) -> Result<(), OomError> {
577         let info = ash::vk::DebugUtilsObjectNameInfoEXT {
578             object_type: ty,
579             object_handle: object,
580             p_object_name: name.as_ptr(),
581             ..Default::default()
582         };
583         check_errors(
584             self.instance
585                 .fns()
586                 .ext_debug_utils
587                 .set_debug_utils_object_name_ext(self.device, &info),
588         )?;
589         Ok(())
590     }
591 
592     /// Checks the given combination of image attributes/configuration for compatibility with the physical device.
593     ///
594     /// Returns a struct with additional capabilities available for this image configuration.
image_format_properties( &self, format: Format, ty: ImageType, tiling: ImageTiling, usage: ImageUsage, create_flags: ImageCreateFlags, ) -> Result<ImageFormatProperties, String>595     pub fn image_format_properties(
596         &self,
597         format: Format,
598         ty: ImageType,
599         tiling: ImageTiling,
600         usage: ImageUsage,
601         create_flags: ImageCreateFlags,
602     ) -> Result<ImageFormatProperties, String> {
603         let fns_i = self.instance().fns();
604         let mut output = MaybeUninit::uninit();
605         let physical_device = self.physical_device().internal_object();
606         unsafe {
607             let r = fns_i.v1_0.get_physical_device_image_format_properties(
608                 physical_device,
609                 format.into(),
610                 ty.into(),
611                 tiling.into(),
612                 usage.into(),
613                 create_flags.into(),
614                 output.as_mut_ptr(),
615             );
616 
617             match check_errors(r) {
618                 Ok(_) => Ok(output.assume_init().into()),
619                 Err(e) => {
620                     return Err(String::from(format!(
621                         "Image properties not supported. {:#?}",
622                         e
623                     )))
624                 }
625             }
626         }
627     }
628 }
629 
630 impl fmt::Debug for Device {
631     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>632     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
633         write!(fmt, "<Vulkan device {:?}>", self.device)
634     }
635 }
636 
637 unsafe impl VulkanObject for Device {
638     type Object = ash::vk::Device;
639 
640     #[inline]
internal_object(&self) -> ash::vk::Device641     fn internal_object(&self) -> ash::vk::Device {
642         self.device
643     }
644 }
645 
646 impl Drop for Device {
647     #[inline]
drop(&mut self)648     fn drop(&mut self) {
649         unsafe {
650             for &raw_fence in self.fence_pool.lock().unwrap().iter() {
651                 self.fns
652                     .v1_0
653                     .destroy_fence(self.device, raw_fence, ptr::null());
654             }
655             for &raw_sem in self.semaphore_pool.lock().unwrap().iter() {
656                 self.fns
657                     .v1_0
658                     .destroy_semaphore(self.device, raw_sem, ptr::null());
659             }
660             for &raw_event in self.event_pool.lock().unwrap().iter() {
661                 self.fns
662                     .v1_0
663                     .destroy_event(self.device, raw_event, ptr::null());
664             }
665             self.fns.v1_0.destroy_device(self.device, ptr::null());
666         }
667     }
668 }
669 
670 impl PartialEq for Device {
671     #[inline]
eq(&self, other: &Self) -> bool672     fn eq(&self, other: &Self) -> bool {
673         self.device == other.device && self.instance == other.instance
674     }
675 }
676 
677 impl Eq for Device {}
678 
679 impl Hash for Device {
680     #[inline]
hash<H: Hasher>(&self, state: &mut H)681     fn hash<H: Hasher>(&self, state: &mut H) {
682         self.device.hash(state);
683         self.instance.hash(state);
684     }
685 }
686 
687 /// Implemented on objects that belong to a Vulkan device.
688 ///
689 /// # Safety
690 ///
691 /// - `device()` must return the correct device.
692 ///
693 pub unsafe trait DeviceOwned {
694     /// Returns the device that owns `Self`.
device(&self) -> &Arc<Device>695     fn device(&self) -> &Arc<Device>;
696 }
697 
698 unsafe impl<T> DeviceOwned for T
699 where
700     T: Deref,
701     T::Target: DeviceOwned,
702 {
703     #[inline]
device(&self) -> &Arc<Device>704     fn device(&self) -> &Arc<Device> {
705         (**self).device()
706     }
707 }
708 
709 /// Iterator that returns the queues produced when creating a device.
710 pub struct QueuesIter {
711     next_queue: usize,
712     device: Arc<Device>,
713     families_and_ids: SmallVec<[(u32, u32); 8]>,
714 }
715 
716 unsafe impl DeviceOwned for QueuesIter {
device(&self) -> &Arc<Device>717     fn device(&self) -> &Arc<Device> {
718         &self.device
719     }
720 }
721 
722 impl Iterator for QueuesIter {
723     type Item = Arc<Queue>;
724 
next(&mut self) -> Option<Arc<Queue>>725     fn next(&mut self) -> Option<Arc<Queue>> {
726         unsafe {
727             let &(family, id) = match self.families_and_ids.get(self.next_queue) {
728                 Some(a) => a,
729                 None => return None,
730             };
731 
732             self.next_queue += 1;
733 
734             let mut output = MaybeUninit::uninit();
735             self.device.fns.v1_0.get_device_queue(
736                 self.device.device,
737                 family,
738                 id,
739                 output.as_mut_ptr(),
740             );
741 
742             Some(Arc::new(Queue {
743                 queue: Mutex::new(output.assume_init()),
744                 device: self.device.clone(),
745                 family: family,
746                 id: id,
747             }))
748         }
749     }
750 
751     #[inline]
size_hint(&self) -> (usize, Option<usize>)752     fn size_hint(&self) -> (usize, Option<usize>) {
753         let len = self.families_and_ids.len().saturating_sub(self.next_queue);
754         (len, Some(len))
755     }
756 }
757 
758 impl ExactSizeIterator for QueuesIter {}
759 
760 /// Error that can be returned when creating a device.
761 #[derive(Copy, Clone, Debug)]
762 pub enum DeviceCreationError {
763     /// Failed to create the device for an implementation-specific reason.
764     InitializationFailed,
765     /// You have reached the limit to the number of devices that can be created from the same
766     /// physical device.
767     TooManyObjects,
768     /// Failed to connect to the device.
769     DeviceLost,
770     /// Some of the requested features are unsupported by the physical device.
771     FeatureNotPresent,
772     /// Some of the requested device extensions are not supported by the physical device.
773     ExtensionNotPresent,
774     /// Tried to create too many queues for a given family.
775     TooManyQueuesForFamily,
776     /// The priority of one of the queues is out of the [0.0; 1.0] range.
777     PriorityOutOfRange,
778     /// There is no memory available on the host (ie. the CPU, RAM, etc.).
779     OutOfHostMemory,
780     /// There is no memory available on the device (ie. video memory).
781     OutOfDeviceMemory,
782     /// A restriction for an extension was not met.
783     ExtensionRestrictionNotMet(ExtensionRestrictionError),
784     /// A restriction for a feature was not met.
785     FeatureRestrictionNotMet(FeatureRestrictionError),
786 }
787 
788 impl error::Error for DeviceCreationError {}
789 
790 impl fmt::Display for DeviceCreationError {
791     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>792     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
793         match *self {
794             DeviceCreationError::InitializationFailed => {
795                 write!(
796                     fmt,
797                     "failed to create the device for an implementation-specific reason"
798                 )
799             }
800             DeviceCreationError::OutOfHostMemory => write!(fmt, "no memory available on the host"),
801             DeviceCreationError::OutOfDeviceMemory => {
802                 write!(fmt, "no memory available on the graphical device")
803             }
804             DeviceCreationError::DeviceLost => write!(fmt, "failed to connect to the device"),
805             DeviceCreationError::TooManyQueuesForFamily => {
806                 write!(fmt, "tried to create too many queues for a given family")
807             }
808             DeviceCreationError::FeatureNotPresent => {
809                 write!(
810                     fmt,
811                     "some of the requested features are unsupported by the physical device"
812                 )
813             }
814             DeviceCreationError::PriorityOutOfRange => {
815                 write!(
816                     fmt,
817                     "the priority of one of the queues is out of the [0.0; 1.0] range"
818                 )
819             }
820             DeviceCreationError::ExtensionNotPresent => {
821                 write!(fmt,"some of the requested device extensions are not supported by the physical device")
822             }
823             DeviceCreationError::TooManyObjects => {
824                 write!(fmt,"you have reached the limit to the number of devices that can be created from the same physical device")
825             }
826             DeviceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
827             DeviceCreationError::FeatureRestrictionNotMet(err) => err.fmt(fmt),
828         }
829     }
830 }
831 
832 impl From<Error> for DeviceCreationError {
833     #[inline]
from(err: Error) -> DeviceCreationError834     fn from(err: Error) -> DeviceCreationError {
835         match err {
836             Error::InitializationFailed => DeviceCreationError::InitializationFailed,
837             Error::OutOfHostMemory => DeviceCreationError::OutOfHostMemory,
838             Error::OutOfDeviceMemory => DeviceCreationError::OutOfDeviceMemory,
839             Error::DeviceLost => DeviceCreationError::DeviceLost,
840             Error::ExtensionNotPresent => DeviceCreationError::ExtensionNotPresent,
841             Error::FeatureNotPresent => DeviceCreationError::FeatureNotPresent,
842             Error::TooManyObjects => DeviceCreationError::TooManyObjects,
843             _ => panic!("Unexpected error value: {}", err as i32),
844         }
845     }
846 }
847 
848 impl From<ExtensionRestrictionError> for DeviceCreationError {
849     #[inline]
from(err: ExtensionRestrictionError) -> Self850     fn from(err: ExtensionRestrictionError) -> Self {
851         Self::ExtensionRestrictionNotMet(err)
852     }
853 }
854 
855 impl From<FeatureRestrictionError> for DeviceCreationError {
856     #[inline]
from(err: FeatureRestrictionError) -> Self857     fn from(err: FeatureRestrictionError) -> Self {
858         Self::FeatureRestrictionNotMet(err)
859     }
860 }
861 
862 /// Represents a queue where commands can be submitted.
863 // TODO: should use internal synchronization?
864 #[derive(Debug)]
865 pub struct Queue {
866     queue: Mutex<ash::vk::Queue>,
867     device: Arc<Device>,
868     family: u32,
869     id: u32, // id within family
870 }
871 
872 impl Queue {
873     /// Returns the device this queue belongs to.
874     #[inline]
device(&self) -> &Arc<Device>875     pub fn device(&self) -> &Arc<Device> {
876         &self.device
877     }
878 
879     /// Returns true if this is the same queue as another one.
880     #[inline]
is_same(&self, other: &Queue) -> bool881     pub fn is_same(&self, other: &Queue) -> bool {
882         self.id == other.id
883             && self.family == other.family
884             && self.device.internal_object() == other.device.internal_object()
885     }
886 
887     /// Returns the family this queue belongs to.
888     #[inline]
family(&self) -> QueueFamily889     pub fn family(&self) -> QueueFamily {
890         self.device
891             .physical_device()
892             .queue_family_by_id(self.family)
893             .unwrap()
894     }
895 
896     /// Returns the index of this queue within its family.
897     #[inline]
id_within_family(&self) -> u32898     pub fn id_within_family(&self) -> u32 {
899         self.id
900     }
901 
902     /// Waits until all work on this queue has finished.
903     ///
904     /// Just like `Device::wait()`, you shouldn't have to call this function in a typical program.
905     #[inline]
wait(&self) -> Result<(), OomError>906     pub fn wait(&self) -> Result<(), OomError> {
907         unsafe {
908             let fns = self.device.fns();
909             let queue = self.queue.lock().unwrap();
910             check_errors(fns.v1_0.queue_wait_idle(*queue))?;
911             Ok(())
912         }
913     }
914 }
915 
916 impl PartialEq for Queue {
eq(&self, other: &Self) -> bool917     fn eq(&self, other: &Self) -> bool {
918         self.is_same(other)
919     }
920 }
921 
922 impl Eq for Queue {}
923 
924 unsafe impl DeviceOwned for Queue {
device(&self) -> &Arc<Device>925     fn device(&self) -> &Arc<Device> {
926         &self.device
927     }
928 }
929 
930 unsafe impl SynchronizedVulkanObject for Queue {
931     type Object = ash::vk::Queue;
932 
933     #[inline]
internal_object_guard(&self) -> MutexGuard<ash::vk::Queue>934     fn internal_object_guard(&self) -> MutexGuard<ash::vk::Queue> {
935         self.queue.lock().unwrap()
936     }
937 }
938 
939 #[cfg(test)]
940 mod tests {
941     use crate::device::physical::PhysicalDevice;
942     use crate::device::Device;
943     use crate::device::DeviceCreationError;
944     use crate::device::DeviceExtensions;
945     use crate::device::{FeatureRestriction, FeatureRestrictionError, Features};
946     use std::sync::Arc;
947 
948     #[test]
one_ref()949     fn one_ref() {
950         let (mut device, _) = gfx_dev_and_queue!();
951         assert!(Arc::get_mut(&mut device).is_some());
952     }
953 
954     #[test]
too_many_queues()955     fn too_many_queues() {
956         let instance = instance!();
957         let physical = match PhysicalDevice::enumerate(&instance).next() {
958             Some(p) => p,
959             None => return,
960         };
961 
962         let family = physical.queue_families().next().unwrap();
963         let queues = (0..family.queues_count() + 1).map(|_| (family, 1.0));
964 
965         match Device::new(
966             physical,
967             &Features::none(),
968             &DeviceExtensions::none(),
969             queues,
970         ) {
971             Err(DeviceCreationError::TooManyQueuesForFamily) => return, // Success
972             _ => panic!(),
973         };
974     }
975 
976     #[test]
unsupposed_features()977     fn unsupposed_features() {
978         let instance = instance!();
979         let physical = match PhysicalDevice::enumerate(&instance).next() {
980             Some(p) => p,
981             None => return,
982         };
983 
984         let family = physical.queue_families().next().unwrap();
985 
986         let features = Features::all();
987         // In the unlikely situation where the device supports everything, we ignore the test.
988         if physical.supported_features().is_superset_of(&features) {
989             return;
990         }
991 
992         match Device::new(
993             physical,
994             &features,
995             &DeviceExtensions::none(),
996             Some((family, 1.0)),
997         ) {
998             Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError {
999                 restriction: FeatureRestriction::NotSupported,
1000                 ..
1001             })) => return, // Success
1002             _ => panic!(),
1003         };
1004     }
1005 
1006     #[test]
priority_out_of_range()1007     fn priority_out_of_range() {
1008         let instance = instance!();
1009         let physical = match PhysicalDevice::enumerate(&instance).next() {
1010             Some(p) => p,
1011             None => return,
1012         };
1013 
1014         let family = physical.queue_families().next().unwrap();
1015 
1016         match Device::new(
1017             physical,
1018             &Features::none(),
1019             &DeviceExtensions::none(),
1020             Some((family, 1.4)),
1021         ) {
1022             Err(DeviceCreationError::PriorityOutOfRange) => (), // Success
1023             _ => panic!(),
1024         };
1025 
1026         match Device::new(
1027             physical,
1028             &Features::none(),
1029             &DeviceExtensions::none(),
1030             Some((family, -0.2)),
1031         ) {
1032             Err(DeviceCreationError::PriorityOutOfRange) => (), // Success
1033             _ => panic!(),
1034         };
1035     }
1036 }
1037