• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 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 use crate::check_errors;
11 use crate::device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi};
12 use crate::instance::{Instance, InstanceCreationError};
13 use crate::sync::PipelineStage;
14 use crate::DeviceSize;
15 use crate::Version;
16 use crate::VulkanObject;
17 use std::convert::TryFrom;
18 use std::ffi::CStr;
19 use std::fmt;
20 use std::hash::Hash;
21 use std::mem::MaybeUninit;
22 use std::ptr;
23 use std::sync::Arc;
24 
25 #[derive(Clone, Debug)]
26 pub(crate) struct PhysicalDeviceInfo {
27     handle: ash::vk::PhysicalDevice,
28     api_version: Version,
29     supported_extensions: DeviceExtensions,
30     required_extensions: DeviceExtensions,
31     supported_features: Features,
32     properties: Properties,
33     memory_properties: ash::vk::PhysicalDeviceMemoryProperties,
34     queue_families: Vec<ash::vk::QueueFamilyProperties>,
35 }
36 
init_physical_devices( instance: &Instance, ) -> Result<Vec<PhysicalDeviceInfo>, InstanceCreationError>37 pub(crate) fn init_physical_devices(
38     instance: &Instance,
39 ) -> Result<Vec<PhysicalDeviceInfo>, InstanceCreationError> {
40     let fns = instance.fns();
41     let instance_extensions = instance.enabled_extensions();
42 
43     let handles: Vec<ash::vk::PhysicalDevice> = unsafe {
44         let mut num = 0;
45         check_errors(fns.v1_0.enumerate_physical_devices(
46             instance.internal_object(),
47             &mut num,
48             ptr::null_mut(),
49         ))?;
50 
51         let mut handles = Vec::with_capacity(num as usize);
52         check_errors(fns.v1_0.enumerate_physical_devices(
53             instance.internal_object(),
54             &mut num,
55             handles.as_mut_ptr(),
56         ))?;
57         handles.set_len(num as usize);
58         handles
59     };
60 
61     let mut infos: Vec<PhysicalDeviceInfo> = handles
62         .into_iter()
63         .enumerate()
64         .map(|(index, handle)| -> Result<_, InstanceCreationError> {
65             let api_version = unsafe {
66                 let mut output = MaybeUninit::uninit();
67                 fns.v1_0
68                     .get_physical_device_properties(handle, output.as_mut_ptr());
69                 let api_version = Version::try_from(output.assume_init().api_version).unwrap();
70                 std::cmp::min(instance.max_api_version(), api_version)
71             };
72 
73             let extension_properties: Vec<ash::vk::ExtensionProperties> = unsafe {
74                 let mut num = 0;
75                 check_errors(fns.v1_0.enumerate_device_extension_properties(
76                     handle,
77                     ptr::null(),
78                     &mut num,
79                     ptr::null_mut(),
80                 ))?;
81 
82                 let mut properties = Vec::with_capacity(num as usize);
83                 check_errors(fns.v1_0.enumerate_device_extension_properties(
84                     handle,
85                     ptr::null(),
86                     &mut num,
87                     properties.as_mut_ptr(),
88                 ))?;
89                 properties.set_len(num as usize);
90                 properties
91             };
92 
93             let supported_extensions = DeviceExtensions::from(
94                 extension_properties
95                     .iter()
96                     .map(|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }),
97             );
98 
99             let required_extensions = supported_extensions
100                 .intersection(&DeviceExtensions::required_if_supported_extensions());
101 
102             Ok(PhysicalDeviceInfo {
103                 handle,
104                 api_version,
105                 supported_extensions,
106                 required_extensions,
107                 supported_features: Default::default(),
108                 properties: Default::default(),
109                 memory_properties: Default::default(),
110                 queue_families: Default::default(),
111             })
112         })
113         .collect::<Result<_, _>>()?;
114 
115     // Getting the remaining infos.
116     // If possible, we use VK_KHR_get_physical_device_properties2.
117     if instance.api_version() >= Version::V1_1
118         || instance_extensions.khr_get_physical_device_properties2
119     {
120         init_physical_devices_inner2(instance, &mut infos)
121     } else {
122         init_physical_devices_inner(instance, &mut infos)
123     };
124 
125     Ok(infos)
126 }
127 
128 /// Initialize all physical devices
init_physical_devices_inner(instance: &Instance, infos: &mut [PhysicalDeviceInfo])129 fn init_physical_devices_inner(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) {
130     let fns = instance.fns();
131 
132     for info in infos.into_iter() {
133         info.supported_features = unsafe {
134             let mut output = FeaturesFfi::default();
135             fns.v1_0
136                 .get_physical_device_features(info.handle, &mut output.head_as_mut().features);
137             Features::from(&output)
138         };
139 
140         info.properties = unsafe {
141             let mut output = PropertiesFfi::default();
142             output.make_chain(
143                 info.api_version,
144                 &info.supported_extensions,
145                 instance.enabled_extensions(),
146             );
147             fns.v1_0
148                 .get_physical_device_properties(info.handle, &mut output.head_as_mut().properties);
149             Properties::from(&output)
150         };
151 
152         info.memory_properties = unsafe {
153             let mut output = MaybeUninit::uninit();
154             fns.v1_0
155                 .get_physical_device_memory_properties(info.handle, output.as_mut_ptr());
156             output.assume_init()
157         };
158 
159         info.queue_families = unsafe {
160             let mut num = 0;
161             fns.v1_0.get_physical_device_queue_family_properties(
162                 info.handle,
163                 &mut num,
164                 ptr::null_mut(),
165             );
166 
167             let mut families = Vec::with_capacity(num as usize);
168             fns.v1_0.get_physical_device_queue_family_properties(
169                 info.handle,
170                 &mut num,
171                 families.as_mut_ptr(),
172             );
173             families.set_len(num as usize);
174             families
175         };
176     }
177 }
178 
179 /// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2
180 /// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
init_physical_devices_inner2(instance: &Instance, infos: &mut [PhysicalDeviceInfo])181 fn init_physical_devices_inner2(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) {
182     let fns = instance.fns();
183 
184     for info in infos.into_iter() {
185         info.supported_features = unsafe {
186             let mut output = FeaturesFfi::default();
187             output.make_chain(
188                 info.api_version,
189                 &info.supported_extensions,
190                 instance.enabled_extensions(),
191             );
192 
193             if instance.api_version() >= Version::V1_1 {
194                 fns.v1_1
195                     .get_physical_device_features2(info.handle, output.head_as_mut());
196             } else {
197                 fns.khr_get_physical_device_properties2
198                     .get_physical_device_features2_khr(info.handle, output.head_as_mut());
199             }
200 
201             Features::from(&output)
202         };
203 
204         info.properties = unsafe {
205             let mut output = PropertiesFfi::default();
206             output.make_chain(
207                 info.api_version,
208                 &info.supported_extensions,
209                 instance.enabled_extensions(),
210             );
211 
212             if instance.api_version() >= Version::V1_1 {
213                 fns.v1_1
214                     .get_physical_device_properties2(info.handle, output.head_as_mut());
215             } else {
216                 fns.khr_get_physical_device_properties2
217                     .get_physical_device_properties2_khr(info.handle, output.head_as_mut());
218             }
219 
220             Properties::from(&output)
221         };
222 
223         info.memory_properties = unsafe {
224             let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
225 
226             if instance.api_version() >= Version::V1_1 {
227                 fns.v1_1
228                     .get_physical_device_memory_properties2(info.handle, &mut output);
229             } else {
230                 fns.khr_get_physical_device_properties2
231                     .get_physical_device_memory_properties2_khr(info.handle, &mut output);
232             }
233 
234             output.memory_properties
235         };
236 
237         info.queue_families = unsafe {
238             let mut num = 0;
239 
240             if instance.api_version() >= Version::V1_1 {
241                 fns.v1_1.get_physical_device_queue_family_properties2(
242                     info.handle,
243                     &mut num,
244                     ptr::null_mut(),
245                 );
246             } else {
247                 fns.khr_get_physical_device_properties2
248                     .get_physical_device_queue_family_properties2_khr(
249                         info.handle,
250                         &mut num,
251                         ptr::null_mut(),
252                     );
253             }
254 
255             let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
256 
257             if instance.api_version() >= Version::V1_1 {
258                 fns.v1_1.get_physical_device_queue_family_properties2(
259                     info.handle,
260                     &mut num,
261                     families.as_mut_ptr(),
262                 );
263             } else {
264                 fns.khr_get_physical_device_properties2
265                     .get_physical_device_queue_family_properties2_khr(
266                         info.handle,
267                         &mut num,
268                         families.as_mut_ptr(),
269                     );
270             }
271 
272             families
273                 .into_iter()
274                 .map(|family| family.queue_family_properties)
275                 .collect()
276         };
277     }
278 }
279 
280 /// Represents one of the available devices on this machine.
281 ///
282 /// This struct simply contains a pointer to an instance and a number representing the physical
283 /// device. You are therefore encouraged to pass this around by value instead of by reference.
284 ///
285 /// # Example
286 ///
287 /// ```no_run
288 /// # use vulkano::instance::Instance;
289 /// # use vulkano::instance::InstanceExtensions;
290 /// # use vulkano::Version;
291 /// use vulkano::device::physical::PhysicalDevice;
292 ///
293 /// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
294 /// for physical_device in PhysicalDevice::enumerate(&instance) {
295 ///     print_infos(physical_device);
296 /// }
297 ///
298 /// fn print_infos(dev: PhysicalDevice) {
299 ///     println!("Name: {}", dev.properties().device_name);
300 /// }
301 /// ```
302 #[derive(Clone, Copy, Debug)]
303 pub struct PhysicalDevice<'a> {
304     instance: &'a Arc<Instance>,
305     index: usize,
306     info: &'a PhysicalDeviceInfo,
307 }
308 
309 impl<'a> PhysicalDevice<'a> {
310     /// Returns an iterator that enumerates the physical devices available.
311     ///
312     /// # Example
313     ///
314     /// ```no_run
315     /// # use vulkano::instance::Instance;
316     /// # use vulkano::instance::InstanceExtensions;
317     /// # use vulkano::Version;
318     /// use vulkano::device::physical::PhysicalDevice;
319     ///
320     /// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
321     /// for physical_device in PhysicalDevice::enumerate(&instance) {
322     ///     println!("Available device: {}", physical_device.properties().device_name);
323     /// }
324     /// ```
325     #[inline]
enumerate( instance: &'a Arc<Instance>, ) -> impl ExactSizeIterator<Item = PhysicalDevice<'a>>326     pub fn enumerate(
327         instance: &'a Arc<Instance>,
328     ) -> impl ExactSizeIterator<Item = PhysicalDevice<'a>> {
329         instance
330             .physical_device_infos
331             .iter()
332             .enumerate()
333             .map(move |(index, info)| PhysicalDevice {
334                 instance,
335                 index,
336                 info,
337             })
338     }
339 
340     /// Returns a physical device from its index. Returns `None` if out of range.
341     ///
342     /// Indices range from 0 to the number of devices.
343     ///
344     /// # Example
345     ///
346     /// ```no_run
347     /// use vulkano::instance::Instance;
348     /// use vulkano::instance::InstanceExtensions;
349     /// use vulkano::device::physical::PhysicalDevice;
350     /// use vulkano::Version;
351     ///
352     /// let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
353     /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap();
354     /// ```
355     #[inline]
from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>>356     pub fn from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>> {
357         instance
358             .physical_device_infos
359             .get(index)
360             .map(|info| PhysicalDevice {
361                 instance,
362                 index,
363                 info,
364             })
365     }
366 
367     /// Returns the instance corresponding to this physical device.
368     ///
369     /// # Example
370     ///
371     /// ```no_run
372     /// use vulkano::device::physical::PhysicalDevice;
373     ///
374     /// fn do_something(physical_device: PhysicalDevice) {
375     ///     let _loaded_extensions = physical_device.instance().enabled_extensions();
376     ///     // ...
377     /// }
378     /// ```
379     #[inline]
instance(&self) -> &'a Arc<Instance>380     pub fn instance(&self) -> &'a Arc<Instance> {
381         &self.instance
382     }
383 
384     /// Returns the index of the physical device in the physical devices list.
385     ///
386     /// This index never changes and can be used later to retrieve a `PhysicalDevice` from an
387     /// instance and an index.
388     #[inline]
index(&self) -> usize389     pub fn index(&self) -> usize {
390         self.index
391     }
392 
393     /// Returns the version of Vulkan supported by this device.
394     ///
395     /// Unlike the `api_version` property, which is the version reported by the device directly,
396     /// this function returns the version the device can actually support, based on the instance's,
397     /// `max_api_version`.
398     #[inline]
api_version(&self) -> Version399     pub fn api_version(&self) -> Version {
400         self.info.api_version
401     }
402 
403     /// Returns the extensions that are supported by this physical device.
404     #[inline]
supported_extensions(&self) -> &'a DeviceExtensions405     pub fn supported_extensions(&self) -> &'a DeviceExtensions {
406         &self.info.supported_extensions
407     }
408 
409     /// Returns the extensions that must be enabled as a minimum when creating a `Device` from this
410     /// physical device.
required_extensions(&self) -> &'a DeviceExtensions411     pub fn required_extensions(&self) -> &'a DeviceExtensions {
412         &self.info.required_extensions
413     }
414 
415     /// Returns the properties reported by the device.
416     #[inline]
properties(&self) -> &'a Properties417     pub fn properties(&self) -> &'a Properties {
418         &self.info.properties
419     }
420 
421     /// Returns the features that are supported by this physical device.
422     #[inline]
supported_features(&self) -> &'a Features423     pub fn supported_features(&self) -> &'a Features {
424         &self.info.supported_features
425     }
426 
427     /// Builds an iterator that enumerates all the memory types on this physical device.
428     #[inline]
memory_types(&self) -> impl ExactSizeIterator<Item = MemoryType<'a>>429     pub fn memory_types(&self) -> impl ExactSizeIterator<Item = MemoryType<'a>> {
430         let physical_device = *self;
431         self.info.memory_properties.memory_types
432             [0..self.info.memory_properties.memory_type_count as usize]
433             .iter()
434             .enumerate()
435             .map(move |(id, info)| MemoryType {
436                 physical_device,
437                 id: id as u32,
438                 info,
439             })
440     }
441 
442     /// Returns the memory type with the given index, or `None` if out of range.
443     #[inline]
memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>>444     pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> {
445         if id < self.info.memory_properties.memory_type_count {
446             Some(MemoryType {
447                 physical_device: *self,
448                 id,
449                 info: &self.info.memory_properties.memory_types[id as usize],
450             })
451         } else {
452             None
453         }
454     }
455 
456     /// Builds an iterator that enumerates all the memory heaps on this physical device.
457     #[inline]
memory_heaps(&self) -> impl ExactSizeIterator<Item = MemoryHeap<'a>>458     pub fn memory_heaps(&self) -> impl ExactSizeIterator<Item = MemoryHeap<'a>> {
459         let physical_device = *self;
460         self.info.memory_properties.memory_heaps
461             [0..self.info.memory_properties.memory_heap_count as usize]
462             .iter()
463             .enumerate()
464             .map(move |(id, info)| MemoryHeap {
465                 physical_device,
466                 id: id as u32,
467                 info,
468             })
469     }
470 
471     /// Returns the memory heap with the given index, or `None` if out of range.
472     #[inline]
memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>>473     pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> {
474         if id < self.info.memory_properties.memory_heap_count {
475             Some(MemoryHeap {
476                 physical_device: *self,
477                 id,
478                 info: &self.info.memory_properties.memory_heaps[id as usize],
479             })
480         } else {
481             None
482         }
483     }
484 
485     /// Builds an iterator that enumerates all the queue families on this physical device.
486     #[inline]
queue_families(&self) -> impl ExactSizeIterator<Item = QueueFamily<'a>>487     pub fn queue_families(&self) -> impl ExactSizeIterator<Item = QueueFamily<'a>> {
488         let physical_device = *self;
489         self.info
490             .queue_families
491             .iter()
492             .enumerate()
493             .map(move |(id, properties)| QueueFamily {
494                 physical_device,
495                 id: id as u32,
496                 properties,
497             })
498     }
499 
500     /// Returns the queue family with the given index, or `None` if out of range.
501     #[inline]
queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>>502     pub fn queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>> {
503         if (id as usize) < self.info.queue_families.len() {
504             Some(QueueFamily {
505                 physical_device: *self,
506                 id,
507                 properties: &self.info.queue_families[id as usize],
508             })
509         } else {
510             None
511         }
512     }
513 }
514 
515 unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
516     type Object = ash::vk::PhysicalDevice;
517 
518     #[inline]
internal_object(&self) -> ash::vk::PhysicalDevice519     fn internal_object(&self) -> ash::vk::PhysicalDevice {
520         self.info.handle
521     }
522 }
523 
524 /// Type of a physical device.
525 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
526 #[repr(i32)]
527 pub enum PhysicalDeviceType {
528     /// The device is an integrated GPU.
529     IntegratedGpu = ash::vk::PhysicalDeviceType::INTEGRATED_GPU.as_raw(),
530     /// The device is a discrete GPU.
531     DiscreteGpu = ash::vk::PhysicalDeviceType::DISCRETE_GPU.as_raw(),
532     /// The device is a virtual GPU.
533     VirtualGpu = ash::vk::PhysicalDeviceType::VIRTUAL_GPU.as_raw(),
534     /// The device is a CPU.
535     Cpu = ash::vk::PhysicalDeviceType::CPU.as_raw(),
536     /// The device is something else.
537     Other = ash::vk::PhysicalDeviceType::OTHER.as_raw(),
538 }
539 
540 /// VkPhysicalDeviceType::Other is represented as 0
541 impl Default for PhysicalDeviceType {
default() -> Self542   fn default() -> Self {
543     PhysicalDeviceType::Other
544   }
545 }
546 
547 impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
548     type Error = ();
549 
550     #[inline]
try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error>551     fn try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error> {
552         match val {
553             ash::vk::PhysicalDeviceType::INTEGRATED_GPU => Ok(Self::IntegratedGpu),
554             ash::vk::PhysicalDeviceType::DISCRETE_GPU => Ok(Self::DiscreteGpu),
555             ash::vk::PhysicalDeviceType::VIRTUAL_GPU => Ok(Self::VirtualGpu),
556             ash::vk::PhysicalDeviceType::CPU => Ok(Self::Cpu),
557             ash::vk::PhysicalDeviceType::OTHER => Ok(Self::Other),
558             _ => Err(()),
559         }
560     }
561 }
562 
563 /// Represents a memory type in a physical device.
564 #[derive(Debug, Copy, Clone)]
565 pub struct MemoryType<'a> {
566     physical_device: PhysicalDevice<'a>,
567     id: u32,
568     info: &'a ash::vk::MemoryType,
569 }
570 
571 impl<'a> MemoryType<'a> {
572     /// Returns the physical device associated to this memory type.
573     #[inline]
physical_device(&self) -> PhysicalDevice<'a>574     pub fn physical_device(&self) -> PhysicalDevice<'a> {
575         self.physical_device
576     }
577 
578     /// Returns the identifier of this memory type within the physical device.
579     #[inline]
id(&self) -> u32580     pub fn id(&self) -> u32 {
581         self.id
582     }
583 
584     /// Returns the heap that corresponds to this memory type.
585     #[inline]
heap(&self) -> MemoryHeap<'a>586     pub fn heap(&self) -> MemoryHeap<'a> {
587         self.physical_device
588             .memory_heap_by_id(self.info.heap_index)
589             .unwrap()
590     }
591 
592     /// Returns true if the memory type is located on the device, which means that it's the most
593     /// efficient for GPU accesses.
594     #[inline]
is_device_local(&self) -> bool595     pub fn is_device_local(&self) -> bool {
596         !(self.info.property_flags & ash::vk::MemoryPropertyFlags::DEVICE_LOCAL).is_empty()
597     }
598 
599     /// Returns true if the memory type can be accessed by the host.
600     #[inline]
is_host_visible(&self) -> bool601     pub fn is_host_visible(&self) -> bool {
602         !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_VISIBLE).is_empty()
603     }
604 
605     /// Returns true if modifications made by the host or the GPU on this memory type are
606     /// instantaneously visible to the other party. False means that changes have to be flushed.
607     ///
608     /// You don't need to worry about this, as this library handles that for you.
609     #[inline]
is_host_coherent(&self) -> bool610     pub fn is_host_coherent(&self) -> bool {
611         !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_COHERENT).is_empty()
612     }
613 
614     /// Returns true if memory of this memory type is cached by the host. Host memory accesses to
615     /// cached memory is faster than for uncached memory. However you are not guaranteed that it
616     /// is coherent.
617     #[inline]
is_host_cached(&self) -> bool618     pub fn is_host_cached(&self) -> bool {
619         !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_CACHED).is_empty()
620     }
621 
622     /// Returns true if allocations made to this memory type is lazy.
623     ///
624     /// This means that no actual allocation is performed. Instead memory is automatically
625     /// allocated by the Vulkan implementation.
626     ///
627     /// Memory of this type can only be used on images created with a certain flag. Memory of this
628     /// type is never host-visible.
629     #[inline]
is_lazily_allocated(&self) -> bool630     pub fn is_lazily_allocated(&self) -> bool {
631         !(self.info.property_flags & ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED).is_empty()
632     }
633 }
634 
635 /// Represents a memory heap in a physical device.
636 #[derive(Debug, Copy, Clone)]
637 pub struct MemoryHeap<'a> {
638     physical_device: PhysicalDevice<'a>,
639     id: u32,
640     info: &'a ash::vk::MemoryHeap,
641 }
642 
643 impl<'a> MemoryHeap<'a> {
644     /// Returns the physical device associated to this memory heap.
645     #[inline]
physical_device(&self) -> PhysicalDevice<'a>646     pub fn physical_device(&self) -> PhysicalDevice<'a> {
647         self.physical_device
648     }
649 
650     /// Returns the identifier of this memory heap within the physical device.
651     #[inline]
id(&self) -> u32652     pub fn id(&self) -> u32 {
653         self.id
654     }
655 
656     /// Returns the size in bytes on this heap.
657     #[inline]
size(&self) -> DeviceSize658     pub fn size(&self) -> DeviceSize {
659         self.info.size
660     }
661 
662     /// Returns true if the heap is local to the GPU.
663     #[inline]
is_device_local(&self) -> bool664     pub fn is_device_local(&self) -> bool {
665         !(self.info.flags & ash::vk::MemoryHeapFlags::DEVICE_LOCAL).is_empty()
666     }
667 
668     /// Returns true if the heap is multi-instance enabled, that is allocation from such
669     /// heap will replicate to each physical-device's instance of heap.
670     #[inline]
is_multi_instance(&self) -> bool671     pub fn is_multi_instance(&self) -> bool {
672         !(self.info.flags & ash::vk::MemoryHeapFlags::MULTI_INSTANCE).is_empty()
673     }
674 }
675 
676 /// Represents a queue family in a physical device.
677 ///
678 /// A queue family is group of one or multiple queues. All queues of one family have the same
679 /// characteristics.
680 #[derive(Debug, Copy, Clone)]
681 pub struct QueueFamily<'a> {
682     physical_device: PhysicalDevice<'a>,
683     id: u32,
684     properties: &'a ash::vk::QueueFamilyProperties,
685 }
686 
687 impl<'a> QueueFamily<'a> {
688     /// Returns the physical device associated to this queue family.
689     #[inline]
physical_device(&self) -> PhysicalDevice<'a>690     pub fn physical_device(&self) -> PhysicalDevice<'a> {
691         self.physical_device
692     }
693 
694     /// Returns the identifier of this queue family within the physical device.
695     #[inline]
id(&self) -> u32696     pub fn id(&self) -> u32 {
697         self.id
698     }
699 
700     /// Returns the number of queues that belong to this family.
701     ///
702     /// Guaranteed to be at least 1 (or else that family wouldn't exist).
703     #[inline]
queues_count(&self) -> usize704     pub fn queues_count(&self) -> usize {
705         self.properties.queue_count as usize
706     }
707 
708     /// If timestamps are supported, returns the number of bits supported by timestamp operations.
709     /// The returned value will be in the range 36..64.
710     /// If timestamps are not supported, returns None.
711     #[inline]
timestamp_valid_bits(&self) -> Option<u32>712     pub fn timestamp_valid_bits(&self) -> Option<u32> {
713         let value = self.properties.timestamp_valid_bits;
714         if value == 0 {
715             None
716         } else {
717             Some(value)
718         }
719     }
720 
721     /// Returns the minimum granularity supported for image transfers in terms
722     /// of `[width, height, depth]`
723     #[inline]
min_image_transfer_granularity(&self) -> [u32; 3]724     pub fn min_image_transfer_granularity(&self) -> [u32; 3] {
725         let ref granularity = self.properties.min_image_transfer_granularity;
726         [granularity.width, granularity.height, granularity.depth]
727     }
728 
729     /// Returns `true` if queues of this family can execute graphics operations.
730     #[inline]
supports_graphics(&self) -> bool731     pub fn supports_graphics(&self) -> bool {
732         !(self.properties.queue_flags & ash::vk::QueueFlags::GRAPHICS).is_empty()
733     }
734 
735     /// Returns `true` if queues of this family can execute compute operations.
736     #[inline]
supports_compute(&self) -> bool737     pub fn supports_compute(&self) -> bool {
738         !(self.properties.queue_flags & ash::vk::QueueFlags::COMPUTE).is_empty()
739     }
740 
741     /// Returns `true` if queues of this family can execute transfer operations.
742     /// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform
743     /// > transfer operations, graphics & compute queues only optionally indicate support for tranfers.
744     /// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT
745     /// > to indicate a special relationship with the DMA module and more efficient transfers.
746     #[inline]
explicitly_supports_transfers(&self) -> bool747     pub fn explicitly_supports_transfers(&self) -> bool {
748         !(self.properties.queue_flags & ash::vk::QueueFlags::TRANSFER).is_empty()
749     }
750 
751     /// Returns `true` if queues of this family can execute sparse resources binding operations.
752     #[inline]
supports_sparse_binding(&self) -> bool753     pub fn supports_sparse_binding(&self) -> bool {
754         !(self.properties.queue_flags & ash::vk::QueueFlags::SPARSE_BINDING).is_empty()
755     }
756 
757     /// Returns `true` if the queues of this family support a particular pipeline stage.
758     #[inline]
supports_stage(&self, stage: PipelineStage) -> bool759     pub fn supports_stage(&self, stage: PipelineStage) -> bool {
760         !(self.properties.queue_flags & stage.required_queue_flags()).is_empty()
761     }
762 }
763 
764 impl<'a> PartialEq for QueueFamily<'a> {
eq(&self, other: &Self) -> bool765     fn eq(&self, other: &Self) -> bool {
766         self.id == other.id
767             && self.physical_device.internal_object() == other.physical_device.internal_object()
768     }
769 }
770 
771 impl<'a> Eq for QueueFamily<'a> {}
772 
773 /// The version of the Vulkan conformance test that a driver is conformant against.
774 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
775 pub struct ConformanceVersion {
776     pub major: u8,
777     pub minor: u8,
778     pub subminor: u8,
779     pub patch: u8,
780 }
781 
782 impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
783     #[inline]
from(val: ash::vk::ConformanceVersion) -> Self784     fn from(val: ash::vk::ConformanceVersion) -> Self {
785         ConformanceVersion {
786             major: val.major,
787             minor: val.minor,
788             subminor: val.subminor,
789             patch: val.patch,
790         }
791     }
792 }
793 
794 impl fmt::Debug for ConformanceVersion {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result795     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
796         write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
797     }
798 }
799 
800 impl fmt::Display for ConformanceVersion {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result801     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
802         fmt::Debug::fmt(self, formatter)
803     }
804 }
805 
806 /// An identifier for the driver of a physical device.
807 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
808 #[repr(i32)]
809 pub enum DriverId {
810     AMDProprietary = ash::vk::DriverId::AMD_PROPRIETARY.as_raw(),
811     AMDOpenSource = ash::vk::DriverId::AMD_OPEN_SOURCE.as_raw(),
812     MesaRADV = ash::vk::DriverId::MESA_RADV.as_raw(),
813     NvidiaProprietary = ash::vk::DriverId::NVIDIA_PROPRIETARY.as_raw(),
814     IntelProprietaryWindows = ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS.as_raw(),
815     IntelOpenSourceMesa = ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA.as_raw(),
816     ImaginationProprietary = ash::vk::DriverId::IMAGINATION_PROPRIETARY.as_raw(),
817     QualcommProprietary = ash::vk::DriverId::QUALCOMM_PROPRIETARY.as_raw(),
818     ARMProprietary = ash::vk::DriverId::ARM_PROPRIETARY.as_raw(),
819     GoogleSwiftshader = ash::vk::DriverId::GOOGLE_SWIFTSHADER.as_raw(),
820     GGPProprietary = ash::vk::DriverId::GGP_PROPRIETARY.as_raw(),
821     BroadcomProprietary = ash::vk::DriverId::BROADCOM_PROPRIETARY.as_raw(),
822     MesaLLVMpipe = ash::vk::DriverId::MESA_LLVMPIPE.as_raw(),
823     MoltenVK = ash::vk::DriverId::MOLTENVK.as_raw(),
824 }
825 
826 impl TryFrom<ash::vk::DriverId> for DriverId {
827     type Error = ();
828 
829     #[inline]
try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error>830     fn try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error> {
831         match val {
832             ash::vk::DriverId::AMD_PROPRIETARY => Ok(Self::AMDProprietary),
833             ash::vk::DriverId::AMD_OPEN_SOURCE => Ok(Self::AMDOpenSource),
834             ash::vk::DriverId::MESA_RADV => Ok(Self::MesaRADV),
835             ash::vk::DriverId::NVIDIA_PROPRIETARY => Ok(Self::NvidiaProprietary),
836             ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS => Ok(Self::IntelProprietaryWindows),
837             ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA => Ok(Self::IntelOpenSourceMesa),
838             ash::vk::DriverId::IMAGINATION_PROPRIETARY => Ok(Self::ImaginationProprietary),
839             ash::vk::DriverId::QUALCOMM_PROPRIETARY => Ok(Self::QualcommProprietary),
840             ash::vk::DriverId::ARM_PROPRIETARY => Ok(Self::ARMProprietary),
841             ash::vk::DriverId::GOOGLE_SWIFTSHADER => Ok(Self::GoogleSwiftshader),
842             ash::vk::DriverId::GGP_PROPRIETARY => Ok(Self::GGPProprietary),
843             ash::vk::DriverId::BROADCOM_PROPRIETARY => Ok(Self::BroadcomProprietary),
844             ash::vk::DriverId::MESA_LLVMPIPE => Ok(Self::MesaLLVMpipe),
845             ash::vk::DriverId::MOLTENVK => Ok(Self::MoltenVK),
846             _ => Err(()),
847         }
848     }
849 }
850 
851 /// Specifies which subgroup operations are supported.
852 #[derive(Clone, Copy, Debug)]
853 pub struct SubgroupFeatures {
854     pub basic: bool,
855     pub vote: bool,
856     pub arithmetic: bool,
857     pub ballot: bool,
858     pub shuffle: bool,
859     pub shuffle_relative: bool,
860     pub clustered: bool,
861     pub quad: bool,
862 }
863 
864 impl From<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
865     #[inline]
from(val: ash::vk::SubgroupFeatureFlags) -> Self866     fn from(val: ash::vk::SubgroupFeatureFlags) -> Self {
867         Self {
868             basic: val.intersects(ash::vk::SubgroupFeatureFlags::BASIC),
869             vote: val.intersects(ash::vk::SubgroupFeatureFlags::VOTE),
870             arithmetic: val.intersects(ash::vk::SubgroupFeatureFlags::ARITHMETIC),
871             ballot: val.intersects(ash::vk::SubgroupFeatureFlags::BALLOT),
872             shuffle: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE),
873             shuffle_relative: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE),
874             clustered: val.intersects(ash::vk::SubgroupFeatureFlags::CLUSTERED),
875             quad: val.intersects(ash::vk::SubgroupFeatureFlags::QUAD),
876         }
877     }
878 }
879 
880 /// Specifies how the device clips single point primitives.
881 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
882 #[repr(i32)]
883 pub enum PointClippingBehavior {
884     /// Points are clipped if they lie outside any clip plane, both those bounding the view volume
885     /// and user-defined clip planes.
886     AllClipPlanes = ash::vk::PointClippingBehavior::ALL_CLIP_PLANES.as_raw(),
887     /// Points are clipped only if they lie outside a user-defined clip plane.
888     UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(),
889 }
890 
891 impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior {
892     type Error = ();
893 
894     #[inline]
try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error>895     fn try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error> {
896         match val {
897             ash::vk::PointClippingBehavior::ALL_CLIP_PLANES => Ok(Self::AllClipPlanes),
898             ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY => Ok(Self::UserClipPlanesOnly),
899             _ => Err(()),
900         }
901     }
902 }
903 
904 /// Specifies whether, and how, shader float controls can be set independently.
905 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
906 #[repr(i32)]
907 pub enum ShaderFloatControlsIndependence {
908     Float32Only = ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY.as_raw(),
909     All = ash::vk::ShaderFloatControlsIndependence::ALL.as_raw(),
910     None = ash::vk::ShaderFloatControlsIndependence::NONE.as_raw(),
911 }
912 
913 impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
914     type Error = ();
915 
916     #[inline]
try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error>917     fn try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error> {
918         match val {
919             ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY => Ok(Self::Float32Only),
920             ash::vk::ShaderFloatControlsIndependence::ALL => Ok(Self::All),
921             ash::vk::ShaderFloatControlsIndependence::NONE => Ok(Self::None),
922             _ => Err(()),
923         }
924     }
925 }
926 
927 /// Specifies shader core properties.
928 #[derive(Clone, Copy, Debug)]
929 pub struct ShaderCoreProperties {}
930 
931 impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
932     #[inline]
from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self933     fn from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
934         Self {}
935     }
936 }
937