1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
// SPDX-License-Identifier: Apache-2.0
//! Pointer chain handling.
//!
//! # Input Pointer Chains
//!
//! Input pointer chains are singly linked lists of Vulkan structs that
//! implement [`vk::InputChainStruct`] such as [`vk::InstanceCreateInfo`]. These
//! pointer chains are used to provide input data to Vulkan commands. A pointer
//! in such a chain can be represented with [`InputChainPtr`] and can be easily
//! iterated over using [`input_chain`].
//!
//! ### Example
//!
//! ```
//! # use vulkanalia::prelude::v1_0::*;
//! # use vulkanalia::chain::input_chain;
//! // Build an input pointer chain.
//!
//! let mut features = vk::ValidationFeaturesEXT::default();
//! let mut flags = vk::ValidationFlagsEXT::default();
//! let info = vk::InstanceCreateInfo::builder()
//! .push_next(&mut features)
//! .push_next(&mut flags)
//! .build();
//!
//! // Iterate over the input pointer chain.
//!
//! let structs = unsafe { input_chain(info.next) }.collect::<Vec<_>>();
//! assert_eq!(structs.len(), 2);
//!
//! // Inspect the pointers in the input pointer chain.
//!
//! let base = unsafe { structs[0].as_base_ref() };
//! assert_eq!(base.s_type, vk::StructureType::VALIDATION_FLAGS_EXT);
//! let full = unsafe { structs[0].as_ref::<vk::ValidationFlagsEXT>() };
//! assert_eq!(full, &flags);
//!
//! let base = unsafe { structs[1].as_base_ref() };
//! assert_eq!(base.s_type, vk::StructureType::VALIDATION_FEATURES_EXT);
//! let full = unsafe { structs[1].as_ref::<vk::ValidationFeaturesEXT>() };
//! assert_eq!(full, &features);
//! ```
//!
//! # Output Pointer Chain
//!
//! Output pointer chains are singly linked lists of Vulkan structs that
//! implement [`vk::OutputChainStruct`] such as [`vk::PhysicalDeviceFeatures2`].
//! These pointer chains are used by Vulkan to provide output data to the
//! application. A pointer in such a chain can be represented with
//! [`OutputChainPtr`] and can be easily iterated over using [`output_chain`].
//!
//! ### Example
//!
//! ```no_run
//! # use vulkanalia::prelude::v1_0::*;
//! # use vulkanalia::chain::output_chain;
//! # use vk::KhrGetPhysicalDeviceProperties2Extension;
//! # let instance: Instance = panic!();
//! # let physical_device: vk::PhysicalDevice = panic!();
//! // Call a command that populates an output pointer chain.
//!
//! let mut features_11 = vk::PhysicalDeviceVulkan11Features::default();
//! let mut features_12 = vk::PhysicalDeviceVulkan12Features::default();
//! let mut features = vk::PhysicalDeviceFeatures2::builder()
//! .push_next(&mut features_11)
//! .push_next(&mut features_12);
//!
//! unsafe { instance.get_physical_device_features2_khr(physical_device, &mut features) };
//!
//! // Iterate over the pointers in the output pointer chain.
//!
//! let structs = unsafe { output_chain(features.next) }.collect::<Vec<_>>();
//! assert_eq!(structs.len(), 2);
//!
//! // Inspect the pointers in the output pointer chain.
//!
//! let base = unsafe { structs[0].as_base_ref() };
//! assert_eq!(base.s_type, vk::StructureType::PHYSICAL_DEVICE_VULKAN_1_2_FEATURES);
//! let full = unsafe { structs[0].as_ref::<vk::PhysicalDeviceVulkan12Features>() };
//! assert_eq!(full.descriptor_indexing, 1);
//!
//! let base = unsafe { structs[1].as_base_ref() };
//! assert_eq!(base.s_type, vk::StructureType::PHYSICAL_DEVICE_VULKAN_1_1_FEATURES);
//! let full = unsafe { structs[1].as_ref::<vk::PhysicalDeviceVulkan11Features>() };
//! assert_eq!(full.protected_memory, 1);
//! ```
use core::ffi::c_void;
use core::iter;
use core::ptr::NonNull;
use crate::prelude::v1_0::*;
/// Creates an iterator over a Vulkan input pointer chain.
///
/// # Safety
///
/// See [`InputChainPtr::new`].
pub unsafe fn input_chain(head: *const c_void) -> impl Iterator<Item = InputChainPtr> {
let mut next = InputChainPtr::new(head);
iter::from_fn(move || {
let current = next?;
next = current.next();
Some(current)
})
}
/// Creates an iterator over a Vulkan output pointer chain.
///
/// # Safety
///
/// See [`OutputChainPtr::new`].
pub unsafe fn output_chain(head: *mut c_void) -> impl Iterator<Item = OutputChainPtr> {
let mut next = OutputChainPtr::new(head);
iter::from_fn(move || {
let current = next?;
next = current.next();
Some(current)
})
}
/// A non-null pointer in a Vulkan input pointer chain.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InputChainPtr(NonNull<vk::BaseInStructure>);
impl InputChainPtr {
/// Creates a non-null pointer in a Vulkan input pointer chain.
///
/// # Safety
///
/// `head` must either be null or be a pointer to a struct that could be
/// part of an input pointer chain (i.e., [`vk::InputChainStruct`]). The
/// same requirement recursively applies to any pointers in the chain.
pub unsafe fn new(head: *const c_void) -> Option<Self> {
NonNull::new(head.cast_mut()).map(|p| Self(p.cast()))
}
/// Gets the pointee of this pointer as a non-specific Vulkan struct.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method.
pub unsafe fn as_base_ref(&self) -> &vk::BaseInStructure {
self.0.as_ref()
}
/// Gets the pointee of this pointer as a specific Vulkan struct.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method **and** it must also be a pointer to a valid
/// instance of the provided Vulkan struct type.
pub unsafe fn as_ref<T: vk::InputChainStruct>(&self) -> &T {
assert_eq!(self.as_base_ref().s_type, T::TYPE);
self.0.cast::<T>().as_ref()
}
/// Gets the next non-null pointer in this Vulkan input pointer chain.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method.
pub unsafe fn next(&self) -> Option<Self> {
Self::new(self.as_base_ref().next.cast())
}
}
/// A non-null pointer in a Vulkan output pointer chain.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutputChainPtr(NonNull<vk::BaseOutStructure>);
impl OutputChainPtr {
/// Creates a non-null pointer in a Vulkan output pointer chain.
///
/// # Safety
///
/// `head` must either be null or be a pointer to a struct that could be
/// part of an output pointer chain (i.e., [`vk::OutputChainStruct`]). The
/// same requirement recursively applies to any pointers in the chain.
pub unsafe fn new(head: *mut c_void) -> Option<Self> {
NonNull::new(head).map(|p| Self(p.cast()))
}
/// Gets the pointee of this pointer as a non-specific Vulkan struct.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method.
pub unsafe fn as_base_ref(&self) -> &vk::BaseOutStructure {
self.0.as_ref()
}
/// Gets the pointee of this pointer as a specific Vulkan struct.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method **and** it must also be a pointer to a valid
/// instance of the provided Vulkan struct type.
pub unsafe fn as_ref<T: vk::OutputChainStruct>(&self) -> &T {
assert_eq!(self.as_base_ref().s_type, T::TYPE);
self.0.cast::<T>().as_ref()
}
/// Gets the next non-null pointer in this Vulkan output pointer chain.
///
/// # Safety
///
/// The pointer passed to [`Self::new`] must still satisfy the safety
/// requirements of that method.
pub unsafe fn next(&self) -> Option<Self> {
Self::new(self.as_base_ref().next.cast())
}
}