use crate::{vk, InstanceLoader};
use std::{
alloc::{self, Layout},
error::Error,
fmt, ptr,
};
pub fn features2_bool_count(structure_type: crate::vk1_0::StructureType) -> Option<usize> {
crate::features2_bool_count(structure_type)
}
#[repr(C)]
#[derive(Debug)]
pub struct AbstractFeaturesNode {
pub base: vk::BaseOutStructure,
pub bools: [vk::Bool32],
}
#[derive(Debug)]
pub enum AbstractFeaturesNodeError {
UnknownFeaturesStruct,
MemoryAllocationFailed,
}
impl fmt::Display for AbstractFeaturesNodeError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AbstractFeaturesNodeError::UnknownFeaturesStruct => {
write!(fmt, "Structure is not a known features struct")
}
AbstractFeaturesNodeError::MemoryAllocationFailed => {
write!(fmt, "Failed to allocate memory")
}
}
}
}
impl Error for AbstractFeaturesNodeError {}
impl AbstractFeaturesNode {
pub unsafe fn from_raw(
node: *mut vk::BaseOutStructure,
) -> Result<*mut AbstractFeaturesNode, AbstractFeaturesNodeError> {
let bool_count = features2_bool_count((*node).s_type)
.ok_or(AbstractFeaturesNodeError::UnknownFeaturesStruct)?;
Ok(ptr::slice_from_raw_parts_mut(node as *mut vk::Bool32, bool_count) as _)
}
pub fn as_raw(&mut self) -> *mut vk::BaseOutStructure {
self as *mut _ as _
}
pub unsafe fn layout(
s_type: vk::StructureType,
) -> Result<(Layout, usize), AbstractFeaturesNodeError> {
let bool_count =
features2_bool_count(s_type).ok_or(AbstractFeaturesNodeError::UnknownFeaturesStruct)?;
let (layout, _bools_offset) = Layout::array::<vk::Bool32>(bool_count)
.and_then(|bools| Layout::new::<vk::BaseOutStructure>().extend(bools))
.unwrap();
Ok((layout.pad_to_align(), bool_count))
}
pub unsafe fn copy_single(
node: *const vk::BaseOutStructure,
) -> Result<Box<AbstractFeaturesNode>, AbstractFeaturesNodeError> {
let (layout, bool_count) = AbstractFeaturesNode::layout((*node).s_type)?;
let allocation = alloc::alloc(layout);
if allocation.is_null() {
return Err(AbstractFeaturesNodeError::MemoryAllocationFailed);
}
ptr::copy_nonoverlapping(node.cast::<u8>(), allocation, layout.size());
let fat_ptr = ptr::slice_from_raw_parts_mut(allocation as *mut vk::Bool32, bool_count);
Ok(Box::from_raw(fat_ptr as *mut _))
}
pub unsafe fn copy_chain(
node: *mut vk::BaseOutStructure,
) -> Result<*mut AbstractFeaturesNode, AbstractFeaturesNodeError> {
let mut first_node: Option<*mut AbstractFeaturesNode> = None;
let mut last_node: Option<*mut AbstractFeaturesNode> = None;
for node in super::iterate_ptr_chain(node) {
let abstract_node = Box::into_raw(AbstractFeaturesNode::copy_single(node)?);
if let Some(last_node) = last_node.or(first_node) {
(*last_node).base.p_next = abstract_node as _;
}
if first_node.is_none() {
first_node = Some(abstract_node);
} else {
last_node = Some(abstract_node);
}
}
Ok(first_node.unwrap())
}
pub unsafe fn free_chain(
node: *mut AbstractFeaturesNode,
) -> Result<(), AbstractFeaturesNodeError> {
let mut node = node as *mut vk::BaseOutStructure;
while !node.is_null() {
let vk::BaseOutStructure { s_type, p_next } = *node;
let (layout, _bool_count) = AbstractFeaturesNode::layout(s_type)?;
alloc::dealloc(node as _, layout);
node = p_next;
}
Ok(())
}
}
pub unsafe fn supported(
instance: &InstanceLoader,
physical_device: vk::PhysicalDevice,
query: &vk::PhysicalDeviceFeatures2Builder,
) -> Result<bool, AbstractFeaturesNodeError> {
let copied = AbstractFeaturesNode::copy_chain(query as *const _ as _)?;
instance.get_physical_device_features2(
physical_device,
&mut *(copied as *mut vk::PhysicalDeviceFeatures2),
);
for (query_node, supported_node) in
super::iterate_ptr_chain(query as *const _ as _).zip(super::iterate_ptr_chain(copied as _))
{
let query_node = AbstractFeaturesNode::from_raw(query_node as _)?;
let supported_node = AbstractFeaturesNode::from_raw(supported_node as _)?;
if !((*query_node).bools.iter())
.zip((*supported_node).bools.iter())
.all(|(query, supported)| *query == 0 || *supported != 0)
{
AbstractFeaturesNode::free_chain(copied)?;
return Ok(false);
}
}
AbstractFeaturesNode::free_chain(copied)?;
Ok(true)
}