vulkanalia/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Vulkan bindings for Rust.
4//!
5//! For a detailed guide on how this crate (thinly) wraps the Vulkan API, see
6//! the `API Concepts` section of the `Overview` chapter of the `vulkanalia`
7//! Vulkan tutorial which can be found
8//! [here](https://kylemayes.github.io/vulkanalia/overview.html#api-concepts).
9//!
10//! For the classic triangle example, see
11//! [here](https://github.com/KyleMayes/vulkanalia/tree/master/examples/src).
12//!
13//! #### Quick Tips
14//!
15//! ##### 1. Use builder structs, but don't `build` them unless you need to!
16//!
17//! `vulkanalia`'s implementation of Vulkan structs like
18//! [`vk::InstanceCreateInfo`] each have associated builder structs that make
19//! constructing instances of these structs simple (
20//! [`vk::InstanceCreateInfoBuilder`] in this case).
21//!
22//! You can call the `build` method on a builder struct to extract the Vulkan
23//! struct, but this discards valuable information! Builder structs are often
24//! parameterized with lifetimes that ensure that the values passed to the
25//! builder struct live at least as long as the builder struct itself.
26//!
27//! Any Vulkan command in `vulkanalia` that takes a Vulkan struct like
28//! [`vk::InstanceCreateInfo`] as an argument can also accept the associated
29//! builder struct as an argument. This means you can skip those `build` calls
30//! and directly invoke Vulkan commands with your builder structs so that the
31//! lifetimes can protect you from an entire class of bugs.
32//!
33//! __Don't__
34//!
35//! ```ignore
36//! let info = vk::InstanceCreateInfo::builder()
37//!     .enabled_extension_names(&vec![/* 3 extension names */])
38//!     .build();
39//!
40//! let instance = entry.create_instance(&info, None).unwrap();
41//! // 💥: this will (hopefully) crash when the Vulkan implementation attempts
42//! // to read a now deallocated list of extension names
43//! ```
44//!
45//! __Do__
46//!
47//! ```ignore
48//! let info = vk::InstanceCreateInfo::builder()
49//!     .enabled_extension_names(&vec![/* 3 extension names */]);
50//!     // Look ma, no `build`!
51//!
52//! let instance = entry.create_instance(&info, None).unwrap();
53//! // 🦀: this will raise an error at compiletime about how the reference to
54//! // the temporary list of extension names doesn't live long enough
55//! ```
56
57#![cfg_attr(not(feature = "std"), no_std)]
58#![cfg_attr(feature = "no_std_error", feature(error_in_core))]
59#![allow(unsafe_op_in_unsafe_fn)]
60
61extern crate alloc;
62
63pub mod bytecode;
64pub mod chain;
65pub mod loader;
66pub mod vk;
67
68#[cfg(feature = "window")]
69pub mod window;
70
71use alloc::boxed::Box;
72use alloc::collections::btree_set::BTreeSet;
73use alloc::sync::Arc;
74use core::ffi::c_char;
75use core::fmt;
76use core::mem;
77use core::slice;
78
79use self::loader::{Loader, LoaderError};
80use self::prelude::v1_0::*;
81use self::vk::{DeviceCommands, EntryCommands, InstanceCommands, StaticCommands};
82
83/// Preludes.
84pub mod prelude {
85    /// Vulkan 1.0 prelude.
86    pub mod v1_0 {
87        pub use crate::vk;
88        pub use crate::vk::{DeviceV1_0, EntryV1_0, InstanceV1_0};
89        pub use crate::vk::{Handle, HasBuilder};
90        pub use crate::{Device, Entry, Instance, VkResult, VkSuccessResult};
91    }
92
93    /// Vulkan 1.1 prelude.
94    pub mod v1_1 {
95        pub use crate::prelude::v1_0::*;
96        pub use crate::vk::{DeviceV1_1, EntryV1_1, InstanceV1_1};
97    }
98
99    /// Vulkan 1.2 prelude.
100    pub mod v1_2 {
101        pub use crate::prelude::v1_1::*;
102        pub use crate::vk::{DeviceV1_2, EntryV1_2, InstanceV1_2};
103    }
104
105    /// Vulkan 1.3 prelude.
106    pub mod v1_3 {
107        pub use crate::prelude::v1_2::*;
108        pub use crate::vk::{DeviceV1_3, EntryV1_3, InstanceV1_3};
109    }
110
111    /// Vulkan 1.4 prelude.
112    pub mod v1_4 {
113        pub use crate::prelude::v1_3::*;
114        pub use crate::vk::{DeviceV1_4, EntryV1_4, InstanceV1_4};
115    }
116}
117
118/// The result of a executing a fallible Vulkan command.
119pub type VkResult<T> = Result<T, vk::ErrorCode>;
120/// The result of a executing a fallible Vulkan command with multiple success codes.
121pub type VkSuccessResult<T> = Result<(T, vk::SuccessCode), vk::ErrorCode>;
122
123/// An extension trait for [`vk::Result`].
124pub trait ResultExt {
125    /// Converts a [`vk::Result`] into a [`VkResult`].
126    fn result(self) -> VkResult<()>;
127}
128
129impl ResultExt for vk::Result {
130    #[inline]
131    fn result(self) -> VkResult<()> {
132        match self {
133            vk::Result::SUCCESS => Ok(()),
134            error => Err(error.into()),
135        }
136    }
137}
138
139/// A Vulkan version.
140#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
141pub struct Version {
142    /// The major version (the `x` in `x.y.z`).
143    pub major: u32,
144    /// The minor version (the `y` in `x.y.z`).
145    pub minor: u32,
146    /// The patch version (the `z` in `x.y.z`).
147    ///
148    /// If the version of Vulkan is not at least `1.1.0`, then the patch version
149    /// will not be known due to the `vkEnumerateInstanceVersion` function not
150    /// being available. In this case this field is set to `0`.
151    pub patch: u32,
152}
153
154impl Version {
155    /// The version for Vulkan `1.0.x`.
156    pub const V1_0_0: Version = Version::new(1, 0, 0);
157    /// The version for Vulkan `1.1.0`.
158    pub const V1_1_0: Version = Version::new(1, 1, 0);
159    /// The version for Vulkan `1.2.0`.
160    pub const V1_2_0: Version = Version::new(1, 2, 0);
161    /// The version for Vulkan `1.3.0`.
162    pub const V1_3_0: Version = Version::new(1, 3, 0);
163    /// The version for Vulkan `1.4.0`.
164    pub const V1_4_0: Version = Version::new(1, 4, 0);
165
166    /// Constructs a new Vulkan version.
167    pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
168        Self {
169            major,
170            minor,
171            patch,
172        }
173    }
174}
175
176impl Default for Version {
177    #[inline]
178    fn default() -> Self {
179        Self::V1_0_0
180    }
181}
182
183impl fmt::Display for Version {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
186    }
187}
188
189impl From<u32> for Version {
190    #[inline]
191    fn from(version: u32) -> Self {
192        Self::new(
193            vk::version_major(version),
194            vk::version_minor(version),
195            vk::version_patch(version),
196        )
197    }
198}
199
200impl From<Version> for u32 {
201    fn from(version: Version) -> Self {
202        vk::make_version(version.major, version.minor, version.patch)
203    }
204}
205
206impl From<(u32, u32, u32)> for Version {
207    fn from((major, minor, patch): (u32, u32, u32)) -> Self {
208        Self::new(major, minor, patch)
209    }
210}
211
212impl From<Version> for (u32, u32, u32) {
213    fn from(version: Version) -> Self {
214        (version.major, version.minor, version.patch)
215    }
216}
217
218/// A Vulkan entry point.
219#[derive(Clone)]
220pub struct Entry {
221    _loader: Option<Arc<dyn Loader>>,
222    static_commands: StaticCommands,
223    commands: EntryCommands,
224}
225
226impl Entry {
227    /// Loads a Vulkan entry point from previously loaded [`StaticCommands`].
228    ///
229    /// # Safety
230    ///
231    /// `static_commands` must contain valid Vulkan commands.
232    #[inline]
233    pub unsafe fn from_commands(static_commands: &StaticCommands) -> Self {
234        let load = |n| (static_commands.get_instance_proc_addr)(vk::Instance::null(), n);
235        let commands = EntryCommands::load(load);
236
237        Self {
238            _loader: None,
239            static_commands: *static_commands,
240            commands,
241        }
242    }
243
244    /// Loads a Vulkan entry point using a Vulkan function loader.
245    ///
246    /// # Safety
247    ///
248    /// The [`Loader::load`] method will be called on the supplied [`Loader`]
249    /// implementation to load the entry commands so the safety requirements of
250    /// [`Loader::load`] for the [`Loader`] implementation used must be upheld.
251    #[inline]
252    pub unsafe fn new(loader: impl Loader + 'static) -> Result<Self, Box<dyn LoaderError>> {
253        let loader = Arc::new(loader);
254
255        type F = extern "system" fn();
256
257        let raw = loader.load(b"vkGetInstanceProcAddr")?;
258        let get_instance_proc_addr = mem::transmute::<F, vk::PFN_vkGetInstanceProcAddr>(raw);
259
260        let raw = loader.load(b"vkGetDeviceProcAddr")?;
261        let get_device_proc_addr = mem::transmute::<F, vk::PFN_vkGetDeviceProcAddr>(raw);
262
263        let static_commands = StaticCommands {
264            get_instance_proc_addr,
265            get_device_proc_addr,
266        };
267
268        let load = |n| get_instance_proc_addr(vk::Instance::null(), n);
269        let commands = EntryCommands::load(load);
270
271        Ok(Self {
272            _loader: Some(loader),
273            static_commands,
274            commands,
275        })
276    }
277
278    /// Gets the instance-level version of this Vulkan entry point.
279    #[inline]
280    pub fn version(&self) -> VkResult<Version> {
281        unsafe { get_version(self.static_commands.get_instance_proc_addr) }
282    }
283
284    /// Creates a Vulkan instance using this Vulkan entry point.
285    ///
286    /// # Safety
287    ///
288    /// The [`Loader::load`] method will be called on the supplied [`Loader`]
289    /// implementation to load the instance commands so the safety requirements
290    /// of [`Loader::load`] for the [`Loader`] implementation used must be
291    /// upheld.
292    #[inline]
293    pub unsafe fn create_instance(
294        &self,
295        info: &vk::InstanceCreateInfo,
296        allocator: Option<&vk::AllocationCallbacks>,
297    ) -> VkResult<Instance> {
298        let instance = EntryV1_0::create_instance(self, info, allocator)?;
299        Instance::from_created(self, info, instance)
300    }
301}
302
303impl fmt::Debug for Entry {
304    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305        write!(f, "Entry")
306    }
307}
308
309unsafe impl Send for Entry {}
310unsafe impl Sync for Entry {}
311
312/// A Vulkan instance.
313#[derive(Clone)]
314pub struct Instance {
315    entry: Entry,
316    handle: vk::Instance,
317    commands: InstanceCommands,
318    version: Version,
319    extensions: BTreeSet<vk::ExtensionName>,
320    layers: BTreeSet<vk::ExtensionName>,
321}
322
323impl Instance {
324    /// Loads a Vulkan instance from a previously created [`vk::Instance`].
325    ///
326    /// # Safety
327    ///
328    /// `instance` must have been created using `entry` and `info`.
329    #[inline]
330    pub unsafe fn from_created(
331        entry: &Entry,
332        info: &vk::InstanceCreateInfo,
333        instance: vk::Instance,
334    ) -> VkResult<Self> {
335        let load = |n| (entry.static_commands.get_instance_proc_addr)(instance, n);
336        let commands = InstanceCommands::load(load);
337
338        let version = get_version(entry.static_commands.get_instance_proc_addr)?;
339
340        let extensions = get_names(info.enabled_extension_count, info.enabled_extension_names);
341        let layers = get_names(info.enabled_layer_count, info.enabled_layer_names);
342
343        Ok(Self {
344            entry: entry.clone(),
345            handle: instance,
346            commands,
347            version,
348            extensions,
349            layers,
350        })
351    }
352
353    /// Gets the version for this Vulkan instance.
354    #[inline]
355    pub fn version(&self) -> Version {
356        self.version
357    }
358
359    /// Gets the loaded extensions for this Vulkan instance.
360    #[inline]
361    pub fn extensions(&self) -> &BTreeSet<vk::ExtensionName> {
362        &self.extensions
363    }
364
365    /// Gets the loaded layers for this Vulkan instance.
366    #[inline]
367    pub fn layers(&self) -> &BTreeSet<vk::ExtensionName> {
368        &self.layers
369    }
370
371    /// Creates a Vulkan device using this Vulkan instance.
372    ///
373    /// # Safety
374    ///
375    /// The [`Loader::load`] method will be called on the supplied [`Loader`]
376    /// implementation to load the device commands so the safety requirements of
377    /// [`Loader::load`] for the [`Loader`] implementation used must be upheld.
378    #[inline]
379    pub unsafe fn create_device(
380        &self,
381        physical_device: vk::PhysicalDevice,
382        info: &vk::DeviceCreateInfo,
383        allocator: Option<&vk::AllocationCallbacks>,
384    ) -> VkResult<Device> {
385        let device = InstanceV1_0::create_device(self, physical_device, info, allocator)?;
386        Device::from_created(&self.entry, physical_device, info, device)
387    }
388}
389
390impl fmt::Debug for Instance {
391    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392        f.debug_struct("Instance")
393            .field("handle", &self.handle)
394            .field("extensions", &self.extensions)
395            .field("layers", &self.layers)
396            .finish()
397    }
398}
399
400unsafe impl Send for Instance {}
401unsafe impl Sync for Instance {}
402
403/// A Vulkan device.
404#[derive(Clone)]
405pub struct Device {
406    handle: vk::Device,
407    commands: DeviceCommands,
408    physical_device: vk::PhysicalDevice,
409    extensions: BTreeSet<vk::ExtensionName>,
410    layers: BTreeSet<vk::ExtensionName>,
411}
412
413impl Device {
414    /// Loads a Vulkan device from a previously created [`vk::Device`].
415    ///
416    /// # Safety
417    ///
418    /// `device` must have been created using `entry`, `physical_device`, and `info`.
419    #[inline]
420    pub unsafe fn from_created(
421        entry: &Entry,
422        physical_device: vk::PhysicalDevice,
423        info: &vk::DeviceCreateInfo,
424        device: vk::Device,
425    ) -> VkResult<Self> {
426        let load = |n| (entry.static_commands.get_device_proc_addr)(device, n);
427        let commands = DeviceCommands::load(load);
428
429        let extensions = get_names(info.enabled_extension_count, info.enabled_extension_names);
430        let layers = get_names(info.enabled_layer_count, info.enabled_layer_names);
431
432        Ok(Self {
433            handle: device,
434            commands,
435            physical_device,
436            extensions,
437            layers,
438        })
439    }
440
441    /// Gets the physical device for this Vulkan device.
442    #[inline]
443    pub fn physical_device(&self) -> vk::PhysicalDevice {
444        self.physical_device
445    }
446
447    /// Gets the loaded extensions for this Vulkan device.
448    #[inline]
449    pub fn extensions(&self) -> &BTreeSet<vk::ExtensionName> {
450        &self.extensions
451    }
452
453    /// Gets the loaded layers for this Vulkan device.
454    #[inline]
455    pub fn layers(&self) -> &BTreeSet<vk::ExtensionName> {
456        &self.layers
457    }
458}
459
460impl fmt::Debug for Device {
461    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462        f.debug_struct("Device")
463            .field("handle", &self.handle)
464            .field("extensions", &self.extensions)
465            .field("layers", &self.layers)
466            .finish()
467    }
468}
469
470unsafe impl Send for Device {}
471unsafe impl Sync for Device {}
472
473#[inline]
474unsafe fn get_names(
475    num_strings: u32,
476    strings: *const *const c_char,
477) -> BTreeSet<vk::ExtensionName> {
478    if strings.is_null() || num_strings == 0 {
479        return BTreeSet::new();
480    }
481
482    slice::from_raw_parts(strings, num_strings as usize)
483        .iter()
484        .map(|s| vk::ExtensionName::from_ptr(*s))
485        .collect()
486}
487
488#[inline]
489unsafe fn get_version(get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr) -> VkResult<Version> {
490    let name = c"vkEnumerateInstanceVersion".as_ptr();
491    let raw = (get_instance_proc_addr)(vk::Instance::null(), name);
492    let enumerate: Option<vk::PFN_vkEnumerateInstanceVersion> = mem::transmute(raw);
493    if let Some(enumerate) = enumerate {
494        let mut version = 0;
495        match unsafe { enumerate(&mut version) } {
496            vk::Result::SUCCESS => Ok(Version::from(version)),
497            error => Err(error.into()),
498        }
499    } else {
500        Ok(Version::V1_0_0)
501    }
502}