1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 use std::error; 11 use std::fmt; 12 13 macro_rules! features { 14 { 15 $($member:ident => { 16 doc: $doc:expr, 17 ffi_name: $ffi_field:ident, 18 ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+], 19 requires_features: [$($requires_feature:ident),*], 20 conflicts_features: [$($conflicts_feature:ident),*], 21 required_by_extensions: [$($required_by_extension:ident),*], 22 },)* 23 } => { 24 /// Represents all the features that are available on a physical device or enabled on 25 /// a logical device. 26 /// 27 /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan 28 /// implementations. 29 /// 30 /// # Example 31 /// 32 /// ``` 33 /// use vulkano::device::Features; 34 /// # let physical_device: vulkano::device::physical::PhysicalDevice = return; 35 /// let minimal_features = Features { 36 /// geometry_shader: true, 37 /// .. Features::none() 38 /// }; 39 /// 40 /// let optimal_features = vulkano::device::Features { 41 /// geometry_shader: true, 42 /// tessellation_shader: true, 43 /// .. Features::none() 44 /// }; 45 /// 46 /// if !physical_device.supported_features().is_superset_of(&minimal_features) { 47 /// panic!("The physical device is not good enough for this application."); 48 /// } 49 /// 50 /// assert!(optimal_features.is_superset_of(&minimal_features)); 51 /// let features_to_request = optimal_features.intersection(physical_device.supported_features()); 52 /// ``` 53 /// 54 #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] 55 #[allow(missing_docs)] 56 pub struct Features { 57 $( 58 #[doc = $doc] 59 pub $member: bool, 60 )* 61 } 62 63 impl Features { 64 /// Checks enabled features against the device version, device extensions and each other. 65 pub(super) fn check_requirements( 66 &self, 67 supported: &Features, 68 api_version: 69 crate::Version, 70 extensions: &crate::device::DeviceExtensions, 71 ) -> Result<(), crate::device::features::FeatureRestrictionError> { 72 $( 73 if self.$member { 74 if !supported.$member { 75 return Err(crate::device::features::FeatureRestrictionError { 76 feature: stringify!($member), 77 restriction: crate::device::features::FeatureRestriction::NotSupported, 78 }); 79 } 80 81 $( 82 if !self.$requires_feature { 83 return Err(crate::device::features::FeatureRestrictionError { 84 feature: stringify!($member), 85 restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)), 86 }); 87 } 88 )* 89 90 $( 91 if self.$conflicts_feature { 92 return Err(crate::device::features::FeatureRestrictionError { 93 feature: stringify!($member), 94 restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)), 95 }); 96 } 97 )* 98 } else { 99 $( 100 if extensions.$required_by_extension { 101 return Err(crate::device::features::FeatureRestrictionError { 102 feature: stringify!($member), 103 restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)), 104 }); 105 } 106 )* 107 } 108 )* 109 Ok(()) 110 } 111 112 /// Builds a `Features` object with all values to false. 113 pub const fn none() -> Features { 114 Features { 115 $($member: false,)* 116 } 117 } 118 119 /// Builds a `Features` object with all values to true. 120 /// 121 /// > **Note**: This function is used for testing purposes, and is probably useless in 122 /// > a real code. 123 pub const fn all() -> Features { 124 Features { 125 $($member: true,)* 126 } 127 } 128 129 /// Returns true if `self` is a superset of the parameter. 130 /// 131 /// That is, for each feature of the parameter that is true, the corresponding value 132 /// in self is true as well. 133 pub fn is_superset_of(&self, other: &Features) -> bool { 134 $((self.$member == true || other.$member == false))&&+ 135 } 136 137 /// Builds a `Features` that is the intersection of `self` and another `Features` 138 /// object. 139 /// 140 /// The result's field will be true if it is also true in both `self` and `other`. 141 pub fn intersection(&self, other: &Features) -> Features { 142 Features { 143 $($member: self.$member && other.$member,)* 144 } 145 } 146 147 /// Builds a `Features` that is the difference of another `Features` object from `self`. 148 /// 149 /// The result's field will be true if it is true in `self` but not `other`. 150 pub fn difference(&self, other: &Features) -> Features { 151 Features { 152 $($member: self.$member && !other.$member,)* 153 } 154 } 155 } 156 157 impl FeaturesFfi { 158 pub(crate) fn write(&mut self, features: &Features) { 159 $( 160 std::array::IntoIter::new([ 161 $(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+ 162 ]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32); 163 )* 164 } 165 } 166 167 impl From<&FeaturesFfi> for Features { 168 fn from(features_ffi: &FeaturesFfi) -> Self { 169 Features { 170 $( 171 $member: std::array::IntoIter::new([ 172 $(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+ 173 ]).flatten().next().unwrap_or(0) != 0, 174 )* 175 } 176 } 177 } 178 }; 179 } 180 181 pub use crate::autogen::Features; 182 pub(crate) use features; 183 184 /// An error that can happen when enabling a feature on a device. 185 #[derive(Clone, Copy, Debug)] 186 pub struct FeatureRestrictionError { 187 /// The feature in question. 188 pub feature: &'static str, 189 /// The restriction that was not met. 190 pub restriction: FeatureRestriction, 191 } 192 193 impl error::Error for FeatureRestrictionError {} 194 195 impl fmt::Display for FeatureRestrictionError { 196 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>197 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 198 write!( 199 fmt, 200 "a restriction for the feature {} was not met: {}", 201 self.feature, self.restriction, 202 ) 203 } 204 } 205 206 #[derive(Clone, Copy, Debug)] 207 pub enum FeatureRestriction { 208 /// Not supported by the physical device. 209 NotSupported, 210 /// Requires a feature to be enabled. 211 RequiresFeature(&'static str), 212 /// Requires a feature to be disabled. 213 ConflictsFeature(&'static str), 214 /// An extension requires this feature to be enabled. 215 RequiredByExtension(&'static str), 216 } 217 218 impl fmt::Display for FeatureRestriction { 219 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>220 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 221 match *self { 222 FeatureRestriction::NotSupported => { 223 write!(fmt, "not supported by the physical device") 224 } 225 FeatureRestriction::RequiresFeature(feat) => { 226 write!(fmt, "requires feature {} to be enabled", feat) 227 } 228 FeatureRestriction::ConflictsFeature(feat) => { 229 write!(fmt, "requires feature {} to be disabled", feat) 230 } 231 FeatureRestriction::RequiredByExtension(ext) => { 232 write!(fmt, "required to be enabled by extension {}", ext) 233 } 234 } 235 } 236 } 237 238 macro_rules! features_ffi { 239 { 240 $api_version:ident, 241 $device_extensions:ident, 242 $instance_extensions:ident, 243 $($member:ident => { 244 ty: $ty:ident, 245 provided_by: [$($provided_by:expr),+], 246 conflicts: [$($conflicts:ident),*], 247 },)+ 248 } => { 249 #[derive(Default)] 250 pub(crate) struct FeaturesFfi { 251 features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>, 252 253 $( 254 $member: Option<ash::vk::$ty>, 255 )+ 256 } 257 258 impl FeaturesFfi { 259 pub(crate) fn make_chain( 260 &mut self, 261 $api_version: crate::Version, 262 $device_extensions: &DeviceExtensions, 263 $instance_extensions: &InstanceExtensions, 264 ) { 265 self.features_vulkan10 = Some(Default::default()); 266 let head = self.features_vulkan10.as_mut().unwrap(); 267 268 $( 269 if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) && 270 std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) { 271 self.$member = Some(Default::default()); 272 let member = self.$member.as_mut().unwrap(); 273 member.p_next = head.p_next; 274 head.p_next = member as *mut _ as _; 275 } 276 )+ 277 } 278 279 pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR { 280 self.features_vulkan10.as_ref().unwrap() 281 } 282 283 pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR { 284 self.features_vulkan10.as_mut().unwrap() 285 } 286 } 287 }; 288 } 289 290 pub(crate) use {crate::autogen::FeaturesFfi, features_ffi}; 291