// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // 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 for $sname where I: IntoIterator { 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 { 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 for SupportedExtensionsError { #[inline] fn from(err: OomError) -> SupportedExtensionsError { SupportedExtensionsError::OomError(err) } } impl From for SupportedExtensionsError { #[inline] fn from(err: LoadingError) -> SupportedExtensionsError { SupportedExtensionsError::LoadingError(err) } } impl From 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) ());