diff options
Diffstat (limited to 'src/extensions.rs')
-rw-r--r-- | src/extensions.rs | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/src/extensions.rs b/src/extensions.rs new file mode 100644 index 0000000..822eb67 --- /dev/null +++ b/src/extensions.rs @@ -0,0 +1,271 @@ +// 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 crate::instance::loader::LoadingError; +use crate::Error; +use crate::OomError; +use crate::Version; +use std::error; +use std::fmt; + +macro_rules! extensions { + ( + $sname:ident, + $($member:ident => { + doc: $doc:expr, + raw: $raw:expr, + requires_core: $requires_core:expr, + requires_device_extensions: [$($requires_device_extension:ident),*], + requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)? + },)* + ) => ( + /// List of extensions that are enabled or available. + #[derive(Copy, Clone, PartialEq, Eq)] + pub struct $sname { + $( + #[doc = $doc] + pub $member: bool, + )* + + /// This field ensures that an instance of this `Extensions` struct + /// can only be created through Vulkano functions and the update + /// syntax. This way, extensions can be added to Vulkano without + /// breaking existing code. + pub _unbuildable: crate::extensions::Unbuildable, + } + + impl $sname { + /// Returns an `Extensions` object with all members set to `false`. + #[inline] + pub const fn none() -> $sname { + $sname { + $($member: false,)* + _unbuildable: crate::extensions::Unbuildable(()) + } + } + + /// Returns true if `self` is a superset of the parameter. + /// + /// That is, for each extension of the parameter that is true, the corresponding value + /// in self is true as well. + pub fn is_superset_of(&self, other: &$sname) -> bool { + $((self.$member == true || other.$member == false))&&+ + } + + /// Returns the union of this list and another list. + #[inline] + pub const fn union(&self, other: &$sname) -> $sname { + $sname { + $( + $member: self.$member || other.$member, + )* + _unbuildable: crate::extensions::Unbuildable(()) + } + } + + /// Returns the intersection of this list and another list. + #[inline] + pub const fn intersection(&self, other: &$sname) -> $sname { + $sname { + $( + $member: self.$member && other.$member, + )* + _unbuildable: crate::extensions::Unbuildable(()) + } + } + + /// Returns the difference of another list from this list. + #[inline] + pub const fn difference(&self, other: &$sname) -> $sname { + $sname { + $( + $member: self.$member && !other.$member, + )* + _unbuildable: crate::extensions::Unbuildable(()) + } + } + } + + impl std::fmt::Debug for $sname { + #[allow(unused_assignments)] + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "[")?; + + let mut first = true; + + $( + if self.$member { + if !first { write!(f, ", ")? } + else { first = false; } + f.write_str(std::str::from_utf8($raw).unwrap())?; + } + )* + + write!(f, "]") + } + } + + impl<'a, I> From<I> for $sname where I: IntoIterator<Item = &'a std::ffi::CStr> { + fn from(names: I) -> Self { + let mut extensions = Self::none(); + for name in names { + match name.to_bytes() { + $( + $raw => { extensions.$member = true; } + )* + _ => (), + } + } + extensions + } + } + + impl<'a> From<&'a $sname> for Vec<std::ffi::CString> { + fn from(x: &'a $sname) -> Self { + let mut data = Self::new(); + $(if x.$member { data.push(std::ffi::CString::new(&$raw[..]).unwrap()); })* + data + } + } + ); +} + +/// Error that can happen when loading the list of layers. +#[derive(Clone, Debug)] +pub enum SupportedExtensionsError { + /// Failed to load the Vulkan shared library. + LoadingError(LoadingError), + /// Not enough memory. + OomError(OomError), +} + +impl error::Error for SupportedExtensionsError { + #[inline] + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + SupportedExtensionsError::LoadingError(ref err) => Some(err), + SupportedExtensionsError::OomError(ref err) => Some(err), + } + } +} + +impl fmt::Display for SupportedExtensionsError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + SupportedExtensionsError::LoadingError(_) => + "failed to load the Vulkan shared library", + SupportedExtensionsError::OomError(_) => "not enough memory available", + } + ) + } +} + +impl From<OomError> for SupportedExtensionsError { + #[inline] + fn from(err: OomError) -> SupportedExtensionsError { + SupportedExtensionsError::OomError(err) + } +} + +impl From<LoadingError> for SupportedExtensionsError { + #[inline] + fn from(err: LoadingError) -> SupportedExtensionsError { + SupportedExtensionsError::LoadingError(err) + } +} + +impl From<Error> for SupportedExtensionsError { + #[inline] + fn from(err: Error) -> SupportedExtensionsError { + match err { + err @ Error::OutOfHostMemory => SupportedExtensionsError::OomError(OomError::from(err)), + err @ Error::OutOfDeviceMemory => { + SupportedExtensionsError::OomError(OomError::from(err)) + } + _ => panic!("unexpected error: {:?}", err), + } + } +} + +/// An error that can happen when enabling an extension on an instance or device. +#[derive(Clone, Copy, Debug)] +pub struct ExtensionRestrictionError { + /// The extension in question. + pub extension: &'static str, + /// The restriction that was not met. + pub restriction: ExtensionRestriction, +} + +impl error::Error for ExtensionRestrictionError {} + +impl fmt::Display for ExtensionRestrictionError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "a restriction for the extension {} was not met: {}", + self.extension, self.restriction, + ) + } +} + +#[derive(Clone, Copy, Debug)] +pub enum ExtensionRestriction { + /// Not supported by the loader or physical device. + NotSupported, + /// Requires a minimum Vulkan API version. + RequiresCore(Version), + /// Requires a device extension to be enabled. + RequiresDeviceExtension(&'static str), + /// Requires an instance extension to be enabled. + RequiresInstanceExtension(&'static str), + /// Required to be enabled by the physical device. + RequiredIfSupported, + /// Requires a device extension to be disabled. + ConflictsDeviceExtension(&'static str), +} + +impl fmt::Display for ExtensionRestriction { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + ExtensionRestriction::NotSupported => { + write!(fmt, "not supported by the loader or physical device") + } + ExtensionRestriction::RequiresCore(version) => { + write!( + fmt, + "requires Vulkan API version {}.{}", + version.major, version.minor + ) + } + ExtensionRestriction::RequiresDeviceExtension(ext) => { + write!(fmt, "requires device extension {} to be enabled", ext) + } + ExtensionRestriction::RequiresInstanceExtension(ext) => { + write!(fmt, "requires instance extension {} to be enabled", ext) + } + ExtensionRestriction::RequiredIfSupported => { + write!(fmt, "required to be enabled by the physical device") + } + ExtensionRestriction::ConflictsDeviceExtension(ext) => { + write!(fmt, "requires device extension {} to be disabled", ext) + } + } + } +} + +/// This helper type can only be instantiated inside this module. +#[doc(hidden)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Unbuildable(pub(crate) ()); |