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}