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