use crate::raw::PNextChainable;
use crate::raw::bindings::{VkPhysicalDeviceFeatures, VkPhysicalDeviceFeatures2};
use crate::safe::PNextChain;
pub struct DeviceFeatures {
chain: PNextChain,
}
impl Default for DeviceFeatures {
fn default() -> Self {
Self::new()
}
}
impl DeviceFeatures {
pub fn new() -> Self {
let mut chain = PNextChain::new();
chain.push(VkPhysicalDeviceFeatures2::new_pnext());
Self { chain }
}
pub fn chain_extension_feature<T: PNextChainable>(mut self, item: T) -> Self {
self.chain.push(item);
self
}
#[cfg(test)]
pub(crate) fn chain(&self) -> &PNextChain {
&self.chain
}
pub(crate) fn clone_chain_for_device_create(&self) -> PNextChain {
self.chain.clone()
}
fn features10_mut(&mut self) -> &mut VkPhysicalDeviceFeatures {
&mut self
.chain
.get_mut::<VkPhysicalDeviceFeatures2>()
.expect("chain head is always VkPhysicalDeviceFeatures2")
.features
}
fn ensure_ext<T: PNextChainable>(&mut self) -> &mut T {
if self.chain.get::<T>().is_none() {
self.chain.push(T::new_pnext());
}
self.chain
.get_mut::<T>()
.expect("struct was just pushed onto the chain")
}
}
impl std::fmt::Debug for DeviceFeatures {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DeviceFeatures")
.field("chain", &self.chain)
.finish()
}
}
include!(concat!(env!("OUT_DIR"), "/device_features_generated.rs"));
#[cfg(test)]
mod tests {
use super::*;
use crate::raw::bindings::{
VkPhysicalDeviceCooperativeMatrixFeaturesKHR, VkPhysicalDeviceVulkan12Features,
VkPhysicalDeviceVulkan13Features, VkStructureType,
};
#[test]
fn new_has_only_features2_head() {
let f = DeviceFeatures::new();
assert_eq!(f.chain().len(), 1);
let types: Vec<_> = f.chain().structure_types().collect();
assert_eq!(
types,
vec![VkStructureType::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2]
);
}
#[test]
fn core_1_0_bit_flips_inside_features2() {
let f = DeviceFeatures::new().with_sampler_anisotropy();
assert_eq!(f.chain().len(), 1);
let features2 = f
.chain()
.get::<VkPhysicalDeviceFeatures2>()
.expect("head present");
assert_eq!(features2.features.samplerAnisotropy, 1);
}
#[test]
fn v12_bit_lazily_pushes_struct() {
let f = DeviceFeatures::new().with_timeline_semaphore();
assert_eq!(f.chain().len(), 2);
let v12 = f
.chain()
.get::<VkPhysicalDeviceVulkan12Features>()
.expect("v12 pushed");
assert_eq!(v12.timelineSemaphore, 1);
}
#[test]
fn multiple_bits_on_same_struct_share_one_push() {
let f = DeviceFeatures::new()
.with_timeline_semaphore()
.with_buffer_device_address();
assert_eq!(f.chain().len(), 2);
let v12 = f
.chain()
.get::<VkPhysicalDeviceVulkan12Features>()
.unwrap();
assert_eq!(v12.timelineSemaphore, 1);
assert_eq!(v12.bufferDeviceAddress, 1);
}
#[test]
fn mixing_core_versions_pushes_one_struct_per_version() {
let f = DeviceFeatures::new()
.with_sampler_anisotropy() .with_timeline_semaphore() .with_synchronization2(); assert_eq!(f.chain().len(), 3);
assert!(f.chain().get::<VkPhysicalDeviceVulkan12Features>().is_some());
assert!(f.chain().get::<VkPhysicalDeviceVulkan13Features>().is_some());
}
#[test]
fn escape_hatch_chains_any_feature_struct() {
let mut coop = VkPhysicalDeviceCooperativeMatrixFeaturesKHR::new_pnext();
coop.cooperativeMatrix = 1;
let f = DeviceFeatures::new().chain_extension_feature(coop);
let back = f
.chain()
.get::<VkPhysicalDeviceCooperativeMatrixFeaturesKHR>()
.expect("coop chained");
assert_eq!(back.cooperativeMatrix, 1);
}
#[test]
fn cooperative_matrix_generated_method_works() {
let f = DeviceFeatures::new().with_cooperative_matrix();
let coop = f
.chain()
.get::<VkPhysicalDeviceCooperativeMatrixFeaturesKHR>()
.expect("coop struct auto-pushed");
assert_eq!(coop.cooperativeMatrix, 1);
}
}