<NME> phd.rs
<BEF> //! Functions to get physical device information

use std::ffi::{CStr, CString};

use ash::{prelude::VkResult, vk};

use super::{version::Version, DriverInfo, PhdInfo, UnsupportedProperty};

impl super::PhysicalDevice {
    /// # Safety:
    ///
    /// The physical device must belong to the specified instance.
    pub(super) unsafe fn from_phd(
        instance: &super::Instance,
        phd: vk::PhysicalDevice,
    ) -> VkResult<Option<super::PhysicalDevice>> {
        let instance = instance.clone();

        let extensions = unsafe { instance.handle().enumerate_device_extension_properties(phd) }?;
        let extensions = extensions
            .iter()
            .map(|extension| {
                // SAFETY: Vulkan guarantees the device name is valid UTF-8 with a null terminator.
                unsafe { CStr::from_ptr(&extension.extension_name as *const _) }.to_owned()
            })
            .collect::<Vec<_>>();

        if let Some(info) =
            unsafe { PhdInfo::from_phd(instance.handle(), instance.api_version(), phd, &extensions) }
        {
            Ok(Some(Self {
                phd,
                info,
                extensions,
                instance,
            }))
        } else {
            Ok(None)
        }
    }
}

impl super::PhdInfo {
    /// Returns [`None`] if the physical device does not support Vulkan 1.1
    ///
    /// # Panics
    ///
    /// - If the instance version is not at least Vulkan 1.1
    ///
    /// # Safety
    ///
    /// - The instance version must be the same version the instance was created with.
    /// - The physical device must belong to the specified instance.
    unsafe fn from_phd(
        instance: &ash::Instance,
        instance_version: Version,
        phd: vk::PhysicalDevice,
        supported_extensions: &[CString],
    ) -> Option<Self> {
        assert!(instance_version >= Version::VERSION_1_1);

        let properties = unsafe { instance.get_physical_device_properties(phd) };
        let features = unsafe { instance.get_physical_device_features(phd) };

        // Pick the lower of the instance version and device version to get the actual version of Vulkan that
        // can be used with the device.
        let api_version = Version::from_raw(u32::min(properties.api_version, instance_version.to_raw()));

        if api_version < Version::VERSION_1_1 {
            // Device does not support Vulkan 1.1, so ignore it.
            return None;
        }

        // SAFETY: Vulkan guarantees the device name is valid UTF-8 with a null terminator.
        let name = unsafe { CStr::from_ptr(&properties.device_name as *const _) }
            .to_str()
            .unwrap()
            .to_string();

        // Maintenance3
        //
        // SAFETY: Maintenance3 extension is supported since Vulkan 1.1
        let maintenance_3 = unsafe {
            let mut maintenance_3 = vk::PhysicalDeviceMaintenance3Properties::default();
            let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut maintenance_3);
            instance.get_physical_device_properties2(phd, &mut props);
            maintenance_3
        };

