Skip to main content

tracel_ash/
lib.rs

1#![warn(
2    clippy::alloc_instead_of_core,
3    clippy::use_self,
4    clippy::std_instead_of_alloc,
5    clippy::std_instead_of_core,
6    deprecated_in_future,
7    rust_2018_idioms,
8    trivial_casts,
9    trivial_numeric_casts,
10    unused_qualifications
11)]
12#![allow(
13    clippy::missing_safety_doc,
14    clippy::missing_transmute_annotations,
15    clippy::too_many_arguments,
16    clippy::upper_case_acronyms
17)]
18#![cfg_attr(docsrs, feature(doc_cfg))]
19#![cfg_attr(not(feature = "std"), no_std)]
20
21//! # Vulkan API
22//!
23//! <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/index.html>
24//!
25//! ## Examples
26//!
27//! ```ignore
28//! use ash::{vk, Entry};
29//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
30//! let entry = Entry::linked();
31//! let app_info = vk::ApplicationInfo {
32//!     api_version: vk::make_api_version(0, 1, 0, 0),
33//!     ..Default::default()
34//! };
35//! let create_info = vk::InstanceCreateInfo {
36//!     p_application_info: &app_info,
37//!     ..Default::default()
38//! };
39//! let instance = unsafe { entry.create_instance(&create_info, None)? };
40//! # Ok(()) }
41//! ```
42//!
43//! ## Getting started
44//!
45//! Load the Vulkan library linked at compile time using [`ash::Entry::linked()`], or load it at runtime
46//! using [`ash::Entry::load()`], which uses `libloading`. If you want to perform entry point loading
47//! yourself, call [`ash::Entry::from_static_fn()`].
48//!
49//! ## Crate features
50//!
51//! * **debug** (default): Whether Vulkan structs should implement `Debug`.
52//! * **loaded** (default): Support searching for the Vulkan loader manually at runtime.
53//! * **linked**: Link the Vulkan loader at compile time.
54//! * **std** (default): Whether ash depends on the standard library (otherwise `alloc` is required)
55
56extern crate alloc;
57
58use alloc::vec::Vec;
59use core::{mem, ptr};
60
61pub use crate::extensions_generated::*;
62pub use crate::tables::*;
63
64mod extensions_generated;
65mod tables;
66/// Raw Vulkan bindings and types, generated from `vk.xml`
67#[macro_use]
68pub mod vk;
69
70// macros of vk need to be defined beforehand
71/// Hand-written ergonomic wrappers for extension functions
72mod extensions;
73
74/// Compat with crates.io version of ash
75mod compat;
76
77pub trait RawPtr<T> {
78    fn to_raw_ptr(self) -> *const T;
79}
80
81impl<T> RawPtr<T> for Option<&T> {
82    fn to_raw_ptr(self) -> *const T {
83        match self {
84            Some(inner) => inner,
85            None => ptr::null(),
86        }
87    }
88}
89
90pub trait RawMutPtr<T> {
91    unsafe fn to_raw_mut_ptr(self) -> *mut T;
92}
93
94impl<T> RawMutPtr<T> for Option<&mut T> {
95    unsafe fn to_raw_mut_ptr(self) -> *mut T {
96        match self {
97            Some(inner) => inner,
98            None => ptr::null_mut(),
99        }
100    }
101}
102
103/// Given an immutable raw pointer to a type with an `s_type` member such as [`vk::BaseInStructure`],
104/// match on a set of Vulkan structures. The struct will be rebound to the given variable of the
105/// type of the given Vulkan structure.
106///
107/// Note that all match bodies have to be enclosed by curly braces due to macro parsing limitations.
108/// It is unfortunately not possible to write `x @ ash::vk::SomeStruct => one_line_expression(),`.
109///
110/// ```
111/// let info = ash::vk::DeviceCreateInfo::default();
112/// let info: *const ash::vk::BaseInStructure = <*const _>::cast(&info);
113/// unsafe {
114///     ash::match_in_struct!(match info {
115///         info @ ash::vk::DeviceQueueCreateInfo => {
116///             dbg!(&info); // Unreachable
117///         }
118///         info @ ash::vk::DeviceCreateInfo => {
119///             dbg!(&info);
120///         }
121///     })
122/// }
123/// ```
124///
125/// See the `match_out_struct!` documentation for an example with implicit return values.
126#[macro_export]
127macro_rules! match_in_struct {
128    (match $p:ident { $($bind:ident @ $ty:path => $body:block $(,)?)+ $(_ => $any:block $(,)?)? }) => {
129        match core::ptr::addr_of!((*$p).s_type).read() {
130            $(<$ty as $crate::vk::TaggedStructure>::STRUCTURE_TYPE => {
131                let $bind = $p
132                    .cast::<$ty>()
133                    .as_ref()
134                    .unwrap();
135                $body
136            }),+
137            _ => { $($any)? }
138        }
139    };
140}
141
142pub type VkResult<T> = Result<T, vk::Result>;
143
144impl vk::Result {
145    #[inline]
146    pub fn result(self) -> VkResult<()> {
147        self.result_with_success(())
148    }
149
150    #[inline]
151    pub fn result_with_success<T>(self, v: T) -> VkResult<T> {
152        match self {
153            Self::SUCCESS => Ok(v),
154            _ => Err(self),
155        }
156    }
157
158    #[inline]
159    pub unsafe fn assume_init_on_success<T>(self, v: mem::MaybeUninit<T>) -> VkResult<T> {
160        self.result().map(move |()| v.assume_init())
161    }
162
163    #[inline]
164    pub unsafe fn set_vec_len_on_success<T>(self, mut v: Vec<T>, len: usize) -> VkResult<Vec<T>> {
165        self.result().map(move |()| {
166            v.set_len(len);
167            v
168        })
169    }
170}
171
172/// Repeatedly calls `f` until it does not return [`vk::Result::INCOMPLETE`] anymore, ensuring all
173/// available data has been read into the vector.
174///
175/// See for example [`vkEnumerateInstanceExtensionProperties`]: the number of available items may
176/// change between calls; [`vk::Result::INCOMPLETE`] is returned when the count increased (and the
177/// vector is not large enough after querying the initial size), requiring Ash to try again.
178///
179/// [`vkEnumerateInstanceExtensionProperties`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html
180pub(crate) unsafe fn read_into_uninitialized_vector<N: Copy + Default + TryInto<usize>, T>(
181    f: impl Fn(&mut N, *mut T) -> vk::Result,
182) -> VkResult<Vec<T>>
183where
184    <N as TryInto<usize>>::Error: core::fmt::Debug,
185{
186    loop {
187        let mut count = N::default();
188        f(&mut count, ptr::null_mut()).result()?;
189        let mut data =
190            Vec::with_capacity(count.try_into().expect("`N` failed to convert to `usize`"));
191
192        let err_code = f(&mut count, data.as_mut_ptr());
193        if err_code != vk::Result::INCOMPLETE {
194            break err_code.set_vec_len_on_success(
195                data,
196                count.try_into().expect("`N` failed to convert to `usize`"),
197            );
198        }
199    }
200}