Skip to main content

vulkano/
lib.rs

1#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
2//! Safe and rich Rust wrapper around the Vulkan API.
3//!
4//! # Starting off with Vulkano
5//!
6//! The steps for using Vulkan through Vulkano are in principle not any different from using
7//! the raw Vulkan API, but the details may be different for the sake of idiomaticity, safety
8//! and convenience.
9//!
10//! 1. Create a [`VulkanLibrary`]. This represents a Vulkan library on the system, which must be
11//!    loaded before you can do anything with Vulkan.
12//!
13//! 2. Create an [`Instance`]. This is the API entry point, and represents an initialised Vulkan
14//!    library.
15//!
16//! 3. If you intend to show graphics to the user on a window or a screen, create a [`Surface`].
17//!    A `Surface` is created from a window identifier or handle, that is specific to the display or
18//!    windowing system being used. Vulkano uses `raw-window-handle` to abstract over the different
19//!    windowing systems. Note that you have to make sure that the `raw-window-handle` that your
20//!    windowing library uses is compatible with the `raw-window-handle` that vulkano uses. For
21//!    example, if you use a `winit` version that uses a different version from the one vulkano
22//!    uses, you can add one of the [features](https://docs.rs/crate/winit/latest/features) that
23//!    starts with `rwh` to `winit`. Currently, vulkano is compatible with `rwh_06`.
24//!    
25//! 4. [Enumerate the physical devices] that are available on the `Instance`, and choose one that
26//!    is suitable for your program. A [`PhysicalDevice`] represents a Vulkan-capable device that
27//!    is available on the system, such as a graphics card, a software implementation, etc.
28//!
29//! 5. Create a [`Device`] and accompanying [`Queue`]s from the selected `PhysicalDevice`. The
30//!    `Device` is the most important object of Vulkan, and you need one to create almost every
31//!    other object. `Queue`s are created together with the `Device`, and are used to submit work
32//!    to the device to make it do something.
33//!
34//! 6. If you created a `Surface` earlier, create a [`Swapchain`]. This object contains special
35//!    images that correspond to the contents of the surface. Whenever you want to change the
36//!    contents (show something new to the user), you must first *acquire* one of these images from
37//!    the swapchain, fill it with the new contents (by rendering, copying or any other means), and
38//!    then *present* it back to the swapchain. A swapchain can become outdated if the properties
39//!    of the surface change, such as when the size of the window changes. It then becomes
40//!    necessary to create a new swapchain.
41//!
42//! 7. Record a [*command buffer*](command_buffer), containing commands that the device must
43//!    execute. Then build the command buffer and submit it to a `Queue`.
44//!
45//! Many different operations can be recorded to a command buffer, such as *draw*, *compute* and
46//! *transfer* operations. To do any of these things, you will need to create several other
47//! objects, depending on your specific needs. This includes:
48//!
49//! - [*Buffers*] store general-purpose data on memory accessible by the device. This can include
50//!   mesh data (vertices, texture coordinates etc.), lighting information, matrices, and anything
51//!   else you can think of.
52//!
53//! - [*Images*] store texel data, arranged in a grid of one or more dimensions. They can be used
54//!   as textures, depth/stencil buffers, framebuffers and as part of a swapchain.
55//!
56//! - [*Pipelines*] describe operations on the device. They include one or more [*shader*]s, small
57//!   programs that the device will execute as part of a pipeline. Pipelines come in several types:
58//!   - A [`ComputePipeline`] describes how *dispatch* commands are to be performed.
59//!   - A [`GraphicsPipeline`] describes how *draw* commands are to be performed.
60//!
61//! - [*Descriptor sets*] make buffers, images and other objects available to shaders. The
62//!   arrangement of these resources in shaders is described by a [`DescriptorSetLayout`]. One or
63//!   more of these layouts in turn forms a [`PipelineLayout`], which is used when creating a
64//!   pipeline object.
65//!
66//! - For more complex, multi-stage draw operations, you can create a [`RenderPass`] object. This
67//!   object describes the stages, known as subpasses, that draw operations consist of, how they
68//!   interact with one another, and which types of images are available in each subpass. You must
69//!   also create a [`Framebuffer`], which contains the image objects that are to be used in a
70//!   render pass.
71//!
72//! # `_unchecked` functions
73//!
74//! Many functions in Vulkano have two versions: the normal function, which is usually safe to
75//! call, and another function with `_unchecked` added onto the end of the name, which is unsafe
76//! to call. The `_unchecked` functions skip all validation checks, so they are usually more
77//! efficient, but you must ensure that you meet the validity/safety requirements of the function.
78//!
79//! For all `_unchecked` functions, a call to the function is valid, if a call to the
80//! corresponding normal function with the same arguments would return without any error.
81//! This includes following all the valid usage requirements of the Vulkan specification, but may
82//! also include additional requirements specific to Vulkano.
83//! **All other usage of `_unchecked` functions may be undefined behavior.**
84//!
85//! Because there are potentially many `_unchecked` functions, and because their name and operation
86//! can be straightforwardly understood based on the corresponding normal function, they are hidden
87//! from the Vulkano documentation by default. You can unhide them by enabling the
88//! `document_unchecked` cargo feature, and then generating the documentation with the command
89//! `cargo doc --open`.
90//!
91//! # Cargo features
92//!
93//! | Feature              | Description                                                    |
94//! |----------------------|----------------------------------------------------------------|
95//! | `macros`             | Include reexports from [`vulkano-macros`]. Enabled by default. |
96//! | `x11`                | Support for X11 platforms. Enabled by default.                 |
97//! | `document_unchecked` | Include `_unchecked` functions in the generated documentation. |
98//! | `serde`              | Enables (de)serialization of certain types using [`serde`].    |
99//!
100//! [`Instance`]: instance::Instance
101//! [`Surface`]: swapchain::Surface
102//! [Enumerate the physical devices]: instance::Instance::enumerate_physical_devices
103//! [`PhysicalDevice`]: device::physical::PhysicalDevice
104//! [`Device`]: device::Device
105//! [`Queue`]: device::Queue
106//! [`Swapchain`]: swapchain::Swapchain
107//! [*command buffer*]: command_buffer
108//! [*Buffers*]: buffer
109//! [*Images*]: image
110//! [*Pipelines*]: pipeline
111//! [*shader*]: shader
112//! [`ComputePipeline`]: pipeline::ComputePipeline
113//! [`GraphicsPipeline`]: pipeline::GraphicsPipeline
114//! [*Descriptor sets*]: descriptor_set
115//! [`DescriptorSetLayout`]: descriptor_set::layout
116//! [`PipelineLayout`]: pipeline::layout
117//! [`RenderPass`]: render_pass::RenderPass
118//! [`Framebuffer`]: render_pass::Framebuffer
119//! [`vulkano-macros`]: vulkano_macros
120//! [`serde`]: https://crates.io/crates/serde
121
122pub use ash::vk::Handle;
123use bytemuck::{Pod, Zeroable};
124pub use extensions::ExtensionProperties;
125pub use half;
126pub use library::{LoadingError, VulkanLibrary};
127use std::{
128    borrow::Cow,
129    error::Error,
130    fmt::{Debug, Display, Error as FmtError, Formatter},
131    num::NonZeroU64,
132    ops::Deref,
133    sync::Arc,
134};
135pub use version::Version;
136
137#[macro_use]
138mod tests;
139#[macro_use]
140mod extensions;
141pub mod acceleration_structure;
142pub mod buffer;
143pub mod command_buffer;
144pub mod deferred;
145pub mod descriptor_set;
146pub mod device;
147pub mod display;
148pub mod format;
149mod version;
150#[macro_use]
151pub mod render_pass;
152mod cache;
153mod fns;
154pub mod image;
155pub mod instance;
156pub mod library;
157mod macros;
158pub mod memory;
159pub mod padded;
160pub mod pipeline;
161pub mod query;
162mod range_map;
163pub mod range_set;
164pub mod shader;
165pub mod swapchain;
166pub mod sync;
167
168/// Represents memory size and offset values on a Vulkan device.
169/// Analogous to the Rust `usize` type on the host.
170pub use ash::vk::DeviceSize;
171
172/// A [`DeviceSize`] that is known not to equal zero.
173pub type NonZeroDeviceSize = NonZeroU64;
174
175/// Represents an address (pointer) on a Vulkan device.
176pub use ash::vk::DeviceAddress;
177
178/// A [`DeviceAddress`] that is known not to equal zero.
179pub type NonNullDeviceAddress = NonZeroU64;
180
181/// Represents a region of device addresses with a stride.
182#[derive(Debug, Copy, Clone, Default)]
183pub struct StridedDeviceAddressRegion {
184    pub device_address: DeviceAddress,
185    pub stride: DeviceSize,
186    pub size: DeviceSize,
187}
188
189impl StridedDeviceAddressRegion {
190    #[doc(hidden)]
191    pub fn to_vk(&self) -> ash::vk::StridedDeviceAddressRegionKHR {
192        ash::vk::StridedDeviceAddressRegionKHR {
193            device_address: self.device_address,
194            stride: self.stride,
195            size: self.size,
196        }
197    }
198}
199
200/// Holds 24 bits in the least significant bits of memory,
201/// and 8 bytes in the most significant bits of that memory,
202/// occupying a single [`u32`] in total.
203// NOTE: This is copied from Ash, but duplicated here so that we can implement traits on it.
204#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Zeroable, Pod)]
205#[repr(transparent)]
206pub struct Packed24_8(u32);
207
208impl Packed24_8 {
209    /// Returns a new `Packed24_8` value.
210    #[inline]
211    pub fn new(low_24: u32, high_8: u8) -> Self {
212        Self((low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24))
213    }
214
215    /// Returns the least-significant 24 bits (3 bytes) of this integer.
216    #[inline]
217    pub fn low_24(&self) -> u32 {
218        self.0 & 0xffffff
219    }
220
221    /// Returns the most significant 8 bits (single byte) of this integer.
222    #[inline]
223    pub fn high_8(&self) -> u8 {
224        (self.0 >> 24) as u8
225    }
226}
227
228// Allow referring to crate by its name to work around limitations of proc-macros
229// in doctests.
230// See https://github.com/rust-lang/cargo/issues/9886
231// and https://github.com/bkchr/proc-macro-crate/issues/10
232#[allow(unused_extern_crates)]
233extern crate self as vulkano;
234
235/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
236pub unsafe trait SafeDeref: Deref {}
237unsafe impl<T: ?Sized> SafeDeref for &T {}
238unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
239unsafe impl<T: ?Sized> SafeDeref for Box<T> {}
240
241/// Gives access to the internal identifier of an object.
242pub unsafe trait VulkanObject {
243    /// The type of the object.
244    type Handle: Handle;
245
246    /// Returns the raw Vulkan handle of the object.
247    fn handle(&self) -> Self::Handle;
248}
249
250unsafe impl<T, U> VulkanObject for T
251where
252    T: SafeDeref<Target = U>,
253    U: VulkanObject + ?Sized,
254{
255    type Handle = U::Handle;
256
257    #[inline]
258    fn handle(&self) -> Self::Handle {
259        (**self).handle()
260    }
261}
262
263/// A wrapper that displays only the contained object's type and handle when debug-formatted. This
264/// is useful because we have a lot of dependency chains, and the same dependencies would otherwise
265/// be debug-formatted along with the dependents over and over leading to royal levels of spam.
266#[repr(transparent)]
267struct DebugWrapper<T>(T);
268
269impl<T> Debug for DebugWrapper<T>
270where
271    T: Debug + VulkanObject,
272{
273    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
274        write!(f, "0x{:x}", self.0.handle().as_raw())
275    }
276}
277
278impl<T> Deref for DebugWrapper<T> {
279    type Target = T;
280
281    fn deref(&self) -> &Self::Target {
282        &self.0
283    }
284}
285
286// Generated by build.rs
287include!(concat!(env!("OUT_DIR"), "/errors.rs"));
288
289impl Error for VulkanError {}
290
291impl Display for VulkanError {
292    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
293        let msg = match self {
294            VulkanError::NotReady => "a resource is not yet ready",
295            VulkanError::Timeout => "an operation has not completed in the specified time",
296            VulkanError::OutOfHostMemory => "a host memory allocation has failed",
297            VulkanError::OutOfDeviceMemory => "a device memory allocation has failed",
298            VulkanError::InitializationFailed => {
299                "initialization of an object could not be completed for implementation-specific \
300                reasons"
301            }
302            VulkanError::DeviceLost => "the logical or physical device has been lost",
303            VulkanError::MemoryMapFailed => "mapping of a memory object has failed",
304            VulkanError::LayerNotPresent => {
305                "a requested layer is not present or could not be loaded"
306            }
307            VulkanError::ExtensionNotPresent => "a requested extension is not supported",
308            VulkanError::FeatureNotPresent => "a requested feature is not supported",
309            VulkanError::IncompatibleDriver => {
310                "the requested version of Vulkan is not supported by the driver or is otherwise \
311                incompatible for implementation-specific reasons"
312            }
313            VulkanError::TooManyObjects => "too many objects of the type have already been created",
314            VulkanError::FormatNotSupported => "a requested format is not supported on this device",
315            VulkanError::FragmentedPool => {
316                "a pool allocation has failed due to fragmentation of the pool's memory"
317            }
318            VulkanError::Unknown => {
319                "an unknown error has occurred; either the application has provided invalid input, \
320                or an implementation failure has occurred"
321            }
322            VulkanError::OutOfPoolMemory => "a pool memory allocation has failed",
323            VulkanError::InvalidExternalHandle => {
324                "an external handle is not a valid handle of the specified type"
325            }
326            VulkanError::Fragmentation => {
327                "a descriptor pool creation has failed due to fragmentation"
328            }
329            VulkanError::InvalidOpaqueCaptureAddress => {
330                "a buffer creation or memory allocation failed because the requested address is \
331                not available. A shader group handle assignment failed because the requested \
332                shader group handle information is no longer valid"
333            }
334            VulkanError::IncompatibleDisplay => {
335                "the display used by a swapchain does not use the same presentable image layout, \
336                or is incompatible in a way that prevents sharing an image"
337            }
338            VulkanError::NotPermitted => "a requested operation was not permitted",
339            VulkanError::SurfaceLost => "a surface is no longer available",
340            VulkanError::NativeWindowInUse => {
341                "the requested window is already in use by Vulkan or another API in a manner which \
342                prevents it from being used again"
343            }
344            VulkanError::OutOfDate => {
345                "a surface has changed in such a way that it is no longer compatible with the \
346                swapchain, and further presentation requests using the swapchain will fail"
347            }
348            VulkanError::InvalidVideoStdParameters => {
349                "the provided Video Std parameters do not adhere to the requirements of the used \
350                video compression standard"
351            }
352            VulkanError::ValidationFailed => "validation failed",
353            VulkanError::FullScreenExclusiveModeLost => {
354                "an operation on a swapchain created with application controlled full-screen \
355                access failed as it did not have exclusive full-screen access"
356            }
357            VulkanError::InvalidDrmFormatModifierPlaneLayout => {
358                "the requested DRM format modifier plane layout is invalid"
359            }
360            VulkanError::InvalidShader => "one or more shaders failed to compile or link",
361            VulkanError::ImageUsageNotSupported => "the requested `ImageUsage` are not supported",
362            VulkanError::VideoPictureLayoutNotSupported => {
363                "the requested video picture layout is not supported"
364            }
365            VulkanError::VideoProfileOperationNotSupported => {
366                "a video profile operation specified via `VideoProfileInfo::video_codec_operation` \
367                is not supported"
368            }
369            VulkanError::VideoProfileFormatNotSupported => {
370                "format parameters in a requested `VideoProfileInfo` chain are not supported"
371            }
372            VulkanError::VideoProfileCodecNotSupported => {
373                "codec-specific parameters in a requested `VideoProfileInfo` chain are not \
374                supported"
375            }
376            VulkanError::VideoStdVersionNotSupported => {
377                "the specified video Std header version is not supported"
378            }
379            VulkanError::CompressionExhausted => {
380                "an image creation failed because internal resources required for compression are \
381                exhausted"
382            }
383            VulkanError::Unnamed(result) => {
384                return write!(f, "unnamed error, VkResult value {}", result.as_raw());
385            }
386        };
387
388        write!(f, "{msg}")
389    }
390}
391
392impl From<VulkanError> for Validated<VulkanError> {
393    fn from(err: VulkanError) -> Self {
394        Self::Error(err)
395    }
396}
397
398/// A wrapper for error types of functions that can return validation errors.
399#[derive(Clone)]
400pub enum Validated<E> {
401    /// A non-validation error occurred.
402    Error(E),
403
404    /// A validation error occurred.
405    ValidationError(Box<ValidationError>),
406}
407
408impl<E> Validated<E> {
409    /// Maps the inner `Error` value using the provided function, or does nothing if the value is
410    /// `ValidationError`.
411    #[inline]
412    pub fn map<F>(self, f: impl FnOnce(E) -> F) -> Validated<F> {
413        match self {
414            Self::Error(err) => Validated::Error(f(err)),
415            Self::ValidationError(err) => Validated::ValidationError(err),
416        }
417    }
418
419    #[inline]
420    fn map_validation(self, f: impl FnOnce(Box<ValidationError>) -> Box<ValidationError>) -> Self {
421        match self {
422            Self::Error(err) => Self::Error(err),
423            Self::ValidationError(err) => Self::ValidationError(f(err)),
424        }
425    }
426
427    /// Returns the inner `Error` value, or panics if it contains `ValidationError`.
428    #[inline(always)]
429    #[track_caller]
430    pub fn unwrap(self) -> E {
431        match self {
432            Self::Error(err) => err,
433            Self::ValidationError(err) => {
434                panic!(
435                    "called `Validated::unwrap` on a `ValidationError` value: {:?}",
436                    err
437                )
438            }
439        }
440    }
441}
442
443impl<E> Error for Validated<E>
444where
445    E: Error + 'static,
446{
447    fn source(&self) -> Option<&(dyn Error + 'static)> {
448        match self {
449            Self::Error(err) => Some(err),
450            Self::ValidationError(err) => Some(err),
451        }
452    }
453}
454
455impl<E> Display for Validated<E> {
456    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
457        match self {
458            Self::Error(_) => write!(f, "a non-validation error occurred"),
459            Self::ValidationError(_) => write!(f, "a validation error occurred"),
460        }
461    }
462}
463
464impl<E> Debug for Validated<E>
465where
466    E: Display,
467{
468    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
469        match self {
470            Self::Error(err) => write!(f, "a non-validation error occurred: {err}"),
471            Self::ValidationError(err) => {
472                write!(f, "a validation error occurred\n\nCaused by:\n    {err:?}")
473            }
474        }
475    }
476}
477
478impl<E> From<Box<ValidationError>> for Validated<E> {
479    fn from(err: Box<ValidationError>) -> Self {
480        Self::ValidationError(err)
481    }
482}
483
484/// The arguments or other context of a call to a Vulkan function were not valid.
485#[derive(Clone, Default)]
486pub struct ValidationError {
487    /// The context in which the problem exists (e.g. a specific parameter).
488    pub context: Cow<'static, str>,
489
490    /// A description of the problem.
491    pub problem: Cow<'static, str>,
492
493    /// If applicable, settings that the user could enable to avoid the problem in the future.
494    pub requires_one_of: RequiresOneOf,
495
496    /// *Valid Usage IDs* (VUIDs) in the Vulkan specification that relate to the problem.
497    pub vuids: &'static [&'static str],
498}
499
500impl ValidationError {
501    fn from_error<E: Error>(err: E) -> Self {
502        Self {
503            context: "".into(),
504            problem: err.to_string().into(),
505            requires_one_of: RequiresOneOf::default(),
506            vuids: &[],
507        }
508    }
509
510    fn add_context(mut self: Box<Self>, context: impl Into<Cow<'static, str>>) -> Box<Self> {
511        if self.context.is_empty() {
512            self.context = context.into();
513        } else {
514            self.context = format!("{}.{}", context.into(), self.context).into();
515        }
516
517        self
518    }
519
520    fn set_vuids(mut self: Box<Self>, vuids: &'static [&'static str]) -> Box<Self> {
521        self.vuids = vuids;
522        self
523    }
524}
525
526impl Debug for ValidationError {
527    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
528        if self.context.is_empty() {
529            write!(f, "{}", self.problem)?;
530        } else {
531            write!(f, "{}: {}", self.context, self.problem)?;
532        }
533
534        if !self.requires_one_of.is_empty() {
535            if self.context.is_empty() && self.problem.is_empty() {
536                write!(f, "{:?}", self.requires_one_of)?;
537            } else {
538                write!(f, "\n\n{:?}", self.requires_one_of)?;
539            }
540        }
541
542        if !self.vuids.is_empty() {
543            write!(f, "\n\nVulkan VUIDs:")?;
544
545            for vuid in self.vuids {
546                write!(f, "\n    {}", vuid)?;
547            }
548        }
549
550        Ok(())
551    }
552}
553
554impl Display for ValidationError {
555    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
556        if self.context.is_empty() {
557            write!(f, "{}", self.problem)?;
558        } else {
559            write!(f, "{}: {}", self.context, self.problem)?;
560        }
561
562        if !self.requires_one_of.is_empty() {
563            if self.problem.is_empty() {
564                write!(f, "{}", self.requires_one_of)?;
565            } else {
566                write!(f, " -- {}", self.requires_one_of)?;
567            }
568        }
569
570        if let Some((first, rest)) = self.vuids.split_first() {
571            write!(f, " (Vulkan VUIDs: {}", first)?;
572
573            for vuid in rest {
574                write!(f, ", {}", vuid)?;
575            }
576
577            write!(f, ")")?;
578        }
579
580        Ok(())
581    }
582}
583
584impl Error for ValidationError {}
585
586/// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow
587/// a given operation.
588#[derive(Clone, Copy, Default, PartialEq, Eq)]
589pub struct RequiresOneOf(pub &'static [RequiresAllOf]);
590
591impl RequiresOneOf {
592    /// Returns the number of alternatives.
593    pub fn len(&self) -> usize {
594        self.0.len()
595    }
596
597    /// Returns whether there are any alternatives.
598    pub fn is_empty(&self) -> bool {
599        self.0.is_empty()
600    }
601}
602
603impl Debug for RequiresOneOf {
604    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
605        write!(f, "Requires one of:")?;
606
607        for requires_all_of in self.0 {
608            write!(f, "\n    {}", requires_all_of)?;
609        }
610
611        Ok(())
612    }
613}
614
615impl Display for RequiresOneOf {
616    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
617        write!(f, "requires one of: ")?;
618
619        if let Some((first, rest)) = self.0.split_first() {
620            if first.0.len() > 1 {
621                write!(f, "({})", first)?;
622            } else {
623                write!(f, "{}", first)?;
624            }
625
626            for rest in rest {
627                if first.0.len() > 1 {
628                    write!(f, " or ({})", rest)?;
629                } else {
630                    write!(f, " or {}", rest)?;
631                }
632            }
633        }
634
635        Ok(())
636    }
637}
638
639/// Used in errors to indicate a set of requirements that all need to be available/enabled to allow
640/// a given operation.
641#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
642pub struct RequiresAllOf(pub &'static [Requires]);
643
644impl Display for RequiresAllOf {
645    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
646        if let Some((first, rest)) = self.0.split_first() {
647            write!(f, "{}", first)?;
648
649            for rest in rest {
650                write!(f, " + {}", rest)?;
651            }
652        }
653
654        Ok(())
655    }
656}
657
658/// Something that needs to be supported or enabled to allow a particular operation.
659#[derive(Clone, Copy, Debug, PartialEq, Eq)]
660pub enum Requires {
661    APIVersion(Version),
662    DeviceFeature(&'static str),
663    DeviceExtension(&'static str),
664    InstanceExtension(&'static str),
665}
666
667impl Display for Requires {
668    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
669        match self {
670            Requires::APIVersion(Version { major, minor, .. }) => {
671                write!(f, "Vulkan API version {}.{}", major, minor)
672            }
673            Requires::DeviceFeature(device_feature) => {
674                write!(f, "device feature `{}`", device_feature)
675            }
676            Requires::DeviceExtension(device_extension) => {
677                write!(f, "device extension `{}`", device_extension)
678            }
679            Requires::InstanceExtension(instance_extension) => {
680                write!(f, "instance extension `{}`", instance_extension)
681            }
682        }
683    }
684}
685
686/// A helper type for non-exhaustive structs.
687///
688/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only
689/// be constructed by calling a constructor function or `Default::default()`. The effect is similar
690/// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update
691/// syntax from being used.
692#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed
693pub struct NonExhaustive(pub(crate) ());