        // IDProperties
        //
        // SAFETY: Core in Vulkan 1.1
        let id = unsafe {
            let mut id = vk::PhysicalDeviceIDProperties::default();
            let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut id);
            instance.get_physical_device_properties2(phd, &mut props);
            id
        };

        // Vulkan 1.1 features
        //
        // Confusingly these types were not added until Vulkan 1.2
        let (properties_1_1, features_1_1) = {
            if api_version >= Version::VERSION_1_2 {
                unsafe {
                    let mut properties_1_1 = vk::PhysicalDeviceVulkan11Properties::default();
                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_1);
                    instance.get_physical_device_properties2(phd, &mut props);

                    let mut features_1_1 = vk::PhysicalDeviceVulkan11Features::default();
                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_1);
                    instance.get_physical_device_features2(phd, &mut features);

                    (Some(properties_1_1), Some(features_1_1))
                }
            } else {
                (None, None)
            }
        };

        // Vulkan 1.2
        let (properties_1_2, features_1_2) = {
            if api_version >= Version::VERSION_1_2 {
                // SAFETY: The physical device supports Vulkan 1.2
                unsafe {
                    let mut properties_1_2 = vk::PhysicalDeviceVulkan12Properties::default();
                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_2);
                    instance.get_physical_device_properties2(phd, &mut props);

                    let mut features_1_2 = vk::PhysicalDeviceVulkan12Features::default();
                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_2);
                    instance.get_physical_device_features2(phd, &mut features);

                    (Some(properties_1_2), Some(features_1_2))
                }
            } else {
                (None, None)
            }
        };

        // Vulkan 1.3
        let (properties_1_3, features_1_3) = {
            if api_version >= Version::VERSION_1_3 {
                // SAFETY: The physical device supports Vulkan 1.3
                unsafe {
                    let mut properties_1_2 = vk::PhysicalDeviceVulkan13Properties::default();
                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_2);
                    instance.get_physical_device_properties2(phd, &mut props);

                    let mut features_1_2 = vk::PhysicalDeviceVulkan13Features::default();
                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_2);
                    instance.get_physical_device_features2(phd, &mut features);

                    (Some(properties_1_2), Some(features_1_2))
                }
            } else {
                (None, None)
            }
        };

        // VK_EXT_physical_device_drm
        let properties_drm = if supported_extensions
            .iter()
            .any(|name| name.as_c_str() == vk::ExtPhysicalDeviceDrmFn::name())
        {
            // SAFETY: The caller has garunteed the physical device supports VK_EXT_physical_device_drm
            unsafe {
                let mut properties_drm = vk::PhysicalDeviceDrmPropertiesEXT::default();
                let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_drm);
                instance.get_physical_device_properties2(phd, &mut props);
                Some(properties_drm)
            }
        } else {
            None
        };

        // VK_KHR_driver_properties or Vulkan 1.2
        let driver = if api_version >= Version::VERSION_1_2 {
            // Copy the data from the Vulkan 1.2 properties into the extension struct for data creation.
            let properties = vk::PhysicalDeviceDriverProperties {
                driver_id: properties_1_2.unwrap().driver_id,
                driver_name: properties_1_2.unwrap().driver_name,
                driver_info: properties_1_2.unwrap().driver_info,
                conformance_version: properties_1_2.unwrap().conformance_version,
                ..Default::default()
            };

            Some(unsafe { DriverInfo::from_driver_properties(properties) })
        } else if supported_extensions
            .iter()
            .any(|name| name.as_c_str() == vk::KhrDriverPropertiesFn::name())
        {
            // SAFETY: VK_KHR_driver_properties is supported
            unsafe {
                let mut driver_props = vk::PhysicalDeviceDriverProperties::default();
                let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut driver_props);
                instance.get_physical_device_properties2(phd, &mut props);

                Some(DriverInfo::from_driver_properties(driver_props))
            }
        } else {
            None
        };

        Some(Self {
            api_version,
            name,
            properties,
            features,
            maintenance_3,
            id,
            properties_1_1,
            features_1_1,
            properties_1_2,
            features_1_2,
            properties_1_3,
            features_1_3,
            properties_drm,
            driver,
        })
    }
}

impl super::DriverInfo {
    unsafe fn from_driver_properties(properties: vk::PhysicalDeviceDriverProperties) -> DriverInfo {
        // SAFETY: Vulkan guarantees the driver name is valid UTF-8 with a null terminator.
        let name = unsafe { CStr::from_ptr(&properties.driver_name as *const _) }
            .to_str()
        self.properties_drm
            .ok_or(UnsupportedProperty::Extensions(EXTENSIONS))
    }
}

impl super::DriverInfo {
    fn from_driver_properties(properties: vk::PhysicalDeviceDriverProperties) -> DriverInfo {
        // SAFETY: Vulkan guarantees the driver name is valid UTF-8 with a null terminator.
        let name = unsafe { CStr::from_ptr(&properties.driver_name as *const _) }
            .to_str()
            .unwrap()
            .to_string();

        // SAFETY: Vulkan guarantees the driver info is valid UTF-8 with a null terminator.
        let info = unsafe { CStr::from_ptr(&properties.driver_info as *const _) }
            .to_str()
            .unwrap()
            .to_string();

        DriverInfo {
            id: properties.driver_id,
            name,
            info,
            conformance: properties.conformance_version,
        }
    }
}

