1#![allow(clippy::all, unreachable_patterns)]
2#![doc(html_logo_url = "https://gitlab.com/Friz64/erupt/-/raw/main/logo.svg")]
3mod 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#[macro_export]
153macro_rules! cstr {
154 ($s:expr) => {
155 concat!($s, "\0").as_ptr().cast::<::std::os::raw::c_char>()
156 };
157}
158
159#[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#[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#[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#[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 let mask = !0 << start & !(!0 << end);
275
276 dst &= !mask;
278 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
289pub type SmallVec<T> = smallvec::SmallVec<[T; 8]>;
292
293#[derive(Debug)]
295pub enum LoaderError {
296 VulkanError(vk1_0::Result),
298 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 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 pub fn enabled(&self) -> &EntryEnabled {
339 &self.enabled
340 }
341
342 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
362pub 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 pub fn new() -> Self {
382 InstanceLoaderBuilder {
383 create_instance_fn: None,
384 symbol_fn: None,
385 allocation_callbacks: None,
386 }
387 }
388
389 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 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 pub fn allocation_callbacks(mut self, allocator: &'a vk1_0::AllocationCallbacks) -> Self {
419 self.allocation_callbacks = Some(allocator);
420 self
421 }
422
423 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 #[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 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
502unsafe 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
572pub 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 pub fn new() -> Self {
593 DeviceLoaderBuilder {
594 create_device_fn: None,
595 symbol_fn: None,
596 allocation_callbacks: None,
597 }
598 }
599
600 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 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 pub fn allocation_callbacks(mut self, allocator: &'a vk1_0::AllocationCallbacks) -> Self {
631 self.allocation_callbacks = Some(allocator);
632 self
633 }
634
635 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 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 #[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 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
717pub trait ObjectHandle: Default + PartialEq {
722 const TYPE: vk1_0::ObjectType;
724
725 fn null() -> Self {
729 Default::default()
730 }
731
732 fn is_null(self) -> bool {
734 self == Self::null()
735 }
736
737 fn to_raw(self) -> u64;
739
740 fn from_raw(raw: u64) -> Self;
742}
743
744pub trait ExtendableFrom<'a, T> {
746 #[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#[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 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 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 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 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 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 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 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 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}