#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
#![warn(
rust_2018_idioms,
rust_2021_compatibility,
clippy::trivially_copy_pass_by_ref
)]
#![allow(
clippy::arc_with_non_send_sync,
clippy::collapsible_else_if,
clippy::collapsible_if,
clippy::derivable_impls, // TODO: remove
clippy::large_enum_variant,
clippy::len_without_is_empty,
clippy::missing_safety_doc, // TODO: remove
clippy::module_inception,
clippy::mutable_key_type,
clippy::needless_borrowed_reference,
clippy::new_without_default,
clippy::nonminimal_bool,
clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error
clippy::result_large_err,
clippy::too_many_arguments,
clippy::type_complexity,
clippy::vec_box,
clippy::wrong_self_convention
)]
pub use ash::vk::Handle;
use bytemuck::{Pod, Zeroable};
pub use half;
pub use library::{LoadingError, VulkanLibrary};
use std::{
borrow::Cow,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
num::NonZeroU64,
ops::Deref,
sync::Arc,
};
pub use {extensions::ExtensionProperties, version::Version};
#[macro_use]
mod tests;
#[macro_use]
mod extensions;
pub mod acceleration_structure;
pub mod buffer;
pub mod command_buffer;
pub mod deferred;
pub mod descriptor_set;
pub mod device;
pub mod display;
pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
mod cache;
mod fns;
pub mod image;
pub mod instance;
pub mod library;
mod macros;
pub mod memory;
pub mod padded;
pub mod pipeline;
pub mod query;
mod range_map;
pub mod range_set;
pub mod shader;
pub mod swapchain;
pub mod sync;
pub use ash::vk::DeviceSize;
pub type NonZeroDeviceSize = NonZeroU64;
pub use ash::vk::DeviceAddress;
pub type NonNullDeviceAddress = NonZeroU64;
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Zeroable, Pod)]
#[repr(transparent)]
pub struct Packed24_8(u32);
impl Packed24_8 {
#[inline]
pub fn new(low_24: u32, high_8: u8) -> Self {
Self((low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24))
}
#[inline]
pub fn low_24(&self) -> u32 {
self.0 & 0xffffff
}
#[inline]
pub fn high_8(&self) -> u8 {
(self.0 >> 24) as u8
}
}
#[allow(unused_extern_crates)]
extern crate self as vulkano;
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
unsafe impl<T: ?Sized> SafeDeref for Box<T> {}
pub unsafe trait VulkanObject {
type Handle: ash::vk::Handle;
fn handle(&self) -> Self::Handle;
}
unsafe impl<T, U> VulkanObject for T
where
T: SafeDeref<Target = U>,
U: VulkanObject + ?Sized,
{
type Handle = U::Handle;
#[inline]
fn handle(&self) -> Self::Handle {
(**self).handle()
}
}
#[repr(transparent)]
struct DebugWrapper<T>(T);
impl<T> Debug for DebugWrapper<T>
where
T: Debug + VulkanObject,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(f, "0x{:x}", self.0.handle().as_raw())
}
}
impl<T> Deref for DebugWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
include!(concat!(env!("OUT_DIR"), "/errors.rs"));
impl Error for VulkanError {}
impl Display for VulkanError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let msg = match self {
VulkanError::NotReady => "a resource is not yet ready",
VulkanError::Timeout => "an operation has not completed in the specified time",
VulkanError::OutOfHostMemory => "a host memory allocation has failed",
VulkanError::OutOfDeviceMemory => "a device memory allocation has failed",
VulkanError::InitializationFailed => {
"initialization of an object could not be completed for implementation-specific \
reasons"
}
VulkanError::DeviceLost => "the logical or physical device has been lost",
VulkanError::MemoryMapFailed => "mapping of a memory object has failed",
VulkanError::LayerNotPresent => {
"a requested layer is not present or could not be loaded"
}
VulkanError::ExtensionNotPresent => "a requested extension is not supported",
VulkanError::FeatureNotPresent => "a requested feature is not supported",
VulkanError::IncompatibleDriver => {
"the requested version of Vulkan is not supported by the driver or is otherwise \
incompatible for implementation-specific reasons"
}
VulkanError::TooManyObjects => "too many objects of the type have already been created",
VulkanError::FormatNotSupported => "a requested format is not supported on this device",
VulkanError::FragmentedPool => {
"a pool allocation has failed due to fragmentation of the pool's memory"
}
VulkanError::Unknown => {
"an unknown error has occurred; either the application has provided invalid input, \
or an implementation failure has occurred"
}
VulkanError::OutOfPoolMemory => "a pool memory allocation has failed",
VulkanError::InvalidExternalHandle => {
"an external handle is not a valid handle of the specified type"
}
VulkanError::Fragmentation => {
"a descriptor pool creation has failed due to fragmentation"
}
VulkanError::InvalidOpaqueCaptureAddress => {
"a buffer creation or memory allocation failed because the requested address is \
not available. A shader group handle assignment failed because the requested \
shader group handle information is no longer valid"
}
VulkanError::IncompatibleDisplay => {
"the display used by a swapchain does not use the same presentable image layout, \
or is incompatible in a way that prevents sharing an image"
}
VulkanError::NotPermitted => "a requested operation was not permitted",
VulkanError::SurfaceLost => "a surface is no longer available",
VulkanError::NativeWindowInUse => {
"the requested window is already in use by Vulkan or another API in a manner which \
prevents it from being used again"
}
VulkanError::OutOfDate => {
"a surface has changed in such a way that it is no longer compatible with the \
swapchain, and further presentation requests using the swapchain will fail"
}
VulkanError::InvalidVideoStdParameters => {
"the provided Video Std parameters do not adhere to the requirements of the used \
video compression standard"
}
VulkanError::ValidationFailed => "validation failed",
VulkanError::FullScreenExclusiveModeLost => {
"an operation on a swapchain created with application controlled full-screen \
access failed as it did not have exclusive full-screen access"
}
VulkanError::InvalidDrmFormatModifierPlaneLayout => {
"the requested DRM format modifier plane layout is invalid"
}
VulkanError::InvalidShader => "one or more shaders failed to compile or link",
VulkanError::ImageUsageNotSupported => "the requested `ImageUsage` are not supported",
VulkanError::VideoPictureLayoutNotSupported => {
"the requested video picture layout is not supported"
}
VulkanError::VideoProfileOperationNotSupported => {
"a video profile operation specified via `VideoProfileInfo::video_codec_operation` \
is not supported"
}
VulkanError::VideoProfileFormatNotSupported => {
"format parameters in a requested `VideoProfileInfo` chain are not supported"
}
VulkanError::VideoProfileCodecNotSupported => {
"codec-specific parameters in a requested `VideoProfileInfo` chain are not \
supported"
}
VulkanError::VideoStdVersionNotSupported => {
"the specified video Std header version is not supported"
}
VulkanError::CompressionExhausted => {
"an image creation failed because internal resources required for compression are \
exhausted"
}
VulkanError::Unnamed(result) => {
return write!(f, "unnamed error, VkResult value {}", result.as_raw());
}
};
write!(f, "{msg}")
}
}
impl From<VulkanError> for Validated<VulkanError> {
fn from(err: VulkanError) -> Self {
Self::Error(err)
}
}
#[derive(Clone)]
pub enum Validated<E> {
Error(E),
ValidationError(Box<ValidationError>),
}
impl<E> Validated<E> {
pub fn map<F>(self, f: impl FnOnce(E) -> F) -> Validated<F> {
match self {
Self::Error(err) => Validated::Error(f(err)),
Self::ValidationError(err) => Validated::ValidationError(err),
}
}
fn map_validation(self, f: impl FnOnce(Box<ValidationError>) -> Box<ValidationError>) -> Self {
match self {
Self::Error(err) => Self::Error(err),
Self::ValidationError(err) => Self::ValidationError(f(err)),
}
}
pub fn unwrap(self) -> E {
match self {
Self::Error(err) => err,
Self::ValidationError(err) => {
panic!(
"called `Validated::unwrap` on a `ValidationError` value: {:?}",
err
)
}
}
}
}
impl<E> Error for Validated<E>
where
E: Error + 'static,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Error(err) => Some(err),
Self::ValidationError(err) => Some(err),
}
}
}
impl<E> Display for Validated<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::Error(_) => write!(f, "a non-validation error occurred"),
Self::ValidationError(_) => write!(f, "a validation error occurred"),
}
}
}
impl<E> Debug for Validated<E>
where
E: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::Error(err) => write!(f, "a non-validation error occurred: {err}"),
Self::ValidationError(err) => {
write!(f, "a validation error occurred\n\nCaused by:\n {err:?}")
}
}
}
}
impl<E> From<Box<ValidationError>> for Validated<E> {
fn from(err: Box<ValidationError>) -> Self {
Self::ValidationError(err)
}
}
#[derive(Clone, Default)]
pub struct ValidationError {
pub context: Cow<'static, str>,
pub problem: Cow<'static, str>,
pub requires_one_of: RequiresOneOf,
pub vuids: &'static [&'static str],
}
impl ValidationError {
fn from_error<E: Error>(err: E) -> Self {
Self {
context: "".into(),
problem: err.to_string().into(),
requires_one_of: RequiresOneOf::default(),
vuids: &[],
}
}
fn add_context(mut self: Box<Self>, context: impl Into<Cow<'static, str>>) -> Box<Self> {
if self.context.is_empty() {
self.context = context.into();
} else {
self.context = format!("{}.{}", context.into(), self.context).into();
}
self
}
fn set_vuids(mut self: Box<Self>, vuids: &'static [&'static str]) -> Box<Self> {
self.vuids = vuids;
self
}
}
impl Debug for ValidationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
if self.context.is_empty() {
write!(f, "{}", self.problem)?;
} else {
write!(f, "{}: {}", self.context, self.problem)?;
}
if !self.requires_one_of.is_empty() {
if self.context.is_empty() && self.problem.is_empty() {
write!(f, "{:?}", self.requires_one_of)?;
} else {
write!(f, "\n\n{:?}", self.requires_one_of)?;
}
}
if !self.vuids.is_empty() {
write!(f, "\n\nVulkan VUIDs:")?;
for vuid in self.vuids {
write!(f, "\n {}", vuid)?;
}
}
Ok(())
}
}
impl Display for ValidationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
if self.context.is_empty() {
write!(f, "{}", self.problem)?;
} else {
write!(f, "{}: {}", self.context, self.problem)?;
}
if !self.requires_one_of.is_empty() {
if self.problem.is_empty() {
write!(f, "{}", self.requires_one_of)?;
} else {
write!(f, " -- {}", self.requires_one_of)?;
}
}
if let Some((first, rest)) = self.vuids.split_first() {
write!(f, " (Vulkan VUIDs: {}", first)?;
for vuid in rest {
write!(f, ", {}", vuid)?;
}
write!(f, ")")?;
}
Ok(())
}
}
impl Error for ValidationError {}
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct RequiresOneOf(pub &'static [RequiresAllOf]);
impl RequiresOneOf {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Debug for RequiresOneOf {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(f, "Requires one of:")?;
for requires_all_of in self.0 {
write!(f, "\n {}", requires_all_of)?;
}
Ok(())
}
}
impl Display for RequiresOneOf {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(f, "requires one of: ")?;
if let Some((first, rest)) = self.0.split_first() {
if first.0.len() > 1 {
write!(f, "({})", first)?;
} else {
write!(f, "{}", first)?;
}
for rest in rest {
if first.0.len() > 1 {
write!(f, " or ({})", rest)?;
} else {
write!(f, " or {}", rest)?;
}
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RequiresAllOf(pub &'static [Requires]);
impl Display for RequiresAllOf {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
if let Some((first, rest)) = self.0.split_first() {
write!(f, "{}", first)?;
for rest in rest {
write!(f, " + {}", rest)?;
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Requires {
APIVersion(Version),
Feature(&'static str),
DeviceExtension(&'static str),
InstanceExtension(&'static str),
}
impl Display for Requires {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Requires::APIVersion(Version { major, minor, .. }) => {
write!(f, "Vulkan API version {}.{}", major, minor)
}
Requires::Feature(feature) => write!(f, "feature `{}`", feature),
Requires::DeviceExtension(device_extension) => {
write!(f, "device extension `{}`", device_extension)
}
Requires::InstanceExtension(instance_extension) => {
write!(f, "instance extension `{}`", instance_extension)
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct NonExhaustive(pub(crate) ());