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 crate::instance::loader::LoadingError; 11 use crate::Error; 12 use crate::OomError; 13 use crate::Version; 14 use std::error; 15 use std::fmt; 16 17 macro_rules! extensions { 18 ( 19 $sname:ident, 20 $($member:ident => { 21 doc: $doc:expr, 22 raw: $raw:expr, 23 requires_core: $requires_core:expr, 24 requires_device_extensions: [$($requires_device_extension:ident),*], 25 requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)? 26 },)* 27 ) => ( 28 /// List of extensions that are enabled or available. 29 #[derive(Copy, Clone, PartialEq, Eq)] 30 pub struct $sname { 31 $( 32 #[doc = $doc] 33 pub $member: bool, 34 )* 35 36 /// This field ensures that an instance of this `Extensions` struct 37 /// can only be created through Vulkano functions and the update 38 /// syntax. This way, extensions can be added to Vulkano without 39 /// breaking existing code. 40 pub _unbuildable: crate::extensions::Unbuildable, 41 } 42 43 impl $sname { 44 /// Returns an `Extensions` object with all members set to `false`. 45 #[inline] 46 pub const fn none() -> $sname { 47 $sname { 48 $($member: false,)* 49 _unbuildable: crate::extensions::Unbuildable(()) 50 } 51 } 52 53 /// Returns true if `self` is a superset of the parameter. 54 /// 55 /// That is, for each extension of the parameter that is true, the corresponding value 56 /// in self is true as well. 57 pub fn is_superset_of(&self, other: &$sname) -> bool { 58 $((self.$member == true || other.$member == false))&&+ 59 } 60 61 /// Returns the union of this list and another list. 62 #[inline] 63 pub const fn union(&self, other: &$sname) -> $sname { 64 $sname { 65 $( 66 $member: self.$member || other.$member, 67 )* 68 _unbuildable: crate::extensions::Unbuildable(()) 69 } 70 } 71 72 /// Returns the intersection of this list and another list. 73 #[inline] 74 pub const fn intersection(&self, other: &$sname) -> $sname { 75 $sname { 76 $( 77 $member: self.$member && other.$member, 78 )* 79 _unbuildable: crate::extensions::Unbuildable(()) 80 } 81 } 82 83 /// Returns the difference of another list from this list. 84 #[inline] 85 pub const fn difference(&self, other: &$sname) -> $sname { 86 $sname { 87 $( 88 $member: self.$member && !other.$member, 89 )* 90 _unbuildable: crate::extensions::Unbuildable(()) 91 } 92 } 93 } 94 95 impl std::fmt::Debug for $sname { 96 #[allow(unused_assignments)] 97 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 98 write!(f, "[")?; 99 100 let mut first = true; 101 102 $( 103 if self.$member { 104 if !first { write!(f, ", ")? } 105 else { first = false; } 106 f.write_str(std::str::from_utf8($raw).unwrap())?; 107 } 108 )* 109 110 write!(f, "]") 111 } 112 } 113 114 impl<'a, I> From<I> for $sname where I: IntoIterator<Item = &'a std::ffi::CStr> { 115 fn from(names: I) -> Self { 116 let mut extensions = Self::none(); 117 for name in names { 118 match name.to_bytes() { 119 $( 120 $raw => { extensions.$member = true; } 121 )* 122 _ => (), 123 } 124 } 125 extensions 126 } 127 } 128 129 impl<'a> From<&'a $sname> for Vec<std::ffi::CString> { 130 fn from(x: &'a $sname) -> Self { 131 let mut data = Self::new(); 132 $(if x.$member { data.push(std::ffi::CString::new(&$raw[..]).unwrap()); })* 133 data 134 } 135 } 136 ); 137 } 138 139 /// Error that can happen when loading the list of layers. 140 #[derive(Clone, Debug)] 141 pub enum SupportedExtensionsError { 142 /// Failed to load the Vulkan shared library. 143 LoadingError(LoadingError), 144 /// Not enough memory. 145 OomError(OomError), 146 } 147 148 impl error::Error for SupportedExtensionsError { 149 #[inline] source(&self) -> Option<&(dyn error::Error + 'static)>150 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 151 match *self { 152 SupportedExtensionsError::LoadingError(ref err) => Some(err), 153 SupportedExtensionsError::OomError(ref err) => Some(err), 154 } 155 } 156 } 157 158 impl fmt::Display for SupportedExtensionsError { 159 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>160 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 161 write!( 162 fmt, 163 "{}", 164 match *self { 165 SupportedExtensionsError::LoadingError(_) => 166 "failed to load the Vulkan shared library", 167 SupportedExtensionsError::OomError(_) => "not enough memory available", 168 } 169 ) 170 } 171 } 172 173 impl From<OomError> for SupportedExtensionsError { 174 #[inline] from(err: OomError) -> SupportedExtensionsError175 fn from(err: OomError) -> SupportedExtensionsError { 176 SupportedExtensionsError::OomError(err) 177 } 178 } 179 180 impl From<LoadingError> for SupportedExtensionsError { 181 #[inline] from(err: LoadingError) -> SupportedExtensionsError182 fn from(err: LoadingError) -> SupportedExtensionsError { 183 SupportedExtensionsError::LoadingError(err) 184 } 185 } 186 187 impl From<Error> for SupportedExtensionsError { 188 #[inline] from(err: Error) -> SupportedExtensionsError189 fn from(err: Error) -> SupportedExtensionsError { 190 match err { 191 err @ Error::OutOfHostMemory => SupportedExtensionsError::OomError(OomError::from(err)), 192 err @ Error::OutOfDeviceMemory => { 193 SupportedExtensionsError::OomError(OomError::from(err)) 194 } 195 _ => panic!("unexpected error: {:?}", err), 196 } 197 } 198 } 199 200 /// An error that can happen when enabling an extension on an instance or device. 201 #[derive(Clone, Copy, Debug)] 202 pub struct ExtensionRestrictionError { 203 /// The extension in question. 204 pub extension: &'static str, 205 /// The restriction that was not met. 206 pub restriction: ExtensionRestriction, 207 } 208 209 impl error::Error for ExtensionRestrictionError {} 210 211 impl fmt::Display for ExtensionRestrictionError { 212 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>213 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 214 write!( 215 fmt, 216 "a restriction for the extension {} was not met: {}", 217 self.extension, self.restriction, 218 ) 219 } 220 } 221 222 #[derive(Clone, Copy, Debug)] 223 pub enum ExtensionRestriction { 224 /// Not supported by the loader or physical device. 225 NotSupported, 226 /// Requires a minimum Vulkan API version. 227 RequiresCore(Version), 228 /// Requires a device extension to be enabled. 229 RequiresDeviceExtension(&'static str), 230 /// Requires an instance extension to be enabled. 231 RequiresInstanceExtension(&'static str), 232 /// Required to be enabled by the physical device. 233 RequiredIfSupported, 234 /// Requires a device extension to be disabled. 235 ConflictsDeviceExtension(&'static str), 236 } 237 238 impl fmt::Display for ExtensionRestriction { 239 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>240 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 241 match *self { 242 ExtensionRestriction::NotSupported => { 243 write!(fmt, "not supported by the loader or physical device") 244 } 245 ExtensionRestriction::RequiresCore(version) => { 246 write!( 247 fmt, 248 "requires Vulkan API version {}.{}", 249 version.major, version.minor 250 ) 251 } 252 ExtensionRestriction::RequiresDeviceExtension(ext) => { 253 write!(fmt, "requires device extension {} to be enabled", ext) 254 } 255 ExtensionRestriction::RequiresInstanceExtension(ext) => { 256 write!(fmt, "requires instance extension {} to be enabled", ext) 257 } 258 ExtensionRestriction::RequiredIfSupported => { 259 write!(fmt, "required to be enabled by the physical device") 260 } 261 ExtensionRestriction::ConflictsDeviceExtension(ext) => { 262 write!(fmt, "requires device extension {} to be disabled", ext) 263 } 264 } 265 } 266 } 267 268 /// This helper type can only be instantiated inside this module. 269 #[doc(hidden)] 270 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 271 pub struct Unbuildable(pub(crate) ()); 272