aboutsummaryrefslogtreecommitdiff
path: root/src/device/features.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/device/features.rs')
-rw-r--r--src/device/features.rs290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/device/features.rs b/src/device/features.rs
new file mode 100644
index 0000000..1d83545
--- /dev/null
+++ b/src/device/features.rs
@@ -0,0 +1,290 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use std::error;
+use std::fmt;
+
+macro_rules! features {
+ {
+ $($member:ident => {
+ doc: $doc:expr,
+ ffi_name: $ffi_field:ident,
+ ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+],
+ requires_features: [$($requires_feature:ident),*],
+ conflicts_features: [$($conflicts_feature:ident),*],
+ required_by_extensions: [$($required_by_extension:ident),*],
+ },)*
+ } => {
+ /// Represents all the features that are available on a physical device or enabled on
+ /// a logical device.
+ ///
+ /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
+ /// implementations.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use vulkano::device::Features;
+ /// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
+ /// let minimal_features = Features {
+ /// geometry_shader: true,
+ /// .. Features::none()
+ /// };
+ ///
+ /// let optimal_features = vulkano::device::Features {
+ /// geometry_shader: true,
+ /// tessellation_shader: true,
+ /// .. Features::none()
+ /// };
+ ///
+ /// if !physical_device.supported_features().is_superset_of(&minimal_features) {
+ /// panic!("The physical device is not good enough for this application.");
+ /// }
+ ///
+ /// assert!(optimal_features.is_superset_of(&minimal_features));
+ /// let features_to_request = optimal_features.intersection(physical_device.supported_features());
+ /// ```
+ ///
+ #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
+ #[allow(missing_docs)]
+ pub struct Features {
+ $(
+ #[doc = $doc]
+ pub $member: bool,
+ )*
+ }
+
+ impl Features {
+ /// Checks enabled features against the device version, device extensions and each other.
+ pub(super) fn check_requirements(
+ &self,
+ supported: &Features,
+ api_version:
+ crate::Version,
+ extensions: &crate::device::DeviceExtensions,
+ ) -> Result<(), crate::device::features::FeatureRestrictionError> {
+ $(
+ if self.$member {
+ if !supported.$member {
+ return Err(crate::device::features::FeatureRestrictionError {
+ feature: stringify!($member),
+ restriction: crate::device::features::FeatureRestriction::NotSupported,
+ });
+ }
+
+ $(
+ if !self.$requires_feature {
+ return Err(crate::device::features::FeatureRestrictionError {
+ feature: stringify!($member),
+ restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)),
+ });
+ }
+ )*
+
+ $(
+ if self.$conflicts_feature {
+ return Err(crate::device::features::FeatureRestrictionError {
+ feature: stringify!($member),
+ restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)),
+ });
+ }
+ )*
+ } else {
+ $(
+ if extensions.$required_by_extension {
+ return Err(crate::device::features::FeatureRestrictionError {
+ feature: stringify!($member),
+ restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)),
+ });
+ }
+ )*
+ }
+ )*
+ Ok(())
+ }
+
+ /// Builds a `Features` object with all values to false.
+ pub const fn none() -> Features {
+ Features {
+ $($member: false,)*
+ }
+ }
+
+ /// Builds a `Features` object with all values to true.
+ ///
+ /// > **Note**: This function is used for testing purposes, and is probably useless in
+ /// > a real code.
+ pub const fn all() -> Features {
+ Features {
+ $($member: true,)*
+ }
+ }
+
+ /// Returns true if `self` is a superset of the parameter.
+ ///
+ /// That is, for each feature of the parameter that is true, the corresponding value
+ /// in self is true as well.
+ pub fn is_superset_of(&self, other: &Features) -> bool {
+ $((self.$member == true || other.$member == false))&&+
+ }
+
+ /// Builds a `Features` that is the intersection of `self` and another `Features`
+ /// object.
+ ///
+ /// The result's field will be true if it is also true in both `self` and `other`.
+ pub fn intersection(&self, other: &Features) -> Features {
+ Features {
+ $($member: self.$member && other.$member,)*
+ }
+ }
+
+ /// Builds a `Features` that is the difference of another `Features` object from `self`.
+ ///
+ /// The result's field will be true if it is true in `self` but not `other`.
+ pub fn difference(&self, other: &Features) -> Features {
+ Features {
+ $($member: self.$member && !other.$member,)*
+ }
+ }
+ }
+
+ impl FeaturesFfi {
+ pub(crate) fn write(&mut self, features: &Features) {
+ $(
+ std::array::IntoIter::new([
+ $(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+
+ ]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32);
+ )*
+ }
+ }
+
+ impl From<&FeaturesFfi> for Features {
+ fn from(features_ffi: &FeaturesFfi) -> Self {
+ Features {
+ $(
+ $member: std::array::IntoIter::new([
+ $(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+
+ ]).flatten().next().unwrap_or(0) != 0,
+ )*
+ }
+ }
+ }
+ };
+}
+
+pub use crate::autogen::Features;
+pub(crate) use features;
+
+/// An error that can happen when enabling a feature on a device.
+#[derive(Clone, Copy, Debug)]
+pub struct FeatureRestrictionError {
+ /// The feature in question.
+ pub feature: &'static str,
+ /// The restriction that was not met.
+ pub restriction: FeatureRestriction,
+}
+
+impl error::Error for FeatureRestrictionError {}
+
+impl fmt::Display for FeatureRestrictionError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "a restriction for the feature {} was not met: {}",
+ self.feature, self.restriction,
+ )
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum FeatureRestriction {
+ /// Not supported by the physical device.
+ NotSupported,
+ /// Requires a feature to be enabled.
+ RequiresFeature(&'static str),
+ /// Requires a feature to be disabled.
+ ConflictsFeature(&'static str),
+ /// An extension requires this feature to be enabled.
+ RequiredByExtension(&'static str),
+}
+
+impl fmt::Display for FeatureRestriction {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ match *self {
+ FeatureRestriction::NotSupported => {
+ write!(fmt, "not supported by the physical device")
+ }
+ FeatureRestriction::RequiresFeature(feat) => {
+ write!(fmt, "requires feature {} to be enabled", feat)
+ }
+ FeatureRestriction::ConflictsFeature(feat) => {
+ write!(fmt, "requires feature {} to be disabled", feat)
+ }
+ FeatureRestriction::RequiredByExtension(ext) => {
+ write!(fmt, "required to be enabled by extension {}", ext)
+ }
+ }
+ }
+}
+
+macro_rules! features_ffi {
+ {
+ $api_version:ident,
+ $device_extensions:ident,
+ $instance_extensions:ident,
+ $($member:ident => {
+ ty: $ty:ident,
+ provided_by: [$($provided_by:expr),+],
+ conflicts: [$($conflicts:ident),*],
+ },)+
+ } => {
+ #[derive(Default)]
+ pub(crate) struct FeaturesFfi {
+ features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>,
+
+ $(
+ $member: Option<ash::vk::$ty>,
+ )+
+ }
+
+ impl FeaturesFfi {
+ pub(crate) fn make_chain(
+ &mut self,
+ $api_version: crate::Version,
+ $device_extensions: &DeviceExtensions,
+ $instance_extensions: &InstanceExtensions,
+ ) {
+ self.features_vulkan10 = Some(Default::default());
+ let head = self.features_vulkan10.as_mut().unwrap();
+
+ $(
+ if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
+ std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
+ self.$member = Some(Default::default());
+ let member = self.$member.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ )+
+ }
+
+ pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
+ self.features_vulkan10.as_ref().unwrap()
+ }
+
+ pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
+ self.features_vulkan10.as_mut().unwrap()
+ }
+ }
+ };
+}
+
+pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};