erupt/
lib.rs

1#![allow(clippy::all, unreachable_patterns)]
2#![doc(html_logo_url = "https://gitlab.com/Friz64/erupt/-/raw/main/logo.svg")]
3/*!
4Vulkan API bindings
5
6Take a look at the [`erupt` user guide](https://gitlab.com/Friz64/erupt/-/blob/main/USER_GUIDE.md).
7
8## **MAINTENANCE MODE NOTICE**
9
10It is not recommended to use erupt for new projects, use ash instead. There is
11work underway to rewrite ash using ideas from the erupt project, for updates see
12<https://github.com/ash-rs/ash/issues/344>. Simple patches to erupt will still
13be merged, but no large changes are to be expected.
14
15## Features
16
17- Full Vulkan API coverage
18- First-class support for all extensions
19- High quality auto-generated function wrappers
20- A [utility module] aiding your use of this crate
21  - [`VulkanResult`]: Idiomatic wrapper around a Vulkan Result
22  - [`surface`]: Create a [`SurfaceKHR`] using a [`RawWindowHandle`] (adapted from [`ash-window`])
23- Generated code distributed into multiple modules
24- Function loading ([`EntryLoader`], [`InstanceLoader`], [`DeviceLoader`])
25- Separate `Flags` and `FlagBits` types
26- A high level `Builder` for every struct
27- Type-safe pointer chain support
28- `Default` and `Debug` implementation for every type
29- Confirmed support for Linux, Windows, macOS and Android
30- Complete auto-generation of everything except [`utils`]
31
32## Example: Instance Creation
33
34```rust ignore
35use erupt::{vk, EntryLoader, InstanceLoader};
36
37let entry = EntryLoader::new()?;
38
39let app_info = vk::ApplicationInfoBuilder::new()
40    .api_version(vk::API_VERSION_1_1);
41let instance_info = vk::InstanceCreateInfoBuilder::new()
42    .application_info(&app_info);
43let instance = InstanceLoader::new(&entry, &instance_info)?;
44
45// ...
46
47instance.destroy_instance(None);
48```
49
50## Additional examples
51
52- [triangle](https://gitlab.com/Friz64/erupt/-/blob/main/erupt_examples/src/bin/triangle.rs)
53- [pointer_chain](https://gitlab.com/Friz64/erupt/-/blob/main/erupt_examples/src/bin/pointer_chain.rs)
54- [features](https://gitlab.com/Friz64/erupt/-/blob/main/erupt_examples/src/bin/features.rs)
55- [version](https://gitlab.com/Friz64/erupt/-/blob/main/erupt_examples/src/bin/version.rs)
56- [custom_loaders](https://gitlab.com/Friz64/erupt/-/blob/main/erupt_examples/src/bin/custom_loaders.rs)
57
58## Cargo Features
59
60- `surface` (enabled by default): Enables the [`surface`] module, adds [`raw-window-handle`] dependency
61- `loading` (enabled by default): Enables the [`EntryLoader::new`] function, adds [`libloading`] dependency
62- `bytemuck`: Implements [`Pod`] for some hand-picked structs (`*IndirectCommand`, etc.), adds [`bytemuck`] dependency
63
64## FAQ
65
66### Q: What's the difference between this, ash and vulkano?
67
68A: Vulkano is special because it provides hand-written Vulkan wrappers, which means that for example
69it has a special hand-written wrapper around a Vulkan `PhysicalDevice`. On the other hand ash and
70erupt both provide Vulkan API bindings too, but not exposing such _fancy_ wrappers and instead
71focusing on having good bindings to the _raw_ Vulkan API.
72
73The big selling points of erupt is that it has better documentation, high level function support for
74all extensions (which is only really relevant if you use those extensions), being fully generated
75and some more smaller improvements. On the other hand ash has a bigger existing community.
76
77### Q: What does the number at the end of the version mean?
78
79A: It represents the Vulkan Header version this version of erupt was generated against and is purely
80informational.
81
82## Ecosystem
83
84### Initialization
85
86- [`erupt-bootstrap`](https://gitlab.com/Friz64/erupt-bootstrap): Vulkan Bootstrapping library, inspired by vk-bootstrap
87
88### Memory Allocation
89
90- [`gpu-alloc`](https://github.com/zakarumych/gpu-alloc): Rust-native, used internally by `wgpu`
91- [`vk-alloc`](https://github.com/hasenbanck/vk-alloc): Rust-native
92- [`vk-mem-erupt`](https://github.com/HindrikStegenga/vk-mem-rs): Bindings to the C++ Vulkan Memory Allocator (VMA) library
93
94## Minimum Supported Rust Version (MSRV)
95
96Rust 1.48 or higher.
97
98## Thank you
99
100- [`ash`](https://crates.io/crates/ash) for helping inspiring and making this crate
101- [`libloading`](https://crates.io/crates/libloading) for providing symbol loading
102- [`ash-window`](https://crates.io/crates/ash-window) for providing a base for the [`surface`] module
103- [`bitflags`](https://crates.io/crates/bitflags) for providing a perfect bitflag macro
104- The Vulkan Community ❤️
105- The Rust Community ❤️
106
107## Licensing
108
109The logo is the Volcano Emoji of [Twemoji](https://twemoji.twitter.com/) ([License](https://creativecommons.org/licenses/by/4.0/)). The name "erupt" was added on top of it.
110
111This project is licensed under the [zlib License](https://gitlab.com/Friz64/erupt/-/blob/main/LICENSE).
112
113[utility module]: https://docs.rs/erupt/%2A/erupt/utils/index.html
114[`vulkanresult`]: https://docs.rs/erupt/%2A/erupt/utils/struct.VulkanResult.html
115[`surface`]: https://docs.rs/erupt/%2A/erupt/utils/surface/index.html
116[`surfacekhr`]: https://docs.rs/erupt/%2A/erupt/extensions/khr_surface/struct.SurfaceKHR.html
117[`allocator`]: https://docs.rs/erupt/%2A/erupt/utils/allocator/index.html
118[`rawwindowhandle`]: https://docs.rs/raw-window-handle/%2A/raw_window_handle/enum.RawWindowHandle.html
119[`libloading`]: https://crates.io/crates/libloading
120[`raw-window-handle`]: https://crates.io/crates/raw-window-handle
121[`ash-window`]: https://crates.io/crates/ash-window
122[`entryloader`]: https://docs.rs/erupt/%2A/erupt/struct.EntryLoader.html
123[`entryloader::new`]: https://docs.rs/erupt/%2A/erupt/struct.EntryLoader.html#method.new
124[`pod`]: https://docs.rs/bytemuck/%2A/bytemuck/trait.Pod.html
125[`bytemuck`]: https://crates.io/crates/bytemuck
126[`instanceloader`]: https://docs.rs/erupt/%2A/erupt/struct.InstanceLoader.html
127[`deviceloader`]: https://docs.rs/erupt/%2A/erupt/struct.DeviceLoader.html
128[`utils`]: https://docs.rs/erupt/%2A/erupt/utils/index.html
129*/
130
131mod generated;
132pub mod utils;
133
134use fmt::Debug;
135pub use generated::*;
136use std::{
137    error::Error,
138    ffi::CStr,
139    fmt::{self, Display},
140    mem, ptr,
141    sync::Arc,
142};
143#[cfg(feature = "loading")]
144pub use utils::loading::EntryLoader;
145
146/// Construct a `*const std::os::raw::c_char` from a string.
147///
148/// # Example
149/// ```ignore
150/// const LAYER_KHRONOS_VALIDATION: *const c_char = cstr!("VK_LAYER_KHRONOS_validation");
151/// ```
152#[macro_export]
153macro_rules! cstr {
154    ($s:expr) => {
155        concat!($s, "\0").as_ptr().cast::<::std::os::raw::c_char>()
156    };
157}
158
159/// Like `try!`, but for [`utils::VulkanResult`](utils/struct.VulkanResult.html).
160///
161/// ```ignore
162/// unsafe fn example(device: &DeviceLoader) -> VulkanResult<(Semaphore, Semaphore)> {
163///     let create_info = SemaphoreCreateInfoBuilder::new();
164///
165///     let semaphore1 = try_vk!(device.create_semaphore(&create_info, None, None));
166///     let semaphore2 = try_vk!(device.create_semaphore(&create_info, None, None));
167///     VulkanResult::new_ok((semaphore1, semaphore2))
168/// }
169/// ```
170#[macro_export]
171macro_rules! try_vk {
172    ($expr:expr) => {
173        match $crate::utils::VulkanResult::result($expr) {
174            Ok(value) => value,
175            Err(raw) => return $crate::utils::VulkanResult::new_err(raw),
176        }
177    };
178}
179
180// adapted from ash
181#[doc(hidden)]
182#[macro_export]
183macro_rules! non_dispatchable_handle {
184    ($name:ident, $ty:ident, $doc:literal, $doc_alias:literal) => {
185        #[doc = $doc]
186        #[doc(alias = $doc_alias)]
187        #[repr(transparent)]
188        #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Default)]
189        pub struct $name(pub u64);
190
191        impl $crate::ObjectHandle for $name {
192            const TYPE: $crate::vk1_0::ObjectType = $crate::vk1_0::ObjectType::$ty;
193
194            fn to_raw(self) -> u64 {
195                self.0
196            }
197
198            fn from_raw(raw: u64) -> Self {
199                $name(raw)
200            }
201        }
202
203        impl std::fmt::Pointer for $name {
204            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
205                write!(f, "0x{:x}", self.0)
206            }
207        }
208
209        impl std::fmt::Debug for $name {
210            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
211                write!(f, "0x{:x}", self.0)
212            }
213        }
214    };
215}
216
217// adapted from ash
218#[doc(hidden)]
219#[macro_export]
220macro_rules! dispatchable_handle {
221    ($name:ident, $ty:ident, $doc:literal, $doc_alias:literal) => {
222        #[doc = $doc]
223        #[doc(alias = $doc_alias)]
224        #[repr(transparent)]
225        #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
226        pub struct $name(pub *mut ());
227
228        impl $crate::ObjectHandle for $name {
229            const TYPE: $crate::vk1_0::ObjectType = $crate::vk1_0::ObjectType::$ty;
230
231            fn to_raw(self) -> u64 {
232                self.0 as u64
233            }
234
235            fn from_raw(raw: u64) -> Self {
236                $name(raw as _)
237            }
238        }
239
240        unsafe impl Send for $name {}
241        unsafe impl Sync for $name {}
242
243        impl Default for $name {
244            fn default() -> $name {
245                $name(std::ptr::null_mut())
246            }
247        }
248
249        impl std::fmt::Pointer for $name {
250            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
251                std::fmt::Pointer::fmt(&self.0, f)
252            }
253        }
254
255        impl std::fmt::Debug for $name {
256            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
257                std::fmt::Debug::fmt(&self.0, f)
258            }
259        }
260    };
261}
262
263// used in builders for bitwidth fields
264#[doc(hidden)]
265#[macro_export]
266macro_rules! bits_copy {
267    ($dst:expr, $src:expr, $start:expr, $end:expr) => {{
268        let mut dst = $dst;
269        let src = $src;
270        let start: usize = $start;
271        let end: usize = $end;
272
273        // bits in the range are 1 (end inclusive)
274        let mask = !0 << start & !(!0 << end);
275
276        // clear bits
277        dst &= !mask;
278        // set bits from src
279        dst |= (src << start) & mask;
280
281        dst
282    }};
283}
284
285const NOT_LOADED_MESSAGE: &str = "tried to call a function that isn't loaded: \
286    is the respective `enabled_extension_names` array correct? \
287    does the configured Vulkan version support this function?";
288
289/// Allows returning small amounts of data (specifically with a length <= 8)
290/// without needlessly allocating heap memory.
291pub type SmallVec<T> = smallvec::SmallVec<[T; 8]>;
292
293/// An error which can occur while initializing a loader.
294#[derive(Debug)]
295pub enum LoaderError {
296    /// A Vulkan function returned a negative `Result` value.
297    VulkanError(vk1_0::Result),
298    /// A symbol was not available while it should have been.
299    SymbolNotAvailable,
300}
301
302impl Display for LoaderError {
303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304        match self {
305            LoaderError::VulkanError(_) => {
306                write!(f, "a Vulkan function returned a negative `Result` value")
307            }
308            LoaderError::SymbolNotAvailable => {
309                write!(f, "a symbol was not available while it should have been")
310            }
311        }
312    }
313}
314
315impl Error for LoaderError {
316    fn source(&self) -> Option<&(dyn Error + 'static)> {
317        match self {
318            LoaderError::VulkanError(vk_result) => Some(vk_result),
319            LoaderError::SymbolNotAvailable => None,
320        }
321    }
322}
323
324impl<T> CustomEntryLoader<T> {
325    /// Creates a entry loader with a custom library used for loading.
326    pub unsafe fn with_library(
327        mut library: T,
328        mut symbol: impl FnMut(&mut T, *const std::os::raw::c_char) -> Option<vk1_0::PFN_vkVoidFunction>,
329    ) -> Result<Self, LoaderError> {
330        Ok(
331            EntryEnabled::new(&mut library, &mut symbol).and_then(|entry_enabled| {
332                CustomEntryLoader::custom(library, &mut symbol, entry_enabled)
333            })?,
334        )
335    }
336
337    /// Access enabled requirements of this entry loader.
338    pub fn enabled(&self) -> &EntryEnabled {
339        &self.enabled
340    }
341
342    /// This will be the result of `vkEnumerateInstanceVersion` if available, otherwise `0.1.0.0`.
343    pub fn instance_version(&self) -> u32 {
344        self.enabled.instance_version
345    }
346}
347
348impl<T> Drop for CustomEntryLoader<T> {
349    fn drop(&mut self) {
350        if Arc::weak_count(&self.arc) != 0 {
351            panic!("attempting to drop a entry loader with active references to it");
352        }
353    }
354}
355
356impl<T> Debug for CustomEntryLoader<T> {
357    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358        write!(f, "Entry")
359    }
360}
361
362/// Builder for an instance loader.
363pub struct InstanceLoaderBuilder<'a> {
364    create_instance_fn: Option<
365        &'a mut dyn FnMut(
366            &vk1_0::InstanceCreateInfo,
367            Option<&vk1_0::AllocationCallbacks>,
368        ) -> utils::VulkanResult<vk1_0::Instance>,
369    >,
370    symbol_fn: Option<
371        &'a mut dyn FnMut(
372            vk1_0::Instance,
373            *const std::os::raw::c_char,
374        ) -> Option<vk1_0::PFN_vkVoidFunction>,
375    >,
376    allocation_callbacks: Option<&'a vk1_0::AllocationCallbacks>,
377}
378
379impl<'a> InstanceLoaderBuilder<'a> {
380    /// Create a new instance loader builder.
381    pub fn new() -> Self {
382        InstanceLoaderBuilder {
383            create_instance_fn: None,
384            symbol_fn: None,
385            allocation_callbacks: None,
386        }
387    }
388
389    /// Specify a custom instance creation function, to use in place of the
390    /// default.
391    ///
392    /// This may be useful when creating the instance using e.g. OpenXR.
393    pub fn create_instance_fn(
394        mut self,
395        create_instance: &'a mut dyn FnMut(
396            &vk1_0::InstanceCreateInfo,
397            Option<&vk1_0::AllocationCallbacks>,
398        ) -> utils::VulkanResult<vk1_0::Instance>,
399    ) -> Self {
400        self.create_instance_fn = Some(create_instance);
401        self
402    }
403
404    /// Specify a custom symbol function, called to get instance function
405    /// pointers, to use in place of the default.
406    pub fn symbol_fn(
407        mut self,
408        symbol: &'a mut impl FnMut(
409            vk1_0::Instance,
410            *const std::os::raw::c_char,
411        ) -> Option<vk1_0::PFN_vkVoidFunction>,
412    ) -> Self {
413        self.symbol_fn = Some(symbol);
414        self
415    }
416
417    /// Specify custom allocation callback functions.
418    pub fn allocation_callbacks(mut self, allocator: &'a vk1_0::AllocationCallbacks) -> Self {
419        self.allocation_callbacks = Some(allocator);
420        self
421    }
422
423    /// Create an instance loader.
424    pub unsafe fn build<T>(
425        self,
426        entry_loader: &'a CustomEntryLoader<T>,
427        create_info: &vk1_0::InstanceCreateInfo,
428    ) -> Result<InstanceLoader, LoaderError> {
429        let instance = match self.create_instance_fn {
430            Some(create_instance) => create_instance(create_info, self.allocation_callbacks),
431            None => entry_loader.create_instance(create_info, self.allocation_callbacks),
432        };
433
434        let instance = instance.result().map_err(LoaderError::VulkanError)?;
435
436        let mut version = vk1_0::make_api_version(0, 1, 0, 0);
437        if !create_info.p_application_info.is_null() {
438            let user_version = (*create_info.p_application_info).api_version;
439            if user_version != 0 {
440                version = user_version;
441            }
442        }
443
444        let enabled_extensions = std::slice::from_raw_parts(
445            create_info.pp_enabled_extension_names,
446            create_info.enabled_extension_count as _,
447        );
448        let enabled_extensions: Vec<_> = enabled_extensions
449            .iter()
450            .map(|&ptr| CStr::from_ptr(ptr))
451            .collect();
452
453        let mut default_symbol = move |name| (entry_loader.get_instance_proc_addr)(instance, name);
454        let mut symbol: &mut dyn FnMut(
455            *const std::os::raw::c_char,
456        ) -> Option<vk1_0::PFN_vkVoidFunction> = &mut default_symbol;
457        let mut user_symbol;
458        if let Some(internal_symbol) = self.symbol_fn {
459            user_symbol = move |name| internal_symbol(instance, name);
460            symbol = &mut user_symbol;
461        }
462
463        let all_physical_device_extension_properties =
464            all_physical_device_extension_properties(&mut symbol, instance)?;
465        let available_device_extensions: Vec<_> = all_physical_device_extension_properties
466            .iter()
467            .map(|properties| CStr::from_ptr(properties.extension_name.as_ptr()))
468            .collect();
469
470        let instance_enabled =
471            InstanceEnabled::new(version, &enabled_extensions, &available_device_extensions)?;
472        InstanceLoader::custom(entry_loader, instance, instance_enabled, symbol)
473    }
474}
475
476impl InstanceLoader {
477    /// Creates a new instance loader.
478    ///
479    /// For more advanced use cases, take a look at [`InstanceLoaderBuilder`].
480    #[inline]
481    pub unsafe fn new<T>(
482        entry_loader: &CustomEntryLoader<T>,
483        create_info: &vk1_0::InstanceCreateInfo,
484    ) -> Result<InstanceLoader, LoaderError> {
485        InstanceLoaderBuilder::new().build(entry_loader, create_info)
486    }
487
488    /// Access enabled requirements of this instance loader.
489    pub fn enabled(&self) -> &InstanceEnabled {
490        &self.enabled
491    }
492}
493
494impl Drop for InstanceLoader {
495    fn drop(&mut self) {
496        if Arc::weak_count(&self.arc) != 0 {
497            panic!("attempting to drop a instance loader with active references to it");
498        }
499    }
500}
501
502// This is needed for available device extensions.
503//
504// Vulkan spec: An "available device extension" is a device extension supported
505// by any physical device enumerated by instance.
506// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html#_description
507unsafe fn all_physical_device_extension_properties(
508    symbol: &mut impl FnMut(*const std::os::raw::c_char) -> Option<vk1_0::PFN_vkVoidFunction>,
509    instance: vk1_0::Instance,
510) -> Result<Vec<vk1_0::ExtensionProperties>, LoaderError> {
511    let enumerate_physical_devices: vk1_0::PFN_vkEnumeratePhysicalDevices = mem::transmute(
512        symbol(vk1_0::FN_ENUMERATE_PHYSICAL_DEVICES).ok_or(LoaderError::SymbolNotAvailable)?,
513    );
514    let enumerate_device_extension_properties: vk1_0::PFN_vkEnumerateDeviceExtensionProperties =
515        mem::transmute(
516            symbol(vk1_0::FN_ENUMERATE_DEVICE_EXTENSION_PROPERTIES)
517                .ok_or(LoaderError::SymbolNotAvailable)?,
518        );
519
520    let mut physical_device_count = 0;
521    let result = enumerate_physical_devices(instance, &mut physical_device_count, ptr::null_mut());
522    if result.0 < 0 {
523        return Err(LoaderError::VulkanError(result));
524    }
525
526    let mut physical_devices = vec![Default::default(); physical_device_count as usize];
527    let result = enumerate_physical_devices(
528        instance,
529        &mut physical_device_count,
530        physical_devices.as_mut_ptr(),
531    );
532    if result.0 < 0 {
533        return Err(LoaderError::VulkanError(result));
534    }
535
536    let mut all_physical_device_extension_properties = Vec::new();
537    for physical_device in physical_devices {
538        let mut property_count = 0;
539        let result = enumerate_device_extension_properties(
540            physical_device,
541            ptr::null(),
542            &mut property_count,
543            ptr::null_mut(),
544        );
545        if result.0 < 0 {
546            return Err(LoaderError::VulkanError(result));
547        }
548
549        let mut properties = vec![Default::default(); property_count as usize];
550        let result = enumerate_device_extension_properties(
551            physical_device,
552            ptr::null(),
553            &mut property_count,
554            properties.as_mut_ptr(),
555        );
556        if result.0 < 0 {
557            return Err(LoaderError::VulkanError(result));
558        }
559
560        all_physical_device_extension_properties.extend(properties.into_iter());
561    }
562
563    Ok(all_physical_device_extension_properties)
564}
565
566impl Debug for InstanceLoader {
567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568        Debug::fmt(&self.handle, f)
569    }
570}
571
572/// Builder for an device loader.
573pub struct DeviceLoaderBuilder<'a> {
574    create_device_fn: Option<
575        &'a mut dyn FnMut(
576            vk1_0::PhysicalDevice,
577            &vk1_0::DeviceCreateInfo,
578            Option<&vk1_0::AllocationCallbacks>,
579        ) -> utils::VulkanResult<vk1_0::Device>,
580    >,
581    symbol_fn: Option<
582        &'a mut dyn FnMut(
583            vk1_0::Device,
584            *const std::os::raw::c_char,
585        ) -> Option<vk1_0::PFN_vkVoidFunction>,
586    >,
587    allocation_callbacks: Option<&'a vk1_0::AllocationCallbacks>,
588}
589
590impl<'a> DeviceLoaderBuilder<'a> {
591    /// Create a new instance loader builder.
592    pub fn new() -> Self {
593        DeviceLoaderBuilder {
594            create_device_fn: None,
595            symbol_fn: None,
596            allocation_callbacks: None,
597        }
598    }
599
600    /// Specify a custom device creation function, to use in place of the
601    /// default.
602    ///
603    /// This may be useful when creating the device using e.g. OpenXR.
604    pub fn create_device_fn(
605        mut self,
606        create_device: &'a mut dyn FnMut(
607            vk1_0::PhysicalDevice,
608            &vk1_0::DeviceCreateInfo,
609            Option<&vk1_0::AllocationCallbacks>,
610        ) -> utils::VulkanResult<vk1_0::Device>,
611    ) -> Self {
612        self.create_device_fn = Some(create_device);
613        self
614    }
615
616    /// Specify a custom symbol function, called to get device function
617    /// pointers, to use in place of the default.
618    pub fn symbol_fn(
619        mut self,
620        symbol: &'a mut impl FnMut(
621            vk1_0::Device,
622            *const std::os::raw::c_char,
623        ) -> Option<vk1_0::PFN_vkVoidFunction>,
624    ) -> Self {
625        self.symbol_fn = Some(symbol);
626        self
627    }
628
629    /// Specify custom allocation callback functions.
630    pub fn allocation_callbacks(mut self, allocator: &'a vk1_0::AllocationCallbacks) -> Self {
631        self.allocation_callbacks = Some(allocator);
632        self
633    }
634
635    /// Build the device loader. Ensure `create_info` is the same as used in the
636    /// creation of `device`.
637    pub unsafe fn build_with_existing_device(
638        self,
639        instance_loader: &'a InstanceLoader,
640        device: vk1_0::Device,
641        create_info: &vk1_0::DeviceCreateInfo,
642    ) -> Result<DeviceLoader, LoaderError> {
643        let device_enabled = {
644            let enabled_extensions = std::slice::from_raw_parts(
645                create_info.pp_enabled_extension_names,
646                create_info.enabled_extension_count as _,
647            );
648            let enabled_extensions: Vec<_> = enabled_extensions
649                .iter()
650                .map(|&ptr| CStr::from_ptr(ptr))
651                .collect();
652            DeviceEnabled::new(&enabled_extensions)
653        };
654
655        let mut default_symbol = move |name| (instance_loader.get_device_proc_addr)(device, name);
656        let mut symbol: &mut dyn FnMut(
657            *const std::os::raw::c_char,
658        ) -> Option<vk1_0::PFN_vkVoidFunction> = &mut default_symbol;
659        let mut user_symbol;
660        if let Some(internal_symbol) = self.symbol_fn {
661            user_symbol = move |name| internal_symbol(device, name);
662            symbol = &mut user_symbol;
663        }
664
665        DeviceLoader::custom(instance_loader, device, device_enabled, symbol)
666    }
667
668    /// Build the device loader. If you want to entirely create the device
669    /// yourself, use [`DeviceLoaderBuilder::build_with_existing_device`].
670    pub unsafe fn build(
671        mut self,
672        instance_loader: &'a InstanceLoader,
673        physical_device: vk1_0::PhysicalDevice,
674        create_info: &vk1_0::DeviceCreateInfo,
675    ) -> Result<DeviceLoader, LoaderError> {
676        let device = match &mut self.create_device_fn {
677            Some(create_device) => {
678                create_device(physical_device, create_info, self.allocation_callbacks)
679            }
680            None => instance_loader.create_device(
681                physical_device,
682                create_info,
683                self.allocation_callbacks,
684            ),
685        };
686
687        let device = device.result().map_err(LoaderError::VulkanError)?;
688        self.build_with_existing_device(instance_loader, device, create_info)
689    }
690}
691
692impl DeviceLoader {
693    /// Creates a new device loader.
694    ///
695    /// For more advanced use cases, take a look at [`DeviceLoaderBuilder`].
696    #[inline]
697    pub unsafe fn new(
698        instance_loader: &InstanceLoader,
699        physical_device: vk1_0::PhysicalDevice,
700        create_info: &vk1_0::DeviceCreateInfo,
701    ) -> Result<DeviceLoader, LoaderError> {
702        DeviceLoaderBuilder::new().build(instance_loader, physical_device, create_info)
703    }
704
705    /// Access enabled requirements of this device loader.
706    pub fn enabled(&self) -> &DeviceEnabled {
707        &self.enabled
708    }
709}
710
711impl Debug for DeviceLoader {
712    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
713        Debug::fmt(&self.handle, f)
714    }
715}
716
717/// Vulkan object handles (dispatchable and non-dispatchable).
718///
719/// This can be useful for building generic abstractions around functions like
720/// [`DeviceLoader::debug_marker_set_object_name_ext`].
721pub trait ObjectHandle: Default + PartialEq {
722    /// An abstract object type.
723    const TYPE: vk1_0::ObjectType;
724
725    /// Get the null handle for this object.
726    ///
727    /// This is the same as [`Default::default`].
728    fn null() -> Self {
729        Default::default()
730    }
731
732    /// Is this handle null / [`Default::default`]?
733    fn is_null(self) -> bool {
734        self == Self::null()
735    }
736
737    /// Get this object's raw handle.
738    fn to_raw(self) -> u64;
739
740    /// Construct an object from an raw handle.
741    fn from_raw(raw: u64) -> Self;
742}
743
744/// Provides type-safe pointer chain support.
745pub trait ExtendableFrom<'a, T> {
746    /// Inserts `addition` (+ its pointer chain) between the head and tail of
747    /// this pointer chain.
748    ///
749    /// - Head of `self`
750    ///   - Head of `addition`
751    ///   - _Tail of `addition`_
752    ///   - _Tail of `addition`_
753    ///   - _Tail of `addition`_
754    ///   - _..._
755    /// - _Tail of `self`_
756    /// - _Tail of `self`_
757    /// - _Tail of `self`_
758    /// - _..._
759    ///
760    /// The implementation is like this specifically, because this trait is only
761    /// ever implemented on the "main carrier" of the pointer chain, which means
762    /// that `addition` doesn't usually have a "tail" (unless, you've set the
763    /// pointers by yourself, which this consequently also supports). This saves
764    /// us from iterating the entire pointer chain each time an item is added.
765    #[must_use]
766    fn extend_from(mut self, addition: &'a mut T) -> Self
767    where
768        Self: Sized,
769    {
770        unsafe {
771            insert_ptr_chain(&mut self as *mut Self as _, addition as *mut T as _);
772        }
773
774        self
775    }
776}
777
778// safety: assumes all pointers in the pointer chain are valid
779#[inline]
780unsafe fn insert_ptr_chain(
781    mut host: *mut vk1_0::BaseOutStructure,
782    mut addition: *mut vk1_0::BaseOutStructure,
783) {
784    let addition_head = addition;
785    let addition_end = loop {
786        let p_next = (*addition).p_next;
787        if p_next.is_null() {
788            break addition;
789        } else {
790            addition = p_next;
791        }
792    };
793
794    let prev_host_next = (*host).p_next;
795    (*host).p_next = addition_head;
796    (*addition_end).p_next = prev_host_next;
797}
798
799#[cfg(test)]
800mod tests {
801    use super::*;
802    use std::ptr;
803
804    #[test]
805    fn ptr_chain_simple() {
806        // s1 -> s2 -> s3 -> (null)
807        let mut s1 = vk::BaseOutStructure {
808            s_type: vk::StructureType(1),
809            p_next: ptr::null_mut(),
810        };
811        let s1 = ptr::addr_of_mut!(s1);
812        let mut s2 = vk::BaseOutStructure {
813            s_type: vk::StructureType(2),
814            p_next: ptr::null_mut(),
815        };
816        let s2 = ptr::addr_of_mut!(s2);
817        let mut s3 = vk::BaseOutStructure {
818            s_type: vk::StructureType(3),
819            p_next: ptr::null_mut(),
820        };
821        let s3 = ptr::addr_of_mut!(s3);
822        unsafe {
823            (*s1).p_next = s2;
824            (*s2).p_next = s3;
825        }
826
827        // s4 -> (null)
828        let mut s4 = vk::BaseOutStructure {
829            s_type: vk::StructureType(4),
830            p_next: ptr::null_mut(),
831        };
832        let s4 = ptr::addr_of_mut!(s4);
833        // s5 -> (null)
834        let mut s5 = vk::BaseOutStructure {
835            s_type: vk::StructureType(5),
836            p_next: ptr::null_mut(),
837        };
838        let s5 = ptr::addr_of_mut!(s5);
839        // s6 -> (null)
840        let mut s6 = vk::BaseOutStructure {
841            s_type: vk::StructureType(6),
842            p_next: ptr::null_mut(),
843        };
844        let s6 = ptr::addr_of_mut!(s6);
845
846        // s1 -> s6 -> s5 -> s4 -> s2 -> s3 -> (null)
847        unsafe {
848            super::insert_ptr_chain(s1, s4);
849            super::insert_ptr_chain(s1, s5);
850            super::insert_ptr_chain(s1, s6);
851        }
852
853        let mut iter =
854            unsafe { utils::iterate_ptr_chain(s1) }.map(|item| unsafe { (*item).s_type.0 });
855        assert_eq!(iter.next(), Some(1));
856        assert_eq!(iter.next(), Some(6));
857        assert_eq!(iter.next(), Some(5));
858        assert_eq!(iter.next(), Some(4));
859        assert_eq!(iter.next(), Some(2));
860        assert_eq!(iter.next(), Some(3));
861        assert_eq!(iter.next(), None);
862    }
863
864    #[test]
865    fn ptr_chain_addition_chain() {
866        // s1 -> s2 -> s3 -> (null)
867        let mut s1 = vk::BaseOutStructure {
868            s_type: vk::StructureType(1),
869            p_next: ptr::null_mut(),
870        };
871        let s1 = ptr::addr_of_mut!(s1);
872        let mut s2 = vk::BaseOutStructure {
873            s_type: vk::StructureType(2),
874            p_next: ptr::null_mut(),
875        };
876        let s2 = ptr::addr_of_mut!(s2);
877        let mut s3 = vk::BaseOutStructure {
878            s_type: vk::StructureType(3),
879            p_next: ptr::null_mut(),
880        };
881        let s3 = ptr::addr_of_mut!(s3);
882        unsafe {
883            (*s1).p_next = s2;
884            (*s2).p_next = s3;
885        }
886
887        // s4 -> s5 -> s6 -> (null)
888        let mut s4 = vk::BaseOutStructure {
889            s_type: vk::StructureType(4),
890            p_next: ptr::null_mut(),
891        };
892        let s4 = ptr::addr_of_mut!(s4);
893        let mut s5 = vk::BaseOutStructure {
894            s_type: vk::StructureType(5),
895            p_next: ptr::null_mut(),
896        };
897        let s5 = ptr::addr_of_mut!(s5);
898        let mut s6 = vk::BaseOutStructure {
899            s_type: vk::StructureType(6),
900            p_next: ptr::null_mut(),
901        };
902        let s6 = ptr::addr_of_mut!(s6);
903        unsafe {
904            (*s4).p_next = s5;
905            (*s5).p_next = s6;
906        }
907
908        // s1 -> s4 -> s5 -> s6 -> s2 -> s3 -> (null)
909        unsafe {
910            super::insert_ptr_chain(s1, s4);
911        }
912
913        let mut iter =
914            unsafe { utils::iterate_ptr_chain(s1) }.map(|item| unsafe { (*item).s_type.0 });
915        assert_eq!(iter.next(), Some(1));
916        assert_eq!(iter.next(), Some(4));
917        assert_eq!(iter.next(), Some(5));
918        assert_eq!(iter.next(), Some(6));
919        assert_eq!(iter.next(), Some(2));
920        assert_eq!(iter.next(), Some(3));
921        assert_eq!(iter.next(), None);
922    }
923
924    #[test]
925    fn ptr_chain_real_world() {
926        let mut vk1_1features = vk::PhysicalDeviceVulkan11FeaturesBuilder::new();
927        let mut vk1_2features = vk::PhysicalDeviceVulkan12FeaturesBuilder::new();
928        let mut features = vk::PhysicalDeviceFeatures2Builder::new()
929            .extend_from(&mut vk1_1features)
930            .extend_from(&mut vk1_2features);
931
932        let base_ptr = ptr::addr_of_mut!(features) as *mut vk::BaseOutStructure;
933        let mut iter =
934            unsafe { utils::iterate_ptr_chain(base_ptr) }.map(|item| unsafe { (*item).s_type });
935        assert_eq!(
936            iter.next(),
937            Some(vk::StructureType::PHYSICAL_DEVICE_FEATURES_2)
938        );
939        assert_eq!(
940            iter.next(),
941            Some(vk::StructureType::PHYSICAL_DEVICE_VULKAN_1_2_FEATURES)
942        );
943        assert_eq!(
944            iter.next(),
945            Some(vk::StructureType::PHYSICAL_DEVICE_VULKAN_1_1_FEATURES)
946        );
947        assert_eq!(iter.next(), None);
948    }
949}