diff options
Diffstat (limited to 'third_party/rust/ash/src/prelude.rs')
-rw-r--r-- | third_party/rust/ash/src/prelude.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/third_party/rust/ash/src/prelude.rs b/third_party/rust/ash/src/prelude.rs new file mode 100644 index 0000000000..321c3aaddd --- /dev/null +++ b/third_party/rust/ash/src/prelude.rs @@ -0,0 +1,122 @@ +use std::convert::TryInto; +#[cfg(feature = "debug")] +use std::fmt; +use std::mem; + +use crate::vk; +pub type VkResult<T> = Result<T, vk::Result>; + +impl vk::Result { + #[inline] + pub fn result(self) -> VkResult<()> { + self.result_with_success(()) + } + + #[inline] + pub fn result_with_success<T>(self, v: T) -> VkResult<T> { + match self { + Self::SUCCESS => Ok(v), + _ => Err(self), + } + } + + #[inline] + pub unsafe fn assume_init_on_success<T>(self, v: mem::MaybeUninit<T>) -> VkResult<T> { + self.result().map(move |()| v.assume_init()) + } +} + +/// Repeatedly calls `f` until it does not return [`vk::Result::INCOMPLETE`] anymore, +/// ensuring all available data has been read into the vector. +/// +/// See for example [`vkEnumerateInstanceExtensionProperties`]: the number of available +/// items may change between calls; [`vk::Result::INCOMPLETE`] is returned when the count +/// increased (and the vector is not large enough after querying the initial size), +/// requiring Ash to try again. +/// +/// [`vkEnumerateInstanceExtensionProperties`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html +pub(crate) unsafe fn read_into_uninitialized_vector<N: Copy + Default + TryInto<usize>, T>( + f: impl Fn(&mut N, *mut T) -> vk::Result, +) -> VkResult<Vec<T>> +where + <N as TryInto<usize>>::Error: std::fmt::Debug, +{ + loop { + let mut count = N::default(); + f(&mut count, std::ptr::null_mut()).result()?; + let mut data = + Vec::with_capacity(count.try_into().expect("`N` failed to convert to `usize`")); + + let err_code = f(&mut count, data.as_mut_ptr()); + if err_code != vk::Result::INCOMPLETE { + err_code.result()?; + data.set_len(count.try_into().expect("`N` failed to convert to `usize`")); + break Ok(data); + } + } +} + +/// Repeatedly calls `f` until it does not return [`vk::Result::INCOMPLETE`] anymore, +/// ensuring all available data has been read into the vector. +/// +/// Items in the target vector are [`default()`][`Default::default()`]-initialized which +/// is required for [`vk::BaseOutStructure`]-like structs where [`vk::BaseOutStructure::s_type`] +/// needs to be a valid type and [`vk::BaseOutStructure::p_next`] a valid or +/// [`null`][`std::ptr::null_mut()`] pointer. +/// +/// See for example [`vkEnumerateInstanceExtensionProperties`]: the number of available +/// items may change between calls; [`vk::Result::INCOMPLETE`] is returned when the count +/// increased (and the vector is not large enough after querying the initial size), +/// requiring Ash to try again. +/// +/// [`vkEnumerateInstanceExtensionProperties`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html +pub(crate) unsafe fn read_into_defaulted_vector< + N: Copy + Default + TryInto<usize>, + T: Default + Clone, +>( + f: impl Fn(&mut N, *mut T) -> vk::Result, +) -> VkResult<Vec<T>> +where + <N as TryInto<usize>>::Error: std::fmt::Debug, +{ + loop { + let mut count = N::default(); + f(&mut count, std::ptr::null_mut()).result()?; + let mut data = + vec![Default::default(); count.try_into().expect("`N` failed to convert to `usize`")]; + + let err_code = f(&mut count, data.as_mut_ptr()); + if err_code != vk::Result::INCOMPLETE { + data.set_len(count.try_into().expect("`N` failed to convert to `usize`")); + break err_code.result_with_success(data); + } + } +} + +#[cfg(feature = "debug")] +pub(crate) fn debug_flags<Value: Into<u64> + Copy>( + f: &mut fmt::Formatter, + known: &[(Value, &'static str)], + value: Value, +) -> fmt::Result { + let mut first = true; + let mut accum = value.into(); + for &(bit, name) in known { + let bit = bit.into(); + if bit != 0 && accum & bit == bit { + if !first { + f.write_str(" | ")?; + } + f.write_str(name)?; + first = false; + accum &= !bit; + } + } + if accum != 0 { + if !first { + f.write_str(" | ")?; + } + write!(f, "{:b}", accum)?; + } + Ok(()) +} |