• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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