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 #![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")] 11 //! Safe and rich Rust wrapper around the Vulkan API. 12 //! 13 //! # Starting off with Vulkano 14 //! 15 //! The steps for using Vulkan through Vulkano are in principle not any different from using 16 //! the raw Vulkan API, but the details may be different for the sake of idiomaticity, safety 17 //! and convenience. 18 //! 19 //! 1. Create a [`VulkanLibrary`]. This represents a Vulkan library on the system, which must be 20 //! loaded before you can do anything with Vulkan. 21 //! 22 //! 2. Create an [`Instance`]. This is the API entry point, and represents an initialised Vulkan 23 //! library. 24 //! 25 //! 3. If you intend to show graphics to the user on a window or a screen, create a [`Surface`]. 26 //! A `Surface` is created from a window identifier or handle, that is specific to the display or 27 //! windowing system being used. The [`vulkano-win`] crate, which is part of the Vulkano 28 //! project, can make this step easier. 29 //! 30 //! 4. [Enumerate the physical devices] that are available on the `Instance`, and choose one that 31 //! is suitable for your program. A [`PhysicalDevice`] represents a Vulkan-capable device that 32 //! is available on the system, such as a graphics card, a software implementation, etc. 33 //! 34 //! 6. Create a [`Device`] and accompanying [`Queue`]s from the selected `PhysicalDevice`. 35 //! The `Device` is the most important object of Vulkan, and you need one to create almost 36 //! every other object. `Queue`s are created together with the `Device`, and are used to submit 37 //! work to the device to make it do something. 38 //! 39 //! 7. If you created a `Surface` earlier, create a [`Swapchain`]. This object contains special 40 //! images that correspond to the contents of the surface. Whenever you want to 41 //! change the contents (show something new to the user), you must first *acquire* one of these 42 //! images from the swapchain, fill it with the new contents (by rendering, copying or any 43 //! other means), and then *present* it back to the swapchain. 44 //! A swapchain can become outdated if the properties of the surface change, such as when 45 //! the size of the window changes. It then becomes necessary to create a new swapchain. 46 //! 47 //! 8. Record a [*command buffer*](crate::command_buffer), containing commands that the device must 48 //! execute. Then build the command buffer and submit it to a `Queue`. 49 //! 50 //! Many different operations can be recorded to a command buffer, such as *draw*, *compute* and 51 //! *transfer* operations. To do any of these things, you will need to create several other objects, 52 //! depending on your specific needs. This includes: 53 //! 54 //! - [*Buffers*] store general-purpose data on memory accessible by the device. This can include 55 //! mesh data (vertices, texture coordinates etc.), lighting information, matrices, and anything 56 //! else you can think of. 57 //! 58 //! - [*Images*] store texel data, arranged in a grid of one or more dimensions. They can be used 59 //! as textures, depth/stencil buffers, framebuffers and as part of a swapchain. 60 //! 61 //! - [*Pipelines*] describe operations on the device. They include one or more [*shader*]s, small 62 //! programs that the device will execute as part of a pipeline. 63 //! Pipelines come in several types: 64 //! - A [`ComputePipeline`] describes how *dispatch* commands are to be performed. 65 //! - A [`GraphicsPipeline`] describes how *draw* commands are to be performed. 66 //! 67 //! - [*Descriptor sets*] make buffers, images and other objects available to shaders. The 68 //! arrangement of these resources in shaders is described by a [`DescriptorSetLayout`]. One or 69 //! more of these layouts in turn forms a [`PipelineLayout`], which is used when creating a 70 //! pipeline object. 71 //! 72 //! - For more complex, multi-stage draw operations, you can create a [`RenderPass`] object. 73 //! This object describes the stages, known as subpasses, that draw operations consist of, 74 //! how they interact with one another, and which types of images are available in each subpass. 75 //! You must also create a [`Framebuffer`], which contains the image objects that are to be used 76 //! in a render pass. 77 //! 78 //! # `_unchecked` functions 79 //! 80 //! Many functions in Vulkano have two versions: the normal function, which is usually safe to 81 //! call, and another function with `_unchecked` added onto the end of the name, which is unsafe 82 //! to call. The `_unchecked` functions skip all validation checks, so they are usually more 83 //! efficient, but you must ensure that you meet the validity/safety requirements of the function. 84 //! 85 //! For all `_unchecked` functions, a call to the function is valid, if a call to the 86 //! corresponding normal function with the same arguments would return without any error. 87 //! This includes following all the valid usage requirements of the Vulkan specification, but may 88 //! also include additional requirements specific to Vulkano. 89 //! **All other usage of `_unchecked` functions may be undefined behavior.** 90 //! 91 //! Because there are potentially many `_unchecked` functions, and because their name and operation 92 //! can be straightforwardly understood based on the corresponding normal function, they are hidden 93 //! from the Vulkano documentation by default. You can unhide them by enabling the 94 //! `document_unchecked` cargo feature, and then generating the documentation with the command 95 //! `cargo doc --open`. 96 //! 97 //! # Cargo features 98 //! 99 //! | Feature | Description | 100 //! |----------------------|---------------------------------------------------------------|| 101 //! | `macros` | Include reexports from [`vulkano-macros`]. Enabled by default. | 102 //! | `document_unchecked` | Include `_unchecked` functions in the generated documentation. | 103 //! | `serde` | Enables (de)serialization of certain types using [`serde`]. | 104 //! 105 //! [`VulkanLibrary`]: crate::VulkanLibrary 106 //! [`Instance`]: crate::instance::Instance 107 //! [`Surface`]: crate::swapchain::Surface 108 //! [`vulkano-win`]: https://crates.io/crates/vulkano-win 109 //! [Enumerate the physical devices]: crate::instance::Instance::enumerate_physical_devices 110 //! [`PhysicalDevice`]: crate::device::physical::PhysicalDevice 111 //! [`Device`]: crate::device::Device 112 //! [`Queue`]: crate::device::Queue 113 //! [`Swapchain`]: crate::swapchain::Swapchain 114 //! [*command buffer*]: crate::command_buffer 115 //! [*Buffers*]: crate::buffer 116 //! [*Images*]: crate::image 117 //! [*Pipelines*]: crate::pipeline 118 //! [*shader*]: crate::shader 119 //! [`ComputePipeline`]: crate::pipeline::ComputePipeline 120 //! [`GraphicsPipeline`]: crate::pipeline::GraphicsPipeline 121 //! [*Descriptor sets*]: crate::descriptor_set 122 //! [`DescriptorSetLayout`]: crate::descriptor_set::layout 123 //! [`PipelineLayout`]: crate::pipeline::layout 124 //! [`RenderPass`]: crate::render_pass::RenderPass 125 //! [`Framebuffer`]: crate::render_pass::Framebuffer 126 //! [`vulkano-macros`]: vulkano_macros 127 //! [`serde`]: https://crates.io/crates/serde 128 129 //#![warn(missing_docs)] // TODO: activate 130 #![warn( 131 rust_2018_idioms, 132 rust_2021_compatibility, 133 clippy::trivially_copy_pass_by_ref 134 )] 135 // These lints are a bit too pedantic, so they're disabled here. 136 #![allow( 137 clippy::collapsible_else_if, 138 clippy::collapsible_if, 139 clippy::derivable_impls, // TODO: remove 140 clippy::large_enum_variant, 141 clippy::len_without_is_empty, 142 clippy::missing_safety_doc, // TODO: remove 143 clippy::module_inception, 144 clippy::mutable_key_type, 145 clippy::needless_borrowed_reference, 146 clippy::new_without_default, 147 clippy::nonminimal_bool, 148 clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error 149 clippy::result_large_err, 150 clippy::too_many_arguments, 151 clippy::type_complexity, 152 clippy::vec_box, 153 clippy::wrong_self_convention 154 )] 155 156 pub use ash::vk::Handle; 157 pub use half; 158 pub use library::{LoadingError, VulkanLibrary}; 159 use std::{ 160 error::Error, 161 fmt::{Display, Error as FmtError, Formatter}, 162 num::NonZeroU64, 163 ops::Deref, 164 sync::Arc, 165 }; 166 pub use {extensions::ExtensionProperties, version::Version}; 167 168 #[macro_use] 169 mod tests; 170 #[macro_use] 171 mod extensions; 172 pub mod buffer; 173 pub mod command_buffer; 174 pub mod descriptor_set; 175 pub mod device; 176 pub mod format; 177 mod version; 178 #[macro_use] 179 pub mod render_pass; 180 mod cache; 181 mod fns; 182 pub mod image; 183 pub mod instance; 184 pub mod library; 185 mod macros; 186 pub mod memory; 187 pub mod padded; 188 pub mod pipeline; 189 pub mod query; 190 mod range_map; 191 pub mod range_set; 192 pub mod sampler; 193 pub mod shader; 194 pub mod swapchain; 195 pub mod sync; 196 197 /// Represents memory size and offset values on a Vulkan device. 198 /// Analogous to the Rust `usize` type on the host. 199 pub use ash::vk::DeviceSize; 200 201 /// A [`DeviceSize`] that is known not to equal zero. 202 pub type NonZeroDeviceSize = NonZeroU64; 203 204 // Allow refering to crate by its name to work around limitations of proc-macros 205 // in doctests. 206 // See https://github.com/rust-lang/cargo/issues/9886 207 // and https://github.com/bkchr/proc-macro-crate/issues/10 208 #[allow(unused_extern_crates)] 209 extern crate self as vulkano; 210 211 /// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object. 212 pub unsafe trait SafeDeref: Deref {} 213 unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {} 214 unsafe impl<T: ?Sized> SafeDeref for Arc<T> {} 215 unsafe impl<T: ?Sized> SafeDeref for Box<T> {} 216 217 /// Gives access to the internal identifier of an object. 218 pub unsafe trait VulkanObject { 219 /// The type of the object. 220 type Handle: ash::vk::Handle; 221 222 /// Returns the raw Vulkan handle of the object. handle(&self) -> Self::Handle223 fn handle(&self) -> Self::Handle; 224 } 225 226 unsafe impl<T, U> VulkanObject for T 227 where 228 T: SafeDeref<Target = U>, 229 U: VulkanObject + ?Sized, 230 { 231 type Handle = U::Handle; 232 233 #[inline] handle(&self) -> Self::Handle234 fn handle(&self) -> Self::Handle { 235 (**self).handle() 236 } 237 } 238 239 /// Error type returned by most Vulkan functions. 240 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 241 pub enum OomError { 242 /// There is no memory available on the host (ie. the CPU, RAM, etc.). 243 OutOfHostMemory, 244 /// There is no memory available on the device (ie. video memory). 245 OutOfDeviceMemory, 246 } 247 248 impl Error for OomError {} 249 250 impl Display for OomError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>251 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 252 write!( 253 f, 254 "{}", 255 match self { 256 OomError::OutOfHostMemory => "no memory available on the host", 257 OomError::OutOfDeviceMemory => "no memory available on the graphical device", 258 } 259 ) 260 } 261 } 262 263 impl From<VulkanError> for OomError { from(err: VulkanError) -> OomError264 fn from(err: VulkanError) -> OomError { 265 match err { 266 VulkanError::OutOfHostMemory => OomError::OutOfHostMemory, 267 VulkanError::OutOfDeviceMemory => OomError::OutOfDeviceMemory, 268 _ => panic!("unexpected error: {:?}", err), 269 } 270 } 271 } 272 273 // Generated by build.rs 274 include!(concat!(env!("OUT_DIR"), "/errors.rs")); 275 276 impl Error for VulkanError {} 277 278 impl Display for VulkanError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>279 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 280 write!( 281 f, 282 "{}", 283 match self { 284 VulkanError::OutOfHostMemory => "a host memory allocation has failed", 285 VulkanError::OutOfDeviceMemory => "a device memory allocation has failed", 286 VulkanError::InitializationFailed => { 287 "initialization of an object could not be completed for \ 288 implementation-specific reasons" 289 } 290 VulkanError::DeviceLost => "the logical or physical device has been lost", 291 VulkanError::MemoryMapFailed => "mapping of a memory object has failed", 292 VulkanError::LayerNotPresent => { 293 "a requested layer is not present or could not be loaded" 294 } 295 VulkanError::ExtensionNotPresent => "a requested extension is not supported", 296 VulkanError::FeatureNotPresent => "a requested feature is not supported", 297 VulkanError::IncompatibleDriver => { 298 "the requested version of Vulkan is not supported by the driver or is \ 299 otherwise incompatible for implementation-specific reasons" 300 } 301 VulkanError::TooManyObjects => { 302 "too many objects of the type have already been created" 303 } 304 VulkanError::FormatNotSupported => { 305 "a requested format is not supported on this device" 306 } 307 VulkanError::FragmentedPool => { 308 "a pool allocation has failed due to fragmentation of the pool's memory" 309 } 310 VulkanError::Unknown => { 311 "an unknown error has occurred; either the application has provided invalid \ 312 input, or an implementation failure has occurred" 313 } 314 VulkanError::OutOfPoolMemory => "a pool memory allocation has failed", 315 VulkanError::InvalidExternalHandle => { 316 "an external handle is not a valid handle of the specified type" 317 } 318 VulkanError::Fragmentation => { 319 "a descriptor pool creation has failed due to fragmentation" 320 } 321 VulkanError::InvalidOpaqueCaptureAddress => { 322 "a buffer creation or memory allocation failed because the requested address \ 323 is not available. A shader group handle assignment failed because the \ 324 requested shader group handle information is no longer valid" 325 } 326 VulkanError::IncompatibleDisplay => { 327 "the display used by a swapchain does not use the same presentable image \ 328 layout, or is incompatible in a way that prevents sharing an image" 329 } 330 VulkanError::NotPermitted => "a requested operation was not permitted", 331 VulkanError::SurfaceLost => "a surface is no longer available", 332 VulkanError::NativeWindowInUse => { 333 "the requested window is already in use by Vulkan or another API in a manner \ 334 which prevents it from being used again" 335 } 336 VulkanError::OutOfDate => { 337 "a surface has changed in such a way that it is no longer compatible with the \ 338 swapchain, and further presentation requests using the swapchain will fail" 339 } 340 VulkanError::ValidationFailed => "validation failed", 341 VulkanError::FullScreenExclusiveModeLost => { 342 "an operation on a swapchain created with application controlled full-screen \ 343 access failed as it did not have exclusive full-screen access" 344 } 345 VulkanError::InvalidDrmFormatModifierPlaneLayout => { 346 "the requested DRM format modifier plane layout is invalid" 347 } 348 VulkanError::InvalidShader => "one or more shaders failed to compile or link", 349 VulkanError::ImageUsageNotSupported => 350 "the requested `ImageUsage` are not supported", 351 VulkanError::VideoPictureLayoutNotSupported => 352 "the requested video picture layout is not supported", 353 VulkanError::VideoProfileOperationNotSupported => 354 "a video profile operation specified via \ 355 `VideoProfileInfo::video_codec_operation` is not supported", 356 VulkanError::VideoProfileFormatNotSupported => 357 "format parameters in a requested `VideoProfileInfo` chain are not supported", 358 VulkanError::VideoProfileCodecNotSupported => 359 "codec-specific parameters in a requested `VideoProfileInfo` chain are not \ 360 supported", 361 VulkanError::VideoStdVersionNotSupported => 362 "the specified video Std header version is not supported", 363 VulkanError::CompressionExhausted => 364 "an image creation failed because internal resources required for compression \ 365 are exhausted", 366 VulkanError::Unnamed(result) => 367 return write!(f, "unnamed error, VkResult value {}", result.as_raw()), 368 } 369 ) 370 } 371 } 372 373 /// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow 374 /// a given operation. 375 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] 376 pub struct RequiresOneOf { 377 /// A minimum Vulkan API version that would allow the operation. 378 pub api_version: Option<Version>, 379 380 /// Enabled features that would allow the operation. 381 pub features: &'static [&'static str], 382 383 /// Available/enabled device extensions that would allow the operation. 384 pub device_extensions: &'static [&'static str], 385 386 /// Available/enabled instance extensions that would allow the operation. 387 pub instance_extensions: &'static [&'static str], 388 } 389 390 impl RequiresOneOf { 391 /// Returns whether there is more than one possible requirement. len(&self) -> usize392 pub fn len(&self) -> usize { 393 self.api_version.map_or(0, |_| 1) 394 + self.features.len() 395 + self.device_extensions.len() 396 + self.instance_extensions.len() 397 } 398 } 399 400 impl Display for RequiresOneOf { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>401 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 402 let mut members_written = 0; 403 404 if let Some(version) = self.api_version { 405 write!(f, "Vulkan API version {}.{}", version.major, version.minor)?; 406 members_written += 1; 407 } 408 409 if let Some((last, rest)) = self.features.split_last() { 410 if members_written != 0 { 411 write!(f, ", ")?; 412 } 413 414 members_written += 1; 415 416 if rest.is_empty() { 417 write!(f, "feature {}", last)?; 418 } else { 419 write!(f, "features ")?; 420 421 for feature in rest { 422 write!(f, "{}, ", feature)?; 423 } 424 425 write!(f, "{}", last)?; 426 } 427 } 428 429 if let Some((last, rest)) = self.device_extensions.split_last() { 430 if members_written != 0 { 431 write!(f, ", ")?; 432 } 433 434 members_written += 1; 435 436 if rest.is_empty() { 437 write!(f, "device extension {}", last)?; 438 } else { 439 write!(f, "device extensions ")?; 440 441 for feature in rest { 442 write!(f, "{}, ", feature)?; 443 } 444 445 write!(f, "{}", last)?; 446 } 447 } 448 449 if let Some((last, rest)) = self.instance_extensions.split_last() { 450 if members_written != 0 { 451 write!(f, ", ")?; 452 } 453 454 if rest.is_empty() { 455 write!(f, "instance extension {}", last)?; 456 } else { 457 write!(f, "instance extensions ")?; 458 459 for feature in rest { 460 write!(f, "{}, ", feature)?; 461 } 462 463 write!(f, "{}", last)?; 464 } 465 } 466 467 Ok(()) 468 } 469 } 470 471 #[derive(Clone, Copy, Debug)] 472 pub(crate) struct RequirementNotMet { 473 pub(crate) required_for: &'static str, 474 pub(crate) requires_one_of: RequiresOneOf, 475 } 476 477 /// A helper type for non-exhaustive structs. 478 /// 479 /// This type cannot be constructed outside Vulkano. Structures with a field of this type can only 480 /// be constructed by calling a constructor function or `Default::default()`. The effect is similar 481 /// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update 482 /// syntax from being used. 483 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed 484 pub struct NonExhaustive(pub(crate) ()); 485