From 6f3deceb8b53c1d679520ede85dd00be9e65913c Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 15 May 2021 22:04:55 +0200 Subject: [PATCH] Add support for instance and device versions, check version in vulkano-shaders (#1569) * Move physical device functions into their own module * Add method to FunctionPointers to query Vulkan api version * Store the versions of instances and devices, allow user to query * Check Vulkan version in vulkano-shaders, changelog * Small mistake in changelog --- CHANGELOG_VULKANO.md | 5 +- vulkano-shaders/src/codegen.rs | 30 + vulkano/src/device/extensions.rs | 27 +- vulkano/src/device/mod.rs | 16 + vulkano/src/instance/extensions.rs | 30 +- vulkano/src/instance/instance.rs | 916 +----------------------- vulkano/src/instance/layers.rs | 2 +- vulkano/src/instance/loader.rs | 59 +- vulkano/src/instance/mod.rs | 22 +- vulkano/src/instance/physical_device.rs | 891 +++++++++++++++++++++++ vulkano/src/lib.rs | 1 + vulkano/src/version.rs | 26 +- 12 files changed, 1064 insertions(+), 961 deletions(-) create mode 100644 vulkano/src/instance/physical_device.rs diff --git a/CHANGELOG_VULKANO.md b/CHANGELOG_VULKANO.md index 16c91f2d..ddd8498a 100644 --- a/CHANGELOG_VULKANO.md +++ b/CHANGELOG_VULKANO.md @@ -3,7 +3,10 @@ Please add new changes at the bottom, preceded by a hyphen -. Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**. --> - +- **Breaking** Vulkano-shaders now checks if the device supports the shader's SPIR-V version, when loading the shader. +- Added `DeviceExtensions::khr_spirv_1_4`, which allows SPIR-V 1.4 shaders in Vulkan versions below 1.2. +- Added `FunctionPointers::api_version` to query the highest supported instance version. +- Added `Instance::api_version` and `Device::api_version` to return the actual supported Vulkan version. These may differ between instance and device, and be lower than what `FunctionPointers::api_version` and `PhysicalDevice::api_version` return (currently never higher than 1.1, but this may change in the future). # Version 0.23.0 (2021-04-10) diff --git a/vulkano-shaders/src/codegen.rs b/vulkano-shaders/src/codegen.rs index c8d969d9..e7a20990 100644 --- a/vulkano-shaders/src/codegen.rs +++ b/vulkano-shaders/src/codegen.rs @@ -215,6 +215,33 @@ where // checking whether each required capability is enabled in the Vulkan device let mut cap_checks: Vec = vec![]; + match doc.version { + (1, 0) => {} + (1, 1) | (1, 2) | (1, 3) => { + cap_checks.push(quote! { + if device.api_version() < (Version { major: 1, minor: 1, patch: 0 }) { + panic!("Device API version 1.1 required"); + } + }); + } + (1, 4) => { + cap_checks.push(quote! { + if device.api_version() < (Version { major: 1, minor: 2, patch: 0 }) + && !device.loaded_extensions().khr_spirv_1_4 { + panic!("Device API version 1.2 or extension VK_KHR_spirv_1_4 required"); + } + }); + } + (1, 5) => { + cap_checks.push(quote! { + if device.api_version() < (Version { major: 1, minor: 2, patch: 0 }) { + panic!("Device API version 1.2 required"); + } + }); + } + _ => return Err(Error::UnsupportedSpirvVersion), + } + for i in doc.instructions.iter() { let dev_req = { match i { @@ -325,6 +352,8 @@ where use vulkano::pipeline::shader::SpecializationConstants as SpecConstsTrait; #[allow(unused_imports)] use vulkano::pipeline::shader::SpecializationMapEntry; + #[allow(unused_imports)] + use vulkano::Version; pub struct #struct_name { shader: ::std::sync::Arc<::vulkano::pipeline::shader::ShaderModule>, @@ -379,6 +408,7 @@ where #[derive(Debug)] pub enum Error { + UnsupportedSpirvVersion, IoError(IoError), ParseError(ParseError), } diff --git a/vulkano/src/device/extensions.rs b/vulkano/src/device/extensions.rs index d5456a05..c0219f99 100644 --- a/vulkano/src/device/extensions.rs +++ b/vulkano/src/device/extensions.rs @@ -128,23 +128,26 @@ device_extensions! { // https://vulkan.lunarg.com/doc/view/1.2.162.1/mac/1.2-extensions/vkspec.html#VUID-VkDeviceCreateInfo-pProperties-04451 khr_portability_subset, ], - khr_swapchain => b"VK_KHR_swapchain", - khr_display_swapchain => b"VK_KHR_display_swapchain", - khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge", - khr_maintenance1 => b"VK_KHR_maintenance1", - khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2", - khr_dedicated_allocation => b"VK_KHR_dedicated_allocation", - khr_incremental_present => b"VK_KHR_incremental_present", + + // List in order: khr, ext, then alphabetical khr_16bit_storage => b"VK_KHR_16bit_storage", khr_8bit_storage => b"VK_KHR_8bit_storage", - khr_storage_buffer_storage_class => b"VK_KHR_storage_buffer_storage_class", - ext_debug_utils => b"VK_EXT_debug_utils", - khr_multiview => b"VK_KHR_multiview", - ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive", + khr_dedicated_allocation => b"VK_KHR_dedicated_allocation", + khr_display_swapchain => b"VK_KHR_display_swapchain", khr_external_memory => b"VK_KHR_external_memory", khr_external_memory_fd => b"VK_KHR_external_memory_fd", - ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf", + khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2", + khr_incremental_present => b"VK_KHR_incremental_present", + khr_maintenance1 => b"VK_KHR_maintenance1", + khr_multiview => b"VK_KHR_multiview", khr_portability_subset => b"VK_KHR_portability_subset", + khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge", + khr_spirv_1_4 => b"VK_KHR_spirv_1_4", + khr_storage_buffer_storage_class => b"VK_KHR_storage_buffer_storage_class", + khr_swapchain => b"VK_KHR_swapchain", + ext_debug_utils => b"VK_EXT_debug_utils", + ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf", + ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive", } /// This helper type can only be instantiated inside this module. diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 76a6824f..0522f999 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -130,6 +130,7 @@ use crate::image::ImageFormatProperties; use crate::image::ImageTiling; use crate::image::ImageType; use crate::image::ImageUsage; +use crate::Version; use std::pin::Pin; /// Represents a Vulkan context. @@ -137,6 +138,11 @@ pub struct Device { instance: Arc, physical_device: usize, device: vk::Device, + + // The highest version that is supported for this device. + // This is the minimum of Instance::desired_version and PhysicalDevice::api_version. + api_version: Version, + vk: vk::DevicePointers, standard_pool: Mutex>, standard_descriptor_pool: Mutex>, @@ -187,6 +193,9 @@ impl Device { I: IntoIterator, f32)>, Ext: Into, { + let desired_version = phys.instance().desired_version; + let api_version = std::cmp::min(desired_version, phys.api_version()); + let queue_families = queue_families.into_iter(); if !phys.supported_features().superset_of(&requested_features) { @@ -329,6 +338,7 @@ impl Device { instance: phys.instance().clone(), physical_device: phys.index(), device: device, + api_version, vk: vk, standard_pool: Mutex::new(Weak::new()), standard_descriptor_pool: Mutex::new(Weak::new()), @@ -356,6 +366,12 @@ impl Device { Ok((device, output_queues)) } + /// Returns the Vulkan version supported by this `Device`. + #[inline] + pub fn api_version(&self) -> Version { + self.api_version + } + /// Grants access to the pointers to the Vulkan functions of the device. #[inline] pub fn pointers(&self) -> &vk::DevicePointers { diff --git a/vulkano/src/instance/extensions.rs b/vulkano/src/instance/extensions.rs index 73d4a895..9310e083 100644 --- a/vulkano/src/instance/extensions.rs +++ b/vulkano/src/instance/extensions.rs @@ -145,30 +145,32 @@ macro_rules! instance_extensions { instance_extensions! { InstanceExtensions, RawInstanceExtensions, - khr_surface => b"VK_KHR_surface", - khr_display => b"VK_KHR_display", - khr_xlib_surface => b"VK_KHR_xlib_surface", - khr_xcb_surface => b"VK_KHR_xcb_surface", - khr_wayland_surface => b"VK_KHR_wayland_surface", + + // List in order: khr, ext, then alphabetical khr_android_surface => b"VK_KHR_android_surface", - khr_win32_surface => b"VK_KHR_win32_surface", - ext_debug_utils => b"VK_EXT_debug_utils", - mvk_ios_surface => b"VK_MVK_ios_surface", - mvk_macos_surface => b"VK_MVK_macos_surface", - mvk_moltenvk => b"VK_MVK_moltenvk", // TODO: confirm that it's an instance extension - nn_vi_surface => b"VK_NN_vi_surface", - ext_swapchain_colorspace => b"VK_EXT_swapchain_colorspace", - khr_get_physical_device_properties2 => b"VK_KHR_get_physical_device_properties2", - khr_get_surface_capabilities2 => b"VK_KHR_get_surface_capabilities2", khr_device_group_creation => b"VK_KHR_device_group_creation", + khr_display => b"VK_KHR_display", khr_external_fence_capabilities => b"VK_KHR_external_fence_capabilities", khr_external_memory_capabilities => b"VK_KHR_external_memory_capabilities", khr_external_semaphore_capabilities => b"VK_KHR_external_semaphore_capabilities", khr_get_display_properties2 => b"VK_KHR_get_display_properties2", + khr_get_physical_device_properties2 => b"VK_KHR_get_physical_device_properties2", + khr_get_surface_capabilities2 => b"VK_KHR_get_surface_capabilities2", + khr_surface => b"VK_KHR_surface", + khr_wayland_surface => b"VK_KHR_wayland_surface", + khr_win32_surface => b"VK_KHR_win32_surface", + khr_xcb_surface => b"VK_KHR_xcb_surface", + khr_xlib_surface => b"VK_KHR_xlib_surface", ext_acquire_xlib_display => b"VK_EXT_acquire_xlib_display", ext_debug_report => b"VK_EXT_debug_report", + ext_debug_utils => b"VK_EXT_debug_utils", ext_direct_mode_display => b"VK_EXT_direct_mode_display", ext_display_surface_counter => b"VK_EXT_display_surface_counter", + ext_swapchain_colorspace => b"VK_EXT_swapchain_colorspace", + mvk_ios_surface => b"VK_MVK_ios_surface", + mvk_macos_surface => b"VK_MVK_macos_surface", + mvk_moltenvk => b"VK_MVK_moltenvk", // TODO: confirm that it's an instance extension + nn_vi_surface => b"VK_NN_vi_surface", } /// This helper type can only be instantiated inside this module. diff --git a/vulkano/src/instance/instance.rs b/vulkano/src/instance/instance.rs index 72603fb5..15a3912a 100644 --- a/vulkano/src/instance/instance.rs +++ b/vulkano/src/instance/instance.rs @@ -8,28 +8,24 @@ // according to those terms. use crate::check_errors; -use crate::features::{Features, FeaturesFfi}; -use crate::instance::limits::Limits; use crate::instance::loader; use crate::instance::loader::FunctionPointers; use crate::instance::loader::Loader; use crate::instance::loader::LoadingError; +use crate::instance::physical_device::{init_physical_devices, PhysicalDeviceInfos}; use crate::instance::{InstanceExtensions, RawInstanceExtensions}; -use crate::sync::PipelineStage; -use crate::version::Version; use crate::vk; use crate::Error; use crate::OomError; +use crate::Version; use crate::VulkanObject; use smallvec::SmallVec; use std::borrow::Cow; use std::error; -use std::ffi::CStr; use std::ffi::CString; use std::fmt; use std::hash::Hash; use std::hash::Hasher; -use std::mem; use std::mem::MaybeUninit; use std::ops::Deref; use std::ptr; @@ -94,7 +90,16 @@ use std::sync::Arc; pub struct Instance { instance: vk::Instance, //alloc: Option>, - physical_devices: Vec, + + // The desired API version for instances and devices created from it. + // TODO: allow the user to specify this on construction. + pub(crate) desired_version: Version, + + // The highest version that is supported for this instance. + // This is the minimum of Instance::desired_version and FunctionPointers::api_version. + api_version: Version, + + pub(super) physical_devices: Vec, vk: vk::InstancePointers, extensions: RawInstanceExtensions, layers: SmallVec<[CString; 16]>, @@ -208,6 +213,21 @@ impl Instance { None }; + // TODO: allow the user to specify this. + // Vulkan 1.0 will return VK_ERROR_INCOMPATIBLE_DRIVER on instance creation if this isn't + // 1.0, but higher versions never return this error, and thus will allow a desired version + // beyond what they support. The actual support on that particular instance/device is the + // minimum of desired and supported. + // In other words, it's impossible to use a Vulkan 1.1 or 1.2 device with a 1.0 instance, + // because instance creation with a higher desired_version will fail. But it is possible to + // use a 1.0 or 1.2 device with a 1.1 instance. + let desired_version = Version { + major: 1, + minor: 1, + patch: 0, + }; + let api_version = std::cmp::min(desired_version, function_pointers.api_version()?); + // Building the `vk::ApplicationInfo` if required. let app_infos = if let Some(app_infos) = app_infos { Some(vk::ApplicationInfo { @@ -235,12 +255,7 @@ impl Instance { .engine_version .map(|v| v.into_vulkan_version()) .unwrap_or(0), - apiVersion: Version { - major: 1, - minor: 1, - patch: 0, - } - .into_vulkan_version(), // TODO: + apiVersion: desired_version.into_vulkan_version(), // TODO: }) } else { None @@ -282,38 +297,18 @@ impl Instance { // Loading the function pointers of the newly-created instance. let vk = { - vk::InstancePointers::load(|name| unsafe { - mem::transmute(function_pointers.get_instance_proc_addr(instance, name.as_ptr())) + vk::InstancePointers::load(|name| { + function_pointers.get_instance_proc_addr(instance, name.as_ptr()) }) }; // Enumerating all physical devices. - let physical_devices: Vec = unsafe { - let mut num = 0; - check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, ptr::null_mut()))?; - - let mut devices = Vec::with_capacity(num as usize); - check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, devices.as_mut_ptr()))?; - devices.set_len(num as usize); - devices - }; - - let vk_khr_get_physical_device_properties2 = - CString::new(b"VK_KHR_get_physical_device_properties2".to_vec()).unwrap(); - - // Getting the properties of all physical devices. - // If possible, we use VK_KHR_get_physical_device_properties2. - let physical_devices = if extensions - .iter() - .any(|v| *v == vk_khr_get_physical_device_properties2) - { - Instance::init_physical_devices2(&vk, physical_devices, &extensions) - } else { - Instance::init_physical_devices(&vk, physical_devices) - }; + let physical_devices = init_physical_devices(instance, &vk, &extensions)?; Ok(Arc::new(Instance { instance, + api_version, + desired_version, //alloc: None, physical_devices, vk, @@ -323,145 +318,6 @@ impl Instance { })) } - /// Initialize all physical devices - fn init_physical_devices( - vk: &vk::InstancePointers, - physical_devices: Vec, - ) -> Vec { - let mut output = Vec::with_capacity(physical_devices.len()); - - for device in physical_devices.into_iter() { - let properties: vk::PhysicalDeviceProperties = unsafe { - let mut output = MaybeUninit::uninit(); - vk.GetPhysicalDeviceProperties(device, output.as_mut_ptr()); - output.assume_init() - }; - - let queue_families = unsafe { - let mut num = 0; - vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, ptr::null_mut()); - - let mut families = Vec::with_capacity(num as usize); - vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, families.as_mut_ptr()); - families.set_len(num as usize); - families - }; - - let memory: vk::PhysicalDeviceMemoryProperties = unsafe { - let mut output = MaybeUninit::uninit(); - vk.GetPhysicalDeviceMemoryProperties(device, output.as_mut_ptr()); - output.assume_init() - }; - - let available_features: vk::PhysicalDeviceFeatures = unsafe { - let mut output = MaybeUninit::uninit(); - vk.GetPhysicalDeviceFeatures(device, output.as_mut_ptr()); - output.assume_init() - }; - - output.push(PhysicalDeviceInfos { - device, - properties, - extended_properties: PhysicalDeviceExtendedProperties::empty(), - memory, - queue_families, - available_features: Features::from(available_features), - }); - } - output - } - - /// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2 - /// TODO: Query extension-specific physical device properties, once a new instance extension is supported. - fn init_physical_devices2( - vk: &vk::InstancePointers, - physical_devices: Vec, - extensions: &RawInstanceExtensions, - ) -> Vec { - let mut output = Vec::with_capacity(physical_devices.len()); - - for device in physical_devices.into_iter() { - let mut extended_properties = PhysicalDeviceExtendedProperties::empty(); - - let properties: vk::PhysicalDeviceProperties = unsafe { - let mut subgroup_properties = vk::PhysicalDeviceSubgroupProperties { - sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES, - pNext: ptr::null_mut(), - subgroupSize: 0, - supportedStages: 0, - supportedOperations: 0, - quadOperationsInAllStages: 0, - }; - - let mut output = vk::PhysicalDeviceProperties2KHR { - sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, - pNext: &mut subgroup_properties, - properties: mem::zeroed(), - }; - - vk.GetPhysicalDeviceProperties2KHR(device, &mut output); - - extended_properties = PhysicalDeviceExtendedProperties { - subgroup_size: Some(subgroup_properties.subgroupSize), - - ..extended_properties - }; - - output.properties - }; - - let queue_families = unsafe { - let mut num = 0; - vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, ptr::null_mut()); - - let mut families = (0..num) - .map(|_| vk::QueueFamilyProperties2KHR { - sType: vk::STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR, - pNext: ptr::null_mut(), - queueFamilyProperties: mem::zeroed(), - }) - .collect::>(); - - vk.GetPhysicalDeviceQueueFamilyProperties2KHR( - device, - &mut num, - families.as_mut_ptr(), - ); - families - .into_iter() - .map(|family| family.queueFamilyProperties) - .collect() - }; - - let memory: vk::PhysicalDeviceMemoryProperties = unsafe { - let mut output = vk::PhysicalDeviceMemoryProperties2KHR { - sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR, - pNext: ptr::null_mut(), - memoryProperties: mem::zeroed(), - }; - vk.GetPhysicalDeviceMemoryProperties2KHR(device, &mut output); - output.memoryProperties - }; - - let available_features: Features = unsafe { - let mut output = FeaturesFfi::new(); - let ptr = FeaturesFfi::mut_base_ptr(&mut output) as *mut _; - vk.GetPhysicalDeviceFeatures2KHR(device, ptr); - Features::from(&output.main) - }; - - output.push(PhysicalDeviceInfos { - device, - properties, - extended_properties, - memory, - queue_families, - available_features, - }); - } - output - } - /*/// Same as `new`, but provides an allocator that will be used by the Vulkan library whenever /// it needs to allocate memory on the host. /// @@ -470,6 +326,12 @@ impl Instance { unimplemented!() }*/ + /// Returns the Vulkan version supported by this `Instance`. + #[inline] + pub fn api_version(&self) -> Version { + self.api_version + } + /// Grants access to the Vulkan functions of the instance. #[inline] pub fn pointers(&self) -> &vk::InstancePointers { @@ -724,706 +586,6 @@ impl From for InstanceCreationError { } } -struct PhysicalDeviceInfos { - device: vk::PhysicalDevice, - properties: vk::PhysicalDeviceProperties, - extended_properties: PhysicalDeviceExtendedProperties, - queue_families: Vec, - memory: vk::PhysicalDeviceMemoryProperties, - available_features: Features, -} - -/// Represents additional information related to Physical Devices fetched from -/// `vkGetPhysicalDeviceProperties` call. Certain features available only when -/// appropriate `Instance` extensions enabled. The core extension required -/// for this features is `InstanceExtensions::khr_get_physical_device_properties2` -/// -/// TODO: Only a small subset of available properties(https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties2.html) is implemented at this moment. -pub struct PhysicalDeviceExtendedProperties { - subgroup_size: Option, -} - -impl PhysicalDeviceExtendedProperties { - fn empty() -> Self { - Self { - subgroup_size: None, - } - } - - /// The default number of invocations in each subgroup - /// - /// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html for details - #[inline] - pub fn subgroup_size(&self) -> &Option { - &self.subgroup_size - } -} - -/// Represents one of the available devices on this machine. -/// -/// This struct simply contains a pointer to an instance and a number representing the physical -/// device. You are therefore encouraged to pass this around by value instead of by reference. -/// -/// # Example -/// -/// ```no_run -/// # use vulkano::instance::Instance; -/// # use vulkano::instance::InstanceExtensions; -/// use vulkano::instance::PhysicalDevice; -/// -/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); -/// for physical_device in PhysicalDevice::enumerate(&instance) { -/// print_infos(physical_device); -/// } -/// -/// fn print_infos(dev: PhysicalDevice) { -/// println!("Name: {}", dev.name()); -/// } -/// ``` -#[derive(Debug, Copy, Clone)] -pub struct PhysicalDevice<'a> { - instance: &'a Arc, - device: usize, -} - -impl<'a> PhysicalDevice<'a> { - /// Returns an iterator that enumerates the physical devices available. - /// - /// # Example - /// - /// ```no_run - /// # use vulkano::instance::Instance; - /// # use vulkano::instance::InstanceExtensions; - /// use vulkano::instance::PhysicalDevice; - /// - /// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); - /// for physical_device in PhysicalDevice::enumerate(&instance) { - /// println!("Available device: {}", physical_device.name()); - /// } - /// ``` - #[inline] - pub fn enumerate(instance: &'a Arc) -> PhysicalDevicesIter<'a> { - PhysicalDevicesIter { - instance, - current_id: 0, - } - } - - /// Returns a physical device from its index. Returns `None` if out of range. - /// - /// Indices range from 0 to the number of devices. - /// - /// # Example - /// - /// ```no_run - /// use vulkano::instance::Instance; - /// use vulkano::instance::InstanceExtensions; - /// use vulkano::instance::PhysicalDevice; - /// - /// let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); - /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap(); - /// ``` - #[inline] - pub fn from_index(instance: &'a Arc, index: usize) -> Option> { - if instance.physical_devices.len() > index { - Some(PhysicalDevice { - instance, - device: index, - }) - } else { - None - } - } - - /// Returns the instance corresponding to this physical device. - /// - /// # Example - /// - /// ```no_run - /// use vulkano::instance::PhysicalDevice; - /// - /// fn do_something(physical_device: PhysicalDevice) { - /// let _loaded_extensions = physical_device.instance().loaded_extensions(); - /// // ... - /// } - /// ``` - #[inline] - pub fn instance(&self) -> &'a Arc { - &self.instance - } - - /// Returns the index of the physical device in the physical devices list. - /// - /// This index never changes and can be used later to retrieve a `PhysicalDevice` from an - /// instance and an index. - #[inline] - pub fn index(&self) -> usize { - self.device - } - - /// Returns the human-readable name of the device. - #[inline] - pub fn name(&self) -> &str { - unsafe { - let val = &self.infos().properties.deviceName; - let val = CStr::from_ptr(val.as_ptr()); - val.to_str() - .expect("physical device name contained non-UTF8 characters") - } - } - - /// Returns the type of the device. - /// - /// # Example - /// - /// ```no_run - /// # use vulkano::instance::Instance; - /// # use vulkano::instance::InstanceExtensions; - /// use vulkano::instance::PhysicalDevice; - /// - /// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); - /// for physical_device in PhysicalDevice::enumerate(&instance) { - /// println!("Available device: {} (type: {:?})", - /// physical_device.name(), physical_device.ty()); - /// } - /// ``` - #[inline] - pub fn ty(&self) -> PhysicalDeviceType { - match self.instance.physical_devices[self.device] - .properties - .deviceType - { - vk::PHYSICAL_DEVICE_TYPE_OTHER => PhysicalDeviceType::Other, - vk::PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => PhysicalDeviceType::IntegratedGpu, - vk::PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => PhysicalDeviceType::DiscreteGpu, - vk::PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU => PhysicalDeviceType::VirtualGpu, - vk::PHYSICAL_DEVICE_TYPE_CPU => PhysicalDeviceType::Cpu, - _ => panic!("Unrecognized Vulkan device type"), - } - } - - /// Returns the version of Vulkan supported by this device. - #[inline] - pub fn api_version(&self) -> Version { - let val = self.infos().properties.apiVersion; - Version::from_vulkan_version(val) - } - - /// Returns the Vulkan features that are supported by this physical device. - #[inline] - pub fn supported_features(&self) -> &'a Features { - &self.infos().available_features - } - - /// Builds an iterator that enumerates all the queue families on this physical device. - #[inline] - pub fn queue_families(&self) -> QueueFamiliesIter<'a> { - QueueFamiliesIter { - physical_device: *self, - current_id: 0, - } - } - - /// Returns the queue family with the given index, or `None` if out of range. - #[inline] - pub fn queue_family_by_id(&self, id: u32) -> Option> { - if (id as usize) < self.infos().queue_families.len() { - Some(QueueFamily { - physical_device: *self, - id, - }) - } else { - None - } - } - - /// Builds an iterator that enumerates all the memory types on this physical device. - #[inline] - pub fn memory_types(&self) -> MemoryTypesIter<'a> { - MemoryTypesIter { - physical_device: *self, - current_id: 0, - } - } - - /// Returns the memory type with the given index, or `None` if out of range. - #[inline] - pub fn memory_type_by_id(&self, id: u32) -> Option> { - if id < self.infos().memory.memoryTypeCount { - Some(MemoryType { - physical_device: *self, - id, - }) - } else { - None - } - } - - /// Builds an iterator that enumerates all the memory heaps on this physical device. - #[inline] - pub fn memory_heaps(&self) -> MemoryHeapsIter<'a> { - MemoryHeapsIter { - physical_device: *self, - current_id: 0, - } - } - - /// Returns the memory heap with the given index, or `None` if out of range. - #[inline] - pub fn memory_heap_by_id(&self, id: u32) -> Option> { - if id < self.infos().memory.memoryHeapCount { - Some(MemoryHeap { - physical_device: *self, - id, - }) - } else { - None - } - } - - /// Gives access to the limits of the physical device. - /// - /// This function should be zero-cost in release mode. It only exists to not pollute the - /// namespace of `PhysicalDevice` with all the limits-related getters. - #[inline] - pub fn limits(&self) -> Limits<'a> { - Limits::from_vk_limits(&self.infos().properties.limits) - } - - /// Returns an opaque number representing the version of the driver of this device. - /// - /// The meaning of this number is implementation-specific. It can be used in bug reports, for - /// example. - #[inline] - pub fn driver_version(&self) -> u32 { - self.infos().properties.driverVersion - } - - /// Returns the PCI ID of the device. - #[inline] - pub fn pci_device_id(&self) -> u32 { - self.infos().properties.deviceID - } - - /// Returns the PCI ID of the vendor. - #[inline] - pub fn pci_vendor_id(&self) -> u32 { - self.infos().properties.vendorID - } - - /// Returns a unique identifier for the device. - /// - /// Can be stored in a configuration file, so that you can retrieve the device again the next - /// time the program is run. - #[inline] - pub fn uuid(&self) -> &[u8; 16] { - // must be equal to vk::UUID_SIZE - &self.infos().properties.pipelineCacheUUID - } - - #[inline] - pub fn extended_properties(&self) -> &PhysicalDeviceExtendedProperties { - &self.infos().extended_properties - } - - // Internal function to make it easier to get the infos of this device. - #[inline] - fn infos(&self) -> &'a PhysicalDeviceInfos { - &self.instance.physical_devices[self.device] - } -} - -unsafe impl<'a> VulkanObject for PhysicalDevice<'a> { - type Object = vk::PhysicalDevice; - - const TYPE: vk::ObjectType = vk::OBJECT_TYPE_PHYSICAL_DEVICE; - - #[inline] - fn internal_object(&self) -> vk::PhysicalDevice { - self.infos().device - } -} - -/// Iterator for all the physical devices available on hardware. -#[derive(Debug, Clone)] -pub struct PhysicalDevicesIter<'a> { - instance: &'a Arc, - current_id: usize, -} - -impl<'a> Iterator for PhysicalDevicesIter<'a> { - type Item = PhysicalDevice<'a>; - - #[inline] - fn next(&mut self) -> Option> { - if self.current_id >= self.instance.physical_devices.len() { - return None; - } - - let dev = PhysicalDevice { - instance: self.instance, - device: self.current_id, - }; - - self.current_id += 1; - Some(dev) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.instance.physical_devices.len() - self.current_id; - (len, Some(len)) - } -} - -impl<'a> ExactSizeIterator for PhysicalDevicesIter<'a> {} - -/// Type of a physical device. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[repr(u32)] -pub enum PhysicalDeviceType { - /// The device is an integrated GPU. - IntegratedGpu = 1, - /// The device is a discrete GPU. - DiscreteGpu = 2, - /// The device is a virtual GPU. - VirtualGpu = 3, - /// The device is a CPU. - Cpu = 4, - /// The device is something else. - Other = 0, -} - -/// Represents a queue family in a physical device. -/// -/// A queue family is group of one or multiple queues. All queues of one family have the same -/// characteristics. -#[derive(Debug, Copy, Clone)] -pub struct QueueFamily<'a> { - physical_device: PhysicalDevice<'a>, - id: u32, -} - -impl<'a> QueueFamily<'a> { - /// Returns the physical device associated to this queue family. - #[inline] - pub fn physical_device(&self) -> PhysicalDevice<'a> { - self.physical_device - } - - /// Returns the identifier of this queue family within the physical device. - #[inline] - pub fn id(&self) -> u32 { - self.id - } - - /// Returns the number of queues that belong to this family. - /// - /// Guaranteed to be at least 1 (or else that family wouldn't exist). - #[inline] - pub fn queues_count(&self) -> usize { - self.physical_device.infos().queue_families[self.id as usize].queueCount as usize - } - - /// If timestamps are supported, returns the number of bits supported by timestamp operations. - /// The returned value will be in the range 36..64. - /// If timestamps are not supported, returns None. - #[inline] - pub fn timestamp_valid_bits(&self) -> Option { - let value = - self.physical_device.infos().queue_families[self.id as usize].timestampValidBits; - if value == 0 { - None - } else { - Some(value) - } - } - - /// Returns the minimum granularity supported for image transfers in terms - /// of `[width, height, depth]` - #[inline] - pub fn min_image_transfer_granularity(&self) -> [u32; 3] { - let ref granularity = self.physical_device.infos().queue_families[self.id as usize] - .minImageTransferGranularity; - [granularity.width, granularity.height, granularity.depth] - } - - /// Returns `true` if queues of this family can execute graphics operations. - #[inline] - pub fn supports_graphics(&self) -> bool { - (self.flags() & vk::QUEUE_GRAPHICS_BIT) != 0 - } - - /// Returns `true` if queues of this family can execute compute operations. - #[inline] - pub fn supports_compute(&self) -> bool { - (self.flags() & vk::QUEUE_COMPUTE_BIT) != 0 - } - - /// Returns `true` if queues of this family can execute transfer operations. - /// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform - /// > transfer operations, graphics & compute queues only optionally indicate support for tranfers. - /// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT - /// > to indicate a special relationship with the DMA module and more efficient transfers. - #[inline] - pub fn explicitly_supports_transfers(&self) -> bool { - (self.flags() & vk::QUEUE_TRANSFER_BIT) != 0 - } - - /// Returns `true` if queues of this family can execute sparse resources binding operations. - #[inline] - pub fn supports_sparse_binding(&self) -> bool { - (self.flags() & vk::QUEUE_SPARSE_BINDING_BIT) != 0 - } - - /// Returns `true` if the queues of this family support a particular pipeline stage. - #[inline] - pub fn supports_stage(&self, stage: PipelineStage) -> bool { - (self.flags() & stage.required_queue_flags()) != 0 - } - - /// Internal utility function that returns the flags of this queue family. - #[inline] - fn flags(&self) -> u32 { - self.physical_device.infos().queue_families[self.id as usize].queueFlags - } -} - -impl<'a> PartialEq for QueueFamily<'a> { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - && self.physical_device.internal_object() == other.physical_device.internal_object() - } -} - -impl<'a> Eq for QueueFamily<'a> {} - -/// Iterator for all the queue families available on a physical device. -#[derive(Debug, Clone)] -pub struct QueueFamiliesIter<'a> { - physical_device: PhysicalDevice<'a>, - current_id: u32, -} - -impl<'a> Iterator for QueueFamiliesIter<'a> { - type Item = QueueFamily<'a>; - - #[inline] - fn next(&mut self) -> Option> { - if self.current_id as usize >= self.physical_device.infos().queue_families.len() { - return None; - } - - let dev = QueueFamily { - physical_device: self.physical_device, - id: self.current_id, - }; - - self.current_id += 1; - Some(dev) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.physical_device.infos().queue_families.len(); - let remain = len - self.current_id as usize; - (remain, Some(remain)) - } -} - -impl<'a> ExactSizeIterator for QueueFamiliesIter<'a> {} - -/// Represents a memory type in a physical device. -#[derive(Debug, Copy, Clone)] -pub struct MemoryType<'a> { - physical_device: PhysicalDevice<'a>, - id: u32, -} - -impl<'a> MemoryType<'a> { - /// Returns the physical device associated to this memory type. - #[inline] - pub fn physical_device(&self) -> PhysicalDevice<'a> { - self.physical_device - } - - /// Returns the identifier of this memory type within the physical device. - #[inline] - pub fn id(&self) -> u32 { - self.id - } - - /// Returns the heap that corresponds to this memory type. - #[inline] - pub fn heap(&self) -> MemoryHeap<'a> { - let heap_id = self.physical_device.infos().memory.memoryTypes[self.id as usize].heapIndex; - MemoryHeap { - physical_device: self.physical_device, - id: heap_id, - } - } - - /// Returns true if the memory type is located on the device, which means that it's the most - /// efficient for GPU accesses. - #[inline] - pub fn is_device_local(&self) -> bool { - (self.flags() & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 - } - - /// Returns true if the memory type can be accessed by the host. - #[inline] - pub fn is_host_visible(&self) -> bool { - (self.flags() & vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0 - } - - /// Returns true if modifications made by the host or the GPU on this memory type are - /// instantaneously visible to the other party. False means that changes have to be flushed. - /// - /// You don't need to worry about this, as this library handles that for you. - #[inline] - pub fn is_host_coherent(&self) -> bool { - (self.flags() & vk::MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0 - } - - /// Returns true if memory of this memory type is cached by the host. Host memory accesses to - /// cached memory is faster than for uncached memory. However you are not guaranteed that it - /// is coherent. - #[inline] - pub fn is_host_cached(&self) -> bool { - (self.flags() & vk::MEMORY_PROPERTY_HOST_CACHED_BIT) != 0 - } - - /// Returns true if allocations made to this memory type is lazy. - /// - /// This means that no actual allocation is performed. Instead memory is automatically - /// allocated by the Vulkan implementation. - /// - /// Memory of this type can only be used on images created with a certain flag. Memory of this - /// type is never host-visible. - #[inline] - pub fn is_lazily_allocated(&self) -> bool { - (self.flags() & vk::MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0 - } - - /// Internal utility function that returns the flags of this queue family. - #[inline] - fn flags(&self) -> u32 { - self.physical_device.infos().memory.memoryTypes[self.id as usize].propertyFlags - } -} - -/// Iterator for all the memory types available on a physical device. -#[derive(Debug, Clone)] -pub struct MemoryTypesIter<'a> { - physical_device: PhysicalDevice<'a>, - current_id: u32, -} - -impl<'a> Iterator for MemoryTypesIter<'a> { - type Item = MemoryType<'a>; - - #[inline] - fn next(&mut self) -> Option> { - if self.current_id >= self.physical_device.infos().memory.memoryTypeCount { - return None; - } - - let dev = MemoryType { - physical_device: self.physical_device, - id: self.current_id, - }; - - self.current_id += 1; - Some(dev) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.physical_device.infos().memory.memoryTypeCount; - let remain = (len - self.current_id) as usize; - (remain, Some(remain)) - } -} - -impl<'a> ExactSizeIterator for MemoryTypesIter<'a> {} - -/// Represents a memory heap in a physical device. -#[derive(Debug, Copy, Clone)] -pub struct MemoryHeap<'a> { - physical_device: PhysicalDevice<'a>, - id: u32, -} - -impl<'a> MemoryHeap<'a> { - /// Returns the physical device associated to this memory heap. - #[inline] - pub fn physical_device(&self) -> PhysicalDevice<'a> { - self.physical_device - } - - /// Returns the identifier of this memory heap within the physical device. - #[inline] - pub fn id(&self) -> u32 { - self.id - } - - /// Returns the size in bytes on this heap. - #[inline] - pub fn size(&self) -> usize { - self.physical_device.infos().memory.memoryHeaps[self.id as usize].size as usize - } - - /// Returns true if the heap is local to the GPU. - #[inline] - pub fn is_device_local(&self) -> bool { - let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags; - (flags & vk::MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0 - } - - /// Returns true if the heap is multi-instance enabled, that is allocation from such - /// heap will replicate to each physical-device's instance of heap. - #[inline] - pub fn is_multi_instance(&self) -> bool { - let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags; - (flags & vk::MEMORY_HEAP_MULTI_INSTANCE_BIT) != 0 - } -} - -/// Iterator for all the memory heaps available on a physical device. -#[derive(Debug, Clone)] -pub struct MemoryHeapsIter<'a> { - physical_device: PhysicalDevice<'a>, - current_id: u32, -} - -impl<'a> Iterator for MemoryHeapsIter<'a> { - type Item = MemoryHeap<'a>; - - #[inline] - fn next(&mut self) -> Option> { - if self.current_id >= self.physical_device.infos().memory.memoryHeapCount { - return None; - } - - let dev = MemoryHeap { - physical_device: self.physical_device, - id: self.current_id, - }; - - self.current_id += 1; - Some(dev) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.physical_device.infos().memory.memoryHeapCount; - let remain = (len - self.current_id) as usize; - (remain, Some(remain)) - } -} - -impl<'a> ExactSizeIterator for MemoryHeapsIter<'a> {} - #[cfg(test)] mod tests { use crate::instance; diff --git a/vulkano/src/instance/layers.rs b/vulkano/src/instance/layers.rs index fef8da3a..6ec19794 100644 --- a/vulkano/src/instance/layers.rs +++ b/vulkano/src/instance/layers.rs @@ -16,10 +16,10 @@ use std::vec::IntoIter; use crate::check_errors; use crate::instance::loader; use crate::instance::loader::LoadingError; -use crate::version::Version; use crate::vk; use crate::Error; use crate::OomError; +use crate::Version; /// Queries the list of layers that are available when creating an instance. /// diff --git a/vulkano/src/instance/loader.rs b/vulkano/src/instance/loader.rs index 9959076c..e0adff0d 100644 --- a/vulkano/src/instance/loader.rs +++ b/vulkano/src/instance/loader.rs @@ -21,11 +21,15 @@ //! By default vulkano will use the `auto_loader()` function, which tries to automatically load //! a Vulkan implementation from the system. +use crate::check_errors; use crate::vk; +use crate::OomError; use crate::SafeDeref; +use crate::Version; use lazy_static::lazy_static; use shared_library; use std::error; +use std::ffi::CStr; use std::fmt; use std::mem; use std::ops::Deref; @@ -38,11 +42,7 @@ pub unsafe trait Loader { /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same. /// /// The returned function must stay valid for as long as `self` is alive. - fn get_instance_proc_addr( - &self, - instance: vk::Instance, - name: *const c_char, - ) -> extern "system" fn() -> (); + fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void; } unsafe impl Loader for T @@ -51,11 +51,7 @@ where T::Target: Loader, { #[inline] - fn get_instance_proc_addr( - &self, - instance: vk::Instance, - name: *const c_char, - ) -> extern "system" fn() -> () { + fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void { (**self).get_instance_proc_addr(instance, name) } } @@ -63,10 +59,8 @@ where /// Implementation of `Loader` that loads Vulkan from a dynamic library. pub struct DynamicLibraryLoader { vk_lib: shared_library::dynamic_library::DynamicLibrary, - get_proc_addr: extern "system" fn( - instance: vk::Instance, - pName: *const c_char, - ) -> extern "system" fn() -> (), + get_proc_addr: + extern "system" fn(instance: vk::Instance, pName: *const c_char) -> *const c_void, } impl DynamicLibraryLoader { @@ -100,11 +94,7 @@ impl DynamicLibraryLoader { unsafe impl Loader for DynamicLibraryLoader { #[inline] - fn get_instance_proc_addr( - &self, - instance: vk::Instance, - name: *const c_char, - ) -> extern "system" fn() -> () { + fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void { (self.get_proc_addr)(instance, name) } } @@ -137,13 +127,42 @@ impl FunctionPointers { &self.entry_points } + /// Returns the highest Vulkan version that is supported for instances. + pub fn api_version(&self) -> Result + where + L: Loader, + { + // Per the Vulkan spec: + // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a + // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion + // to determine the version of Vulkan. + unsafe { + let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0"); + let func = self.get_instance_proc_addr(0, name.as_ptr()); + + if func.is_null() { + Ok(Version { + major: 1, + minor: 0, + patch: 0, + }) + } else { + type Pfn = extern "system" fn(pApiVersion: *mut u32) -> vk::Result; + let func: Pfn = mem::transmute(func); + let mut api_version = 0; + check_errors(func(&mut api_version))?; + Ok(Version::from_vulkan_version(api_version)) + } + } + } + /// Calls `get_instance_proc_addr` on the underlying loader. #[inline] pub fn get_instance_proc_addr( &self, instance: vk::Instance, name: *const c_char, - ) -> extern "system" fn() -> () + ) -> *const c_void where L: Loader, { diff --git a/vulkano/src/instance/mod.rs b/vulkano/src/instance/mod.rs index 96ca99b6..ae062f10 100644 --- a/vulkano/src/instance/mod.rs +++ b/vulkano/src/instance/mod.rs @@ -111,27 +111,27 @@ pub use self::extensions::RawInstanceExtensions; pub use self::instance::ApplicationInfo; pub use self::instance::Instance; pub use self::instance::InstanceCreationError; -pub use self::instance::MemoryHeap; -pub use self::instance::MemoryHeapsIter; -pub use self::instance::MemoryType; -pub use self::instance::MemoryTypesIter; -pub use self::instance::PhysicalDevice; -pub use self::instance::PhysicalDeviceType; -pub use self::instance::PhysicalDevicesIter; -pub use self::instance::QueueFamiliesIter; -pub use self::instance::QueueFamily; pub use self::layers::layers_list; pub use self::layers::LayerProperties; pub use self::layers::LayersIterator; pub use self::layers::LayersListError; pub use self::limits::Limits; pub use self::loader::LoadingError; +pub use self::physical_device::MemoryHeap; +pub use self::physical_device::MemoryHeapsIter; +pub use self::physical_device::MemoryType; +pub use self::physical_device::MemoryTypesIter; +pub use self::physical_device::PhysicalDevice; +pub use self::physical_device::PhysicalDeviceType; +pub use self::physical_device::PhysicalDevicesIter; +pub use self::physical_device::QueueFamiliesIter; +pub use self::physical_device::QueueFamily; pub use crate::version::Version; pub mod debug; -pub mod loader; - mod extensions; mod instance; mod layers; mod limits; +pub mod loader; +mod physical_device; diff --git a/vulkano/src/instance/physical_device.rs b/vulkano/src/instance/physical_device.rs new file mode 100644 index 00000000..2698ad40 --- /dev/null +++ b/vulkano/src/instance/physical_device.rs @@ -0,0 +1,891 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use crate::check_errors; +use crate::features::{Features, FeaturesFfi}; +use crate::instance::limits::Limits; +use crate::instance::{Instance, InstanceCreationError, RawInstanceExtensions}; +use crate::sync::PipelineStage; +use crate::vk; +use crate::Version; +use crate::VulkanObject; +use std::ffi::CStr; +use std::ffi::CString; +use std::hash::Hash; +use std::mem; +use std::mem::MaybeUninit; +use std::ptr; +use std::sync::Arc; + +pub(super) fn init_physical_devices( + instance: vk::Instance, + vk: &vk::InstancePointers, + extensions: &RawInstanceExtensions, +) -> Result, InstanceCreationError> { + let physical_devices: Vec = unsafe { + let mut num = 0; + check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, ptr::null_mut()))?; + + let mut devices = Vec::with_capacity(num as usize); + check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, devices.as_mut_ptr()))?; + devices.set_len(num as usize); + devices + }; + + let vk_khr_get_physical_device_properties2 = + CString::new(b"VK_KHR_get_physical_device_properties2".to_vec()).unwrap(); + + // Getting the properties of all physical devices. + // If possible, we use VK_KHR_get_physical_device_properties2. + let physical_devices = if extensions + .iter() + .any(|v| *v == vk_khr_get_physical_device_properties2) + { + init_physical_devices_inner2(&vk, physical_devices, &extensions) + } else { + init_physical_devices_inner(&vk, physical_devices) + }; + + Ok(physical_devices) +} + +/// Initialize all physical devices +fn init_physical_devices_inner( + vk: &vk::InstancePointers, + physical_devices: Vec, +) -> Vec { + let mut output = Vec::with_capacity(physical_devices.len()); + + for device in physical_devices.into_iter() { + let properties: vk::PhysicalDeviceProperties = unsafe { + let mut output = MaybeUninit::uninit(); + vk.GetPhysicalDeviceProperties(device, output.as_mut_ptr()); + output.assume_init() + }; + + let queue_families = unsafe { + let mut num = 0; + vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, ptr::null_mut()); + + let mut families = Vec::with_capacity(num as usize); + vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, families.as_mut_ptr()); + families.set_len(num as usize); + families + }; + + let memory: vk::PhysicalDeviceMemoryProperties = unsafe { + let mut output = MaybeUninit::uninit(); + vk.GetPhysicalDeviceMemoryProperties(device, output.as_mut_ptr()); + output.assume_init() + }; + + let available_features: vk::PhysicalDeviceFeatures = unsafe { + let mut output = MaybeUninit::uninit(); + vk.GetPhysicalDeviceFeatures(device, output.as_mut_ptr()); + output.assume_init() + }; + + output.push(PhysicalDeviceInfos { + device, + properties, + extended_properties: PhysicalDeviceExtendedProperties::empty(), + memory, + queue_families, + available_features: Features::from(available_features), + }); + } + output +} + +/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2 +/// TODO: Query extension-specific physical device properties, once a new instance extension is supported. +fn init_physical_devices_inner2( + vk: &vk::InstancePointers, + physical_devices: Vec, + extensions: &RawInstanceExtensions, +) -> Vec { + let mut output = Vec::with_capacity(physical_devices.len()); + + for device in physical_devices.into_iter() { + let mut extended_properties = PhysicalDeviceExtendedProperties::empty(); + + let properties: vk::PhysicalDeviceProperties = unsafe { + let mut subgroup_properties = vk::PhysicalDeviceSubgroupProperties { + sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES, + pNext: ptr::null_mut(), + subgroupSize: 0, + supportedStages: 0, + supportedOperations: 0, + quadOperationsInAllStages: 0, + }; + + let mut output = vk::PhysicalDeviceProperties2KHR { + sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, + pNext: &mut subgroup_properties, + properties: mem::zeroed(), + }; + + vk.GetPhysicalDeviceProperties2KHR(device, &mut output); + + extended_properties = PhysicalDeviceExtendedProperties { + subgroup_size: Some(subgroup_properties.subgroupSize), + + ..extended_properties + }; + + output.properties + }; + + let queue_families = unsafe { + let mut num = 0; + vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, ptr::null_mut()); + + let mut families = (0..num) + .map(|_| vk::QueueFamilyProperties2KHR { + sType: vk::STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR, + pNext: ptr::null_mut(), + queueFamilyProperties: mem::zeroed(), + }) + .collect::>(); + + vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, families.as_mut_ptr()); + families + .into_iter() + .map(|family| family.queueFamilyProperties) + .collect() + }; + + let memory: vk::PhysicalDeviceMemoryProperties = unsafe { + let mut output = vk::PhysicalDeviceMemoryProperties2KHR { + sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR, + pNext: ptr::null_mut(), + memoryProperties: mem::zeroed(), + }; + vk.GetPhysicalDeviceMemoryProperties2KHR(device, &mut output); + output.memoryProperties + }; + + let available_features: Features = unsafe { + let mut output = FeaturesFfi::new(); + let ptr = FeaturesFfi::mut_base_ptr(&mut output) as *mut _; + vk.GetPhysicalDeviceFeatures2KHR(device, ptr); + Features::from(&output.main) + }; + + output.push(PhysicalDeviceInfos { + device, + properties, + extended_properties, + memory, + queue_families, + available_features, + }); + } + output +} + +pub(super) struct PhysicalDeviceInfos { + device: vk::PhysicalDevice, + properties: vk::PhysicalDeviceProperties, + extended_properties: PhysicalDeviceExtendedProperties, + queue_families: Vec, + memory: vk::PhysicalDeviceMemoryProperties, + available_features: Features, +} + +/// Represents additional information related to Physical Devices fetched from +/// `vkGetPhysicalDeviceProperties` call. Certain features available only when +/// appropriate `Instance` extensions enabled. The core extension required +/// for this features is `InstanceExtensions::khr_get_physical_device_properties2` +/// +/// TODO: Only a small subset of available properties(https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties2.html) is implemented at this moment. +pub struct PhysicalDeviceExtendedProperties { + subgroup_size: Option, +} + +impl PhysicalDeviceExtendedProperties { + pub(super) fn empty() -> Self { + Self { + subgroup_size: None, + } + } + + /// The default number of invocations in each subgroup + /// + /// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html for details + #[inline] + pub fn subgroup_size(&self) -> &Option { + &self.subgroup_size + } +} + +/// Represents one of the available devices on this machine. +/// +/// This struct simply contains a pointer to an instance and a number representing the physical +/// device. You are therefore encouraged to pass this around by value instead of by reference. +/// +/// # Example +/// +/// ```no_run +/// # use vulkano::instance::Instance; +/// # use vulkano::instance::InstanceExtensions; +/// use vulkano::instance::PhysicalDevice; +/// +/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); +/// for physical_device in PhysicalDevice::enumerate(&instance) { +/// print_infos(physical_device); +/// } +/// +/// fn print_infos(dev: PhysicalDevice) { +/// println!("Name: {}", dev.name()); +/// } +/// ``` +#[derive(Debug, Copy, Clone)] +pub struct PhysicalDevice<'a> { + instance: &'a Arc, + device: usize, +} + +impl<'a> PhysicalDevice<'a> { + /// Returns an iterator that enumerates the physical devices available. + /// + /// # Example + /// + /// ```no_run + /// # use vulkano::instance::Instance; + /// # use vulkano::instance::InstanceExtensions; + /// use vulkano::instance::PhysicalDevice; + /// + /// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); + /// for physical_device in PhysicalDevice::enumerate(&instance) { + /// println!("Available device: {}", physical_device.name()); + /// } + /// ``` + #[inline] + pub fn enumerate(instance: &'a Arc) -> PhysicalDevicesIter<'a> { + PhysicalDevicesIter { + instance, + current_id: 0, + } + } + + /// Returns a physical device from its index. Returns `None` if out of range. + /// + /// Indices range from 0 to the number of devices. + /// + /// # Example + /// + /// ```no_run + /// use vulkano::instance::Instance; + /// use vulkano::instance::InstanceExtensions; + /// use vulkano::instance::PhysicalDevice; + /// + /// let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); + /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap(); + /// ``` + #[inline] + pub fn from_index(instance: &'a Arc, index: usize) -> Option> { + if instance.physical_devices.len() > index { + Some(PhysicalDevice { + instance, + device: index, + }) + } else { + None + } + } + + /// Returns the instance corresponding to this physical device. + /// + /// # Example + /// + /// ```no_run + /// use vulkano::instance::PhysicalDevice; + /// + /// fn do_something(physical_device: PhysicalDevice) { + /// let _loaded_extensions = physical_device.instance().loaded_extensions(); + /// // ... + /// } + /// ``` + #[inline] + pub fn instance(&self) -> &'a Arc { + &self.instance + } + + /// Returns the index of the physical device in the physical devices list. + /// + /// This index never changes and can be used later to retrieve a `PhysicalDevice` from an + /// instance and an index. + #[inline] + pub fn index(&self) -> usize { + self.device + } + + /// Returns the human-readable name of the device. + #[inline] + pub fn name(&self) -> &str { + unsafe { + let val = &self.infos().properties.deviceName; + let val = CStr::from_ptr(val.as_ptr()); + val.to_str() + .expect("physical device name contained non-UTF8 characters") + } + } + + /// Returns the type of the device. + /// + /// # Example + /// + /// ```no_run + /// # use vulkano::instance::Instance; + /// # use vulkano::instance::InstanceExtensions; + /// use vulkano::instance::PhysicalDevice; + /// + /// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap(); + /// for physical_device in PhysicalDevice::enumerate(&instance) { + /// println!("Available device: {} (type: {:?})", + /// physical_device.name(), physical_device.ty()); + /// } + /// ``` + #[inline] + pub fn ty(&self) -> PhysicalDeviceType { + match self.instance.physical_devices[self.device] + .properties + .deviceType + { + vk::PHYSICAL_DEVICE_TYPE_OTHER => PhysicalDeviceType::Other, + vk::PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => PhysicalDeviceType::IntegratedGpu, + vk::PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => PhysicalDeviceType::DiscreteGpu, + vk::PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU => PhysicalDeviceType::VirtualGpu, + vk::PHYSICAL_DEVICE_TYPE_CPU => PhysicalDeviceType::Cpu, + _ => panic!("Unrecognized Vulkan device type"), + } + } + + /// Returns the version of Vulkan supported by this device. + #[inline] + pub fn api_version(&self) -> Version { + let val = self.infos().properties.apiVersion; + Version::from_vulkan_version(val) + } + + /// Returns the Vulkan features that are supported by this physical device. + #[inline] + pub fn supported_features(&self) -> &'a Features { + &self.infos().available_features + } + + /// Builds an iterator that enumerates all the queue families on this physical device. + #[inline] + pub fn queue_families(&self) -> QueueFamiliesIter<'a> { + QueueFamiliesIter { + physical_device: *self, + current_id: 0, + } + } + + /// Returns the queue family with the given index, or `None` if out of range. + #[inline] + pub fn queue_family_by_id(&self, id: u32) -> Option> { + if (id as usize) < self.infos().queue_families.len() { + Some(QueueFamily { + physical_device: *self, + id, + }) + } else { + None + } + } + + /// Builds an iterator that enumerates all the memory types on this physical device. + #[inline] + pub fn memory_types(&self) -> MemoryTypesIter<'a> { + MemoryTypesIter { + physical_device: *self, + current_id: 0, + } + } + + /// Returns the memory type with the given index, or `None` if out of range. + #[inline] + pub fn memory_type_by_id(&self, id: u32) -> Option> { + if id < self.infos().memory.memoryTypeCount { + Some(MemoryType { + physical_device: *self, + id, + }) + } else { + None + } + } + + /// Builds an iterator that enumerates all the memory heaps on this physical device. + #[inline] + pub fn memory_heaps(&self) -> MemoryHeapsIter<'a> { + MemoryHeapsIter { + physical_device: *self, + current_id: 0, + } + } + + /// Returns the memory heap with the given index, or `None` if out of range. + #[inline] + pub fn memory_heap_by_id(&self, id: u32) -> Option> { + if id < self.infos().memory.memoryHeapCount { + Some(MemoryHeap { + physical_device: *self, + id, + }) + } else { + None + } + } + + /// Gives access to the limits of the physical device. + /// + /// This function should be zero-cost in release mode. It only exists to not pollute the + /// namespace of `PhysicalDevice` with all the limits-related getters. + #[inline] + pub fn limits(&self) -> Limits<'a> { + Limits::from_vk_limits(&self.infos().properties.limits) + } + + /// Returns an opaque number representing the version of the driver of this device. + /// + /// The meaning of this number is implementation-specific. It can be used in bug reports, for + /// example. + #[inline] + pub fn driver_version(&self) -> u32 { + self.infos().properties.driverVersion + } + + /// Returns the PCI ID of the device. + #[inline] + pub fn pci_device_id(&self) -> u32 { + self.infos().properties.deviceID + } + + /// Returns the PCI ID of the vendor. + #[inline] + pub fn pci_vendor_id(&self) -> u32 { + self.infos().properties.vendorID + } + + /// Returns a unique identifier for the device. + /// + /// Can be stored in a configuration file, so that you can retrieve the device again the next + /// time the program is run. + #[inline] + pub fn uuid(&self) -> &[u8; 16] { + // must be equal to vk::UUID_SIZE + &self.infos().properties.pipelineCacheUUID + } + + #[inline] + pub fn extended_properties(&self) -> &PhysicalDeviceExtendedProperties { + &self.infos().extended_properties + } + + // Internal function to make it easier to get the infos of this device. + #[inline] + fn infos(&self) -> &'a PhysicalDeviceInfos { + &self.instance.physical_devices[self.device] + } +} + +unsafe impl<'a> VulkanObject for PhysicalDevice<'a> { + type Object = vk::PhysicalDevice; + + const TYPE: vk::ObjectType = vk::OBJECT_TYPE_PHYSICAL_DEVICE; + + #[inline] + fn internal_object(&self) -> vk::PhysicalDevice { + self.infos().device + } +} + +/// Iterator for all the physical devices available on hardware. +#[derive(Debug, Clone)] +pub struct PhysicalDevicesIter<'a> { + instance: &'a Arc, + current_id: usize, +} + +impl<'a> Iterator for PhysicalDevicesIter<'a> { + type Item = PhysicalDevice<'a>; + + #[inline] + fn next(&mut self) -> Option> { + if self.current_id >= self.instance.physical_devices.len() { + return None; + } + + let dev = PhysicalDevice { + instance: self.instance, + device: self.current_id, + }; + + self.current_id += 1; + Some(dev) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.instance.physical_devices.len() - self.current_id; + (len, Some(len)) + } +} + +impl<'a> ExactSizeIterator for PhysicalDevicesIter<'a> {} + +/// Type of a physical device. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[repr(u32)] +pub enum PhysicalDeviceType { + /// The device is an integrated GPU. + IntegratedGpu = 1, + /// The device is a discrete GPU. + DiscreteGpu = 2, + /// The device is a virtual GPU. + VirtualGpu = 3, + /// The device is a CPU. + Cpu = 4, + /// The device is something else. + Other = 0, +} + +/// Represents a queue family in a physical device. +/// +/// A queue family is group of one or multiple queues. All queues of one family have the same +/// characteristics. +#[derive(Debug, Copy, Clone)] +pub struct QueueFamily<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, +} + +impl<'a> QueueFamily<'a> { + /// Returns the physical device associated to this queue family. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this queue family within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the number of queues that belong to this family. + /// + /// Guaranteed to be at least 1 (or else that family wouldn't exist). + #[inline] + pub fn queues_count(&self) -> usize { + self.physical_device.infos().queue_families[self.id as usize].queueCount as usize + } + + /// If timestamps are supported, returns the number of bits supported by timestamp operations. + /// The returned value will be in the range 36..64. + /// If timestamps are not supported, returns None. + #[inline] + pub fn timestamp_valid_bits(&self) -> Option { + let value = + self.physical_device.infos().queue_families[self.id as usize].timestampValidBits; + if value == 0 { + None + } else { + Some(value) + } + } + + /// Returns the minimum granularity supported for image transfers in terms + /// of `[width, height, depth]` + #[inline] + pub fn min_image_transfer_granularity(&self) -> [u32; 3] { + let ref granularity = self.physical_device.infos().queue_families[self.id as usize] + .minImageTransferGranularity; + [granularity.width, granularity.height, granularity.depth] + } + + /// Returns `true` if queues of this family can execute graphics operations. + #[inline] + pub fn supports_graphics(&self) -> bool { + (self.flags() & vk::QUEUE_GRAPHICS_BIT) != 0 + } + + /// Returns `true` if queues of this family can execute compute operations. + #[inline] + pub fn supports_compute(&self) -> bool { + (self.flags() & vk::QUEUE_COMPUTE_BIT) != 0 + } + + /// Returns `true` if queues of this family can execute transfer operations. + /// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform + /// > transfer operations, graphics & compute queues only optionally indicate support for tranfers. + /// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT + /// > to indicate a special relationship with the DMA module and more efficient transfers. + #[inline] + pub fn explicitly_supports_transfers(&self) -> bool { + (self.flags() & vk::QUEUE_TRANSFER_BIT) != 0 + } + + /// Returns `true` if queues of this family can execute sparse resources binding operations. + #[inline] + pub fn supports_sparse_binding(&self) -> bool { + (self.flags() & vk::QUEUE_SPARSE_BINDING_BIT) != 0 + } + + /// Returns `true` if the queues of this family support a particular pipeline stage. + #[inline] + pub fn supports_stage(&self, stage: PipelineStage) -> bool { + (self.flags() & stage.required_queue_flags()) != 0 + } + + /// Internal utility function that returns the flags of this queue family. + #[inline] + fn flags(&self) -> u32 { + self.physical_device.infos().queue_families[self.id as usize].queueFlags + } +} + +impl<'a> PartialEq for QueueFamily<'a> { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.physical_device.internal_object() == other.physical_device.internal_object() + } +} + +impl<'a> Eq for QueueFamily<'a> {} + +/// Iterator for all the queue families available on a physical device. +#[derive(Debug, Clone)] +pub struct QueueFamiliesIter<'a> { + physical_device: PhysicalDevice<'a>, + current_id: u32, +} + +impl<'a> Iterator for QueueFamiliesIter<'a> { + type Item = QueueFamily<'a>; + + #[inline] + fn next(&mut self) -> Option> { + if self.current_id as usize >= self.physical_device.infos().queue_families.len() { + return None; + } + + let dev = QueueFamily { + physical_device: self.physical_device, + id: self.current_id, + }; + + self.current_id += 1; + Some(dev) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.physical_device.infos().queue_families.len(); + let remain = len - self.current_id as usize; + (remain, Some(remain)) + } +} + +impl<'a> ExactSizeIterator for QueueFamiliesIter<'a> {} + +/// Represents a memory type in a physical device. +#[derive(Debug, Copy, Clone)] +pub struct MemoryType<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, +} + +impl<'a> MemoryType<'a> { + /// Returns the physical device associated to this memory type. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this memory type within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the heap that corresponds to this memory type. + #[inline] + pub fn heap(&self) -> MemoryHeap<'a> { + let heap_id = self.physical_device.infos().memory.memoryTypes[self.id as usize].heapIndex; + MemoryHeap { + physical_device: self.physical_device, + id: heap_id, + } + } + + /// Returns true if the memory type is located on the device, which means that it's the most + /// efficient for GPU accesses. + #[inline] + pub fn is_device_local(&self) -> bool { + (self.flags() & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 + } + + /// Returns true if the memory type can be accessed by the host. + #[inline] + pub fn is_host_visible(&self) -> bool { + (self.flags() & vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0 + } + + /// Returns true if modifications made by the host or the GPU on this memory type are + /// instantaneously visible to the other party. False means that changes have to be flushed. + /// + /// You don't need to worry about this, as this library handles that for you. + #[inline] + pub fn is_host_coherent(&self) -> bool { + (self.flags() & vk::MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0 + } + + /// Returns true if memory of this memory type is cached by the host. Host memory accesses to + /// cached memory is faster than for uncached memory. However you are not guaranteed that it + /// is coherent. + #[inline] + pub fn is_host_cached(&self) -> bool { + (self.flags() & vk::MEMORY_PROPERTY_HOST_CACHED_BIT) != 0 + } + + /// Returns true if allocations made to this memory type is lazy. + /// + /// This means that no actual allocation is performed. Instead memory is automatically + /// allocated by the Vulkan implementation. + /// + /// Memory of this type can only be used on images created with a certain flag. Memory of this + /// type is never host-visible. + #[inline] + pub fn is_lazily_allocated(&self) -> bool { + (self.flags() & vk::MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0 + } + + /// Internal utility function that returns the flags of this queue family. + #[inline] + fn flags(&self) -> u32 { + self.physical_device.infos().memory.memoryTypes[self.id as usize].propertyFlags + } +} + +/// Iterator for all the memory types available on a physical device. +#[derive(Debug, Clone)] +pub struct MemoryTypesIter<'a> { + physical_device: PhysicalDevice<'a>, + current_id: u32, +} + +impl<'a> Iterator for MemoryTypesIter<'a> { + type Item = MemoryType<'a>; + + #[inline] + fn next(&mut self) -> Option> { + if self.current_id >= self.physical_device.infos().memory.memoryTypeCount { + return None; + } + + let dev = MemoryType { + physical_device: self.physical_device, + id: self.current_id, + }; + + self.current_id += 1; + Some(dev) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.physical_device.infos().memory.memoryTypeCount; + let remain = (len - self.current_id) as usize; + (remain, Some(remain)) + } +} + +impl<'a> ExactSizeIterator for MemoryTypesIter<'a> {} + +/// Represents a memory heap in a physical device. +#[derive(Debug, Copy, Clone)] +pub struct MemoryHeap<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, +} + +impl<'a> MemoryHeap<'a> { + /// Returns the physical device associated to this memory heap. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this memory heap within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the size in bytes on this heap. + #[inline] + pub fn size(&self) -> usize { + self.physical_device.infos().memory.memoryHeaps[self.id as usize].size as usize + } + + /// Returns true if the heap is local to the GPU. + #[inline] + pub fn is_device_local(&self) -> bool { + let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags; + (flags & vk::MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0 + } + + /// Returns true if the heap is multi-instance enabled, that is allocation from such + /// heap will replicate to each physical-device's instance of heap. + #[inline] + pub fn is_multi_instance(&self) -> bool { + let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags; + (flags & vk::MEMORY_HEAP_MULTI_INSTANCE_BIT) != 0 + } +} + +/// Iterator for all the memory heaps available on a physical device. +#[derive(Debug, Clone)] +pub struct MemoryHeapsIter<'a> { + physical_device: PhysicalDevice<'a>, + current_id: u32, +} + +impl<'a> Iterator for MemoryHeapsIter<'a> { + type Item = MemoryHeap<'a>; + + #[inline] + fn next(&mut self) -> Option> { + if self.current_id >= self.physical_device.infos().memory.memoryHeapCount { + return None; + } + + let dev = MemoryHeap { + physical_device: self.physical_device, + id: self.current_id, + }; + + self.current_id += 1; + Some(dev) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.physical_device.infos().memory.memoryHeapCount; + let remain = (len - self.current_id) as usize; + (remain, Some(remain)) + } +} + +impl<'a> ExactSizeIterator for MemoryHeapsIter<'a> {} diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index 8169f320..459b479a 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -70,6 +70,7 @@ use std::fmt; use std::ops::Deref; use std::sync::Arc; use std::sync::MutexGuard; +pub use version::Version; #[macro_use] mod tests; diff --git a/vulkano/src/version.rs b/vulkano/src/version.rs index 710e166e..fbf08dff 100644 --- a/vulkano/src/version.rs +++ b/vulkano/src/version.rs @@ -9,11 +9,10 @@ // The `Version` object is reexported from the `instance` module. -use std::cmp::Ordering; use std::fmt; /// Represents an API version of Vulkan. -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { /// Major version number. pub major: u16, @@ -35,29 +34,6 @@ impl fmt::Display for Version { } } -impl PartialOrd for Version { - #[inline] - fn partial_cmp(&self, other: &Version) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Version { - fn cmp(&self, other: &Version) -> Ordering { - match self.major.cmp(&other.major) { - Ordering::Equal => (), - o => return o, - }; - - match self.minor.cmp(&other.minor) { - Ordering::Equal => (), - o => return o, - }; - - self.patch.cmp(&other.patch) - } -} - impl Version { /// Turns a version number given by Vulkan into a `Version` struct. #[inline]