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::too_many_arguments,
14    clippy::missing_safety_doc,
15    clippy::upper_case_acronyms
16)]
17#![cfg_attr(docsrs, feature(doc_cfg))]
18#![cfg_attr(not(feature = "std"), no_std)]
19
20//! # Vulkan API
21//!
22//! <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/index.html>
23//!
24//! ## Examples
25//!
26//! ```no_run
27//! use ash::{vk, Entry};
28//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
29//! let entry = Entry::linked();
30//! let app_info = vk::ApplicationInfo {
31//!     api_version: vk::make_api_version(0, 1, 0, 0),
32//!     ..Default::default()
33//! };
34//! let create_info = vk::InstanceCreateInfo {
35//!     p_application_info: &app_info,
36//!     ..Default::default()
37//! };
38//! let instance = unsafe { entry.create_instance(&create_info, None)? };
39//! # Ok(()) }
40//! ```
41//!
42//! ## Getting started
43//!
44//! Load the Vulkan library linked at compile time using [`Entry::linked()`], or load it at runtime
45//! using [`Entry::load()`], which uses `libloading`. If you want to perform entry point loading
46//! yourself, call [`Entry::from_static_fn()`].
47//!
48//! ## Crate features
49//!
50//! * **debug** (default): Whether Vulkan structs should implement `Debug`.
51//! * **loaded** (default): Support searching for the Vulkan loader manually at runtime.
52//! * **linked**: Link the Vulkan loader at compile time.
53//! * **std** (default): Whether ash depends on the standard library (otherwise `alloc` is required)
54
55extern crate alloc;
56
57pub use crate::device::Device;
58pub use crate::entry::Entry;
59#[cfg(feature = "loaded")]
60pub use crate::entry::LoadingError;
61pub use crate::extensions_generated::*;
62pub use crate::instance::Instance;
63pub use crate::tables::*;
64
65mod device;
66mod entry;
67mod extensions_generated;
68mod instance;
69pub mod prelude;
70mod tables;
71pub mod util;
72/// Raw Vulkan bindings and types, generated from `vk.xml`
73#[macro_use]
74pub mod vk;
75
76// macros of vk need to be defined beforehand
77/// Hand-written ergonomic wrappers for extension functions
78mod extensions;
79
80pub trait RawPtr<T> {
81    fn as_raw_ptr(&self) -> *const T;
82}
83
84impl<'r, T> RawPtr<T> for Option<&'r T> {
85    fn as_raw_ptr(&self) -> *const T {
86        match *self {
87            Some(inner) => inner,
88            _ => ::core::ptr::null(),
89        }
90    }
91}
92
93/// Given a mutable raw pointer to a type with an `s_type` member such as [`vk::BaseOutStructure`],
94/// match on a set of Vulkan structures. The struct will be rebound to the given variable of the
95/// type of the given Vulkan structure.
96///
97/// Note that all match bodies have to be enclosed by curly braces due to macro parsing limitations.
98/// It is unfortunately not possible to write `x @ ash::vk::SomeStruct => one_line_expression(),`.
99///
100/// ```
101/// let mut info = ash::vk::DeviceCreateInfo::default();
102/// let info: *mut ash::vk::BaseOutStructure = <*mut _>::cast(&mut info);
103/// unsafe {
104///     ash::match_out_struct!(match info {
105///         info @ ash::vk::DeviceQueueCreateInfo => {
106///             dbg!(&info); // Unreachable
107///         }
108///         info @ ash::vk::DeviceCreateInfo => {
109///             dbg!(&info);
110///         }
111///     })
112/// }
113/// ```
114///
115/// In addition this macro propagates implicit return values just like normal `match` blocks, as
116/// long as a default value or expression is provided in the "any" match arm
117/// (`_ => { some_value() }`). For the time being said arm must be wrapped in curly braces; an
118/// expression like `_ => None` is not yet supported.
119///
120/// ```
121/// # let mut info = ash::vk::DeviceCreateInfo::default();
122/// # let info: *mut ash::vk::BaseOutStructure = <*mut _>::cast(&mut info);
123/// let device_create_flags: Option<ash::vk::DeviceCreateFlags> = unsafe {
124///     ash::match_out_struct!(match info {
125///         info @ ash::vk::DeviceQueueCreateInfo => {
126///             dbg!(&info); // Unreachable
127///             Some(ash::vk::DeviceCreateFlags::empty())
128///         }
129///         info @ ash::vk::DeviceCreateInfo => {
130///             dbg!(&info);
131///             Some(info.flags)
132///         }
133///         _ => {
134///             None
135///         }
136///     })
137/// };
138/// ```
139#[macro_export]
140macro_rules! match_out_struct {
141    (match $p:ident { $($bind:ident @ $ty:path => $body:block $(,)?)+ $(_ => $any:block $(,)?)? }) => {
142        match core::ptr::addr_of!((*$p).s_type).read() {
143            $(<$ty as $crate::vk::TaggedStructure>::STRUCTURE_TYPE => {
144                let $bind = $p
145                    .cast::<$ty>()
146                    .as_mut()
147                    .unwrap();
148                $body
149            }),+
150            _ => { $($any)? }
151        }
152    };
153}
154
155/// Given an immutable raw pointer to a type with an `s_type` member such as [`vk::BaseInStructure`],
156/// match on a set of Vulkan structures. The struct will be rebound to the given variable of the
157/// type of the given Vulkan structure.
158///
159/// Note that all match bodies have to be enclosed by curly braces due to macro parsing limitations.
160/// It is unfortunately not possible to write `x @ ash::vk::SomeStruct => one_line_expression(),`.
161///
162/// ```
163/// let info = ash::vk::DeviceCreateInfo::default();
164/// let info: *const ash::vk::BaseInStructure = <*const _>::cast(&info);
165/// unsafe {
166///     ash::match_in_struct!(match info {
167///         info @ ash::vk::DeviceQueueCreateInfo => {
168///             dbg!(&info); // Unreachable
169///         }
170///         info @ ash::vk::DeviceCreateInfo => {
171///             dbg!(&info);
172///         }
173///     })
174/// }
175/// ```
176///
177/// See the [`match_out_struct!`] documentation for an example with implicit return values.
178#[macro_export]
179macro_rules! match_in_struct {
180    (match $p:ident { $($bind:ident @ $ty:path => $body:block $(,)?)+ $(_ => $any:block $(,)?)? }) => {
181        match core::ptr::addr_of!((*$p).s_type).read() {
182            $(<$ty as $crate::vk::TaggedStructure>::STRUCTURE_TYPE => {
183                let $bind = $p
184                    .cast::<$ty>()
185                    .as_ref()
186                    .unwrap();
187                $body
188            }),+
189            _ => { $($any)? }
190        }
191    };
192}
193
194#[cfg(test)]
195mod tests {
196    use super::vk;
197    use alloc::vec::Vec;
198    #[test]
199    fn test_ptr_chains() {
200        let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default();
201        let mut corner = vk::PhysicalDeviceCornerSampledImageFeaturesNV::default();
202        let chain = alloc::vec![
203            <*mut _>::cast(&mut variable_pointers),
204            <*mut _>::cast(&mut corner),
205        ];
206        let mut device_create_info = vk::DeviceCreateInfo::default()
207            .push_next(&mut corner)
208            .push_next(&mut variable_pointers);
209        let chain2: Vec<*mut vk::BaseOutStructure<'_>> = unsafe {
210            vk::ptr_chain_iter(&mut device_create_info)
211                .skip(1)
212                .collect()
213        };
214        assert_eq!(chain, chain2);
215    }
216}