<MSG> vulkan: remove Vulkan1X features/properties from PhysicalDevice

The Vulkan1X types are not ideal for our level of abstraction nor too idomatic. Smithay intends to support higher versions of Vulkan like a superset of existing functionality. However the Vulkan1X types cannot be chained with their individual parts without validation errors. There is also the fact that these types are not available until Vulkan 1.2, and the Vulkan11 structures are actually provided in Vulkan 1.2, not Vulkan 1.1. Therefore for the sake of cleaning up the codebase, the Vulkan1X types now need to be obtained some other way if desired.

<DFF> @@ -60,7 +60,6 @@ impl super::PhdInfo {
         assert!(instance_version >= Version::VERSION_1_1);
 
         let properties = unsafe { instance.get_physical_device_properties(phd) };
-        let features = unsafe { instance.get_physical_device_features(phd) };
 
         // Pick the lower of the instance version and device version to get the actual version of Vulkan that
         // can be used with the device.
@@ -77,152 +76,58 @@ impl super::PhdInfo {
             .unwrap()
             .to_string();
 
-        // Maintenance3
-        //
-        // SAFETY: Maintenance3 extension is supported since Vulkan 1.1
-        let maintenance_3 = unsafe {
-            let mut maintenance_3 = vk::PhysicalDeviceMaintenance3Properties::default();
-            let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut maintenance_3);
-            instance.get_physical_device_properties2(phd, &mut props);
-            maintenance_3
+        // Initialize the type with the api_version.
+        let mut info = PhdInfo {
+            api_version,
+            name,
+            ..Default::default()
         };
 
-        // IDProperties
-        //
-        // SAFETY: Core in Vulkan 1.1
-        let id = unsafe {
-            let mut id = vk::PhysicalDeviceIDProperties::default();
-            let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut id);
-            instance.get_physical_device_properties2(phd, &mut props);
-            id
-        };
+        let mut properties = vk::PhysicalDeviceProperties2::builder();
 
-        // Vulkan 1.1 features
+        // Maintenance3 and IDProperties are both Core in Vulkan 1.1
         //
-        // Confusingly these types were not added until Vulkan 1.2
-        let (properties_1_1, features_1_1) = {
-            if api_version >= Version::VERSION_1_2 {
-                unsafe {
-                    let mut properties_1_1 = vk::PhysicalDeviceVulkan11Properties::default();
-                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_1);
-                    instance.get_physical_device_properties2(phd, &mut props);
-
-                    let mut features_1_1 = vk::PhysicalDeviceVulkan11Features::default();
-                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_1);
-                    instance.get_physical_device_features2(phd, &mut features);
-
-                    (Some(properties_1_1), Some(features_1_1))
-                }
-            } else {
-                (None, None)
-            }
-        };
-
-        // Vulkan 1.2
-        let (properties_1_2, features_1_2) = {
-            if api_version >= Version::VERSION_1_2 {
-                // SAFETY: The physical device supports Vulkan 1.2
-                unsafe {
-                    let mut properties_1_2 = vk::PhysicalDeviceVulkan12Properties::default();
-                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_2);
-                    instance.get_physical_device_properties2(phd, &mut props);
-
-                    let mut features_1_2 = vk::PhysicalDeviceVulkan12Features::default();
-                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_2);
-                    instance.get_physical_device_features2(phd, &mut features);
-
-                    (Some(properties_1_2), Some(features_1_2))
-                }
-            } else {
-                (None, None)
-            }
-        };
-
-        // Vulkan 1.3
-        let (properties_1_3, features_1_3) = {
-            if api_version >= Version::VERSION_1_3 {
-                // SAFETY: The physical device supports Vulkan 1.3
-                unsafe {
-                    let mut properties_1_2 = vk::PhysicalDeviceVulkan13Properties::default();
-                    let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_1_2);
-                    instance.get_physical_device_properties2(phd, &mut props);
-
-                    let mut features_1_2 = vk::PhysicalDeviceVulkan13Features::default();
-                    let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_2);
-                    instance.get_physical_device_features2(phd, &mut features);
-
-                    (Some(properties_1_2), Some(features_1_2))
-                }
-            } else {
-                (None, None)
-            }
-        };
+        // SAFETY: Maintenance3 extension is supported since Vulkan 1.1
+        properties = properties
+            .push_next(&mut info.maintenance_3)
+            .push_next(&mut info.id);
 
         // VK_EXT_physical_device_drm
