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