Skip to main content

jay_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 jay_ash as ash;
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 [`Entry::linked()`], or load it at runtime
46//! using [`Entry::load()`], which uses `libloading`. If you want to perform entry point loading
47//! yourself, call [`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
58pub use crate::device::Device;
59pub use crate::entry::Entry;
60#[cfg(feature = "loaded")]
61pub use crate::entry::LoadingError;
62pub use crate::extensions_generated::*;
63pub use crate::instance::Instance;
64pub use crate::tables::*;
65
66mod device;
67mod entry;
68mod extensions_generated;
69mod instance;
70pub mod prelude;
71mod tables;
72pub mod util;
73/// Raw Vulkan bindings and types, generated from `vk.xml`
74#[macro_use]
75pub mod vk;
76
77// macros of vk need to be defined beforehand
78/// Hand-written ergonomic wrappers for extension functions
79mod extensions;
80
81pub trait RawPtr<T> {
82    fn as_raw_ptr(&self) -> *const T;
83}
84
85impl<T> RawPtr<T> for Option<&T> {
86    fn as_raw_ptr(&self) -> *const T {
87        match *self {
88            Some(inner) => inner,
89            _ => ::core::ptr::null(),
90        }
91    }
92}
93
94/// Given a mutable raw pointer to a type with an `s_type` member such as [`vk::BaseOutStructure`],
95/// match on a set of Vulkan structures. The struct will be rebound to the given variable of the
96/// type of the given Vulkan structure.
97///
98/// Note that all match bodies have to be enclosed by curly braces due to macro parsing limitations.
99/// It is unfortunately not possible to write `x @ ash::vk::SomeStruct => one_line_expression(),`.
100///
101/// ```
102/// # use jay_ash as ash;
103/// let mut info = ash::vk::DeviceCreateInfo::default();
104/// let info: *mut ash::vk::BaseOutStructure = <*mut _>::cast(&mut info);
105/// unsafe {
106///     ash::match_out_struct!(match info {
107///         info @ ash::vk::DeviceQueueCreateInfo => {
108///             dbg!(&info); // Unreachable
109///         }
110///         info @ ash::vk::DeviceCreateInfo => {
111///             dbg!(&info);
112///         }
113///     })
114/// }
115/// ```
116///
117/// In addition this macro propagates implicit return values just like normal `match` blocks, as
118/// long as a default value or expression is provided in the "any" match arm
119/// (`_ => { some_value() }`). For the time being said arm must be wrapped in curly braces; an
120/// expression like `_ => None` is not yet supported.
121///
122/// ```
123/// # use jay_ash as ash;
124/// # let mut info = ash::vk::DeviceCreateInfo::default();
125/// # let info: *mut ash::vk::BaseOutStructure = <*mut _>::cast(&mut info);
126/// let device_create_flags: Option<ash::vk::DeviceCreateFlags> = unsafe {
127///     ash::match_out_struct!(match info {
128///         info @ ash::vk::DeviceQueueCreateInfo => {
129///             dbg!(&info); // Unreachable
130///             Some(ash::vk::DeviceCreateFlags::empty())
131///         }
132///         info @ ash::vk::DeviceCreateInfo => {
133///             dbg!(&info);
134///             Some(info.flags)
135///         }
136///         _ => {
137///             None
138///         }
139///     })
140/// };
141/// ```
142#[macro_export]
143macro_rules! match_out_struct {
144    (match $p:ident { $($bind:ident @ $ty:path => $body:block $(,)?)+ $(_ => $any:block $(,)?)? }) => {
145        match core::ptr::addr_of!((*$p).s_type).read() {
146            $(<$ty as $crate::vk::TaggedStructure>::STRUCTURE_TYPE => {
147                let $bind = $p
148                    .cast::<$ty>()
149                    .as_mut()
150                    .unwrap();
151                $body
152            }),+
153            _ => { $($any)? }
154        }
155    };
156}
157
158/// Given an immutable raw pointer to a type with an `s_type` member such as [`vk::BaseInStructure`],
159/// match on a set of Vulkan structures. The struct will be rebound to the given variable of the
160/// type of the given Vulkan structure.
161///
162/// Note that all match bodies have to be enclosed by curly braces due to macro parsing limitations.
163/// It is unfortunately not possible to write `x @ ash::vk::SomeStruct => one_line_expression(),`.
164///
165/// ```
166/// # use jay_ash as ash;
167/// let info = ash::vk::DeviceCreateInfo::default();
168/// let info: *const ash::vk::BaseInStructure = <*const _>::cast(&info);
169/// unsafe {
170///     ash::match_in_struct!(match info {
171///         info @ ash::vk::DeviceQueueCreateInfo => {
172///             dbg!(&info); // Unreachable
173///         }
174///         info @ ash::vk::DeviceCreateInfo => {
175///             dbg!(&info);
176///         }
177///     })
178/// }
179/// ```
180///
181/// See the [`match_out_struct!`] documentation for an example with implicit return values.
182#[macro_export]
183macro_rules! match_in_struct {
184    (match $p:ident { $($bind:ident @ $ty:path => $body:block $(,)?)+ $(_ => $any:block $(,)?)? }) => {
185        match core::ptr::addr_of!((*$p).s_type).read() {
186            $(<$ty as $crate::vk::TaggedStructure>::STRUCTURE_TYPE => {
187                let $bind = $p
188                    .cast::<$ty>()
189                    .as_ref()
190                    .unwrap();
191                $body
192            }),+
193            _ => { $($any)? }
194        }
195    };
196}
197
198#[cfg(test)]
199mod tests {
200    use super::vk;
201    use alloc::vec::Vec;
202    #[test]
203    fn test_ptr_chains() {
204        let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default();
205        let mut corner = vk::PhysicalDeviceCornerSampledImageFeaturesNV::default();
206        let chain = alloc::vec![
207            <*mut _>::cast(&mut variable_pointers),
208            <*mut _>::cast(&mut corner),
209        ];
210        let mut device_create_info = vk::DeviceCreateInfo::default()
211            .push_next(&mut corner)
212            .push_next(&mut variable_pointers);
213        let chain2: Vec<*mut vk::BaseOutStructure<'_>> = unsafe {
214            vk::ptr_chain_iter(&mut device_create_info)
215                .skip(1)
216                .collect()
217        };
218        assert_eq!(chain, chain2);
219    }
220}