use ash::vk;
use std::ffi::CStr;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(super) struct OptionalInstanceExts {
pub swapchain_colorspace: bool,
pub portability_enumeration: bool,
}
impl OptionalInstanceExts {
pub(crate) fn names(self) -> Vec<&'static CStr> {
let mut names = Vec::new();
if self.swapchain_colorspace {
names.push(ash::ext::swapchain_colorspace::NAME);
}
if self.portability_enumeration {
names.push(ash::khr::portability_enumeration::NAME);
}
names
}
pub(crate) fn flags(self) -> vk::InstanceCreateFlags {
if self.portability_enumeration {
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
} else {
vk::InstanceCreateFlags::empty()
}
}
}
pub(super) fn select(available: &[&CStr], hdr_display: bool) -> OptionalInstanceExts {
let has = |name: &CStr| available.contains(&name);
OptionalInstanceExts {
swapchain_colorspace: hdr_display && has(ash::ext::swapchain_colorspace::NAME),
portability_enumeration: has(ash::khr::portability_enumeration::NAME),
}
}
pub(super) fn names_of(props: &[vk::ExtensionProperties]) -> Vec<&CStr> {
props
.iter()
.map(|p| unsafe { CStr::from_ptr(p.extension_name.as_ptr()) })
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
const COLORSPACE: &CStr = ash::ext::swapchain_colorspace::NAME;
const PORTABILITY: &CStr = ash::khr::portability_enumeration::NAME;
const SURFACE: &CStr = ash::khr::surface::NAME;
#[test]
fn colorspace_needs_both_the_request_and_the_extension() {
assert!(select(&[COLORSPACE, SURFACE], true).swapchain_colorspace);
assert!(!select(&[SURFACE], true).swapchain_colorspace);
assert!(!select(&[COLORSPACE], false).swapchain_colorspace);
}
#[test]
fn portability_follows_the_loader_alone() {
assert!(select(&[PORTABILITY], false).portability_enumeration);
assert!(select(&[PORTABILITY], true).portability_enumeration);
assert!(!select(&[SURFACE], false).portability_enumeration);
}
#[test]
fn names_and_flags_follow_the_selection() {
let none = OptionalInstanceExts::default();
assert!(none.names().is_empty());
assert_eq!(none.flags(), vk::InstanceCreateFlags::empty());
let both = select(&[COLORSPACE, PORTABILITY], true);
assert_eq!(both.names(), vec![COLORSPACE, PORTABILITY]);
assert_eq!(
both.flags(),
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
);
let colorspace_only = select(&[COLORSPACE], true);
assert_eq!(colorspace_only.names(), vec![COLORSPACE]);
assert_eq!(colorspace_only.flags(), vk::InstanceCreateFlags::empty());
}
#[test]
fn names_read_back_from_extension_properties() {
let mut props = vk::ExtensionProperties::default();
let bytes = PORTABILITY.to_bytes_with_nul();
for (dst, src) in props.extension_name.iter_mut().zip(bytes) {
*dst = *src as std::os::raw::c_char;
}
let props = [props];
assert_eq!(names_of(&props), vec![PORTABILITY]);
}
}