-        let properties_drm = if supported_extensions
+        if supported_extensions
             .iter()
             .any(|name| name.as_c_str() == vk::ExtPhysicalDeviceDrmFn::name())
         {
             // SAFETY: The caller has garunteed the physical device supports VK_EXT_physical_device_drm
-            unsafe {
-                let mut properties_drm = vk::PhysicalDeviceDrmPropertiesEXT::default();
-                let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut properties_drm);
-                instance.get_physical_device_properties2(phd, &mut props);
-                Some(properties_drm)
-            }
-        } else {
-            None
-        };
+            let next = info
+                .properties_drm
+                .insert(vk::PhysicalDeviceDrmPropertiesEXT::default());
+            properties = properties.push_next(next);
+        }
 
         // VK_KHR_driver_properties or Vulkan 1.2
-        let driver = if api_version >= Version::VERSION_1_2 {
-            // Copy the data from the Vulkan 1.2 properties into the extension struct for data creation.
-            let properties = vk::PhysicalDeviceDriverProperties {
-                driver_id: properties_1_2.unwrap().driver_id,
-                driver_name: properties_1_2.unwrap().driver_name,
-                driver_info: properties_1_2.unwrap().driver_info,
-                conformance_version: properties_1_2.unwrap().conformance_version,
-                ..Default::default()
-            };
-
-            Some(unsafe { DriverInfo::from_driver_properties(properties) })
-        } else if supported_extensions
-            .iter()
-            .any(|name| name.as_c_str() == vk::KhrDriverPropertiesFn::name())
+        if api_version >= Version::VERSION_1_2
+            || supported_extensions
+                .iter()
+                .any(|name| name.as_c_str() == vk::KhrDriverPropertiesFn::name())
         {
             // SAFETY: VK_KHR_driver_properties is supported
-            unsafe {
-                let mut driver_props = vk::PhysicalDeviceDriverProperties::default();
-                let mut props = vk::PhysicalDeviceProperties2::builder().push_next(&mut driver_props);
-                instance.get_physical_device_properties2(phd, &mut props);
+            let next = info
+                .properties_driver
+                .insert(vk::PhysicalDeviceDriverProperties::default());
+            properties = properties.push_next(next);
+        }
 
-                Some(DriverInfo::from_driver_properties(driver_props))
-            }
-        } else {
-            None
-        };
+        unsafe { instance.get_physical_device_properties2(phd, &mut properties) };
 
-        Some(Self {
-            api_version,
-            name,
-            properties,
-            features,
-            maintenance_3,
-            id,
-            properties_1_1,
-            features_1_1,
-            properties_1_2,
-            features_1_2,
-            properties_1_3,
-            features_1_3,
-            properties_drm,
-            driver,
-        })
+        // Initialize the driver info
+        info.driver = info.properties_driver.map(DriverInfo::from_driver_properties);
+
+        Some(info)
     }
 }
 
 impl super::DriverInfo {
-    unsafe fn from_driver_properties(properties: vk::PhysicalDeviceDriverProperties) -> DriverInfo {
+    fn from_driver_properties(properties: vk::PhysicalDeviceDriverProperties) -> DriverInfo {
         // SAFETY: Vulkan guarantees the driver name is valid UTF-8 with a null terminator.
         let name = unsafe { CStr::from_ptr(&properties.driver_name as *const _) }
             .to_str()

vulkan: remove Vulkan1X features/properties from PhysicalDevice