1use super::CallError;
3use crate as vk;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct FeatureValue {
9 pub structure: vk::StructureType,
10 pub member: &'static str,
11 pub enabled: bool,
12}
13
14#[derive(Debug)]
21pub struct Features {
22 values: Vec<FeatureValue>,
23 structures: Vec<vk::StructureType>,
24 unrecognized: Vec<vk::StructureType>,
25}
26
27impl Features {
28 pub fn values(&self) -> &[FeatureValue] {
31 &self.values
32 }
33
34 pub fn unrecognized_structures(&self) -> &[vk::StructureType] {
38 &self.unrecognized
39 }
40
41 pub fn enabled(&self, structure: vk::StructureType, member: &str) -> Option<bool> {
45 self
46 .values
47 .iter()
48 .find(|value| value.structure == structure && value.member == member)
49 .map(|value| value.enabled)
50 }
51
52 pub fn require(
59 &self,
60 requirements: &[(vk::StructureType, &'static str)],
61 ) -> Result<(), CallError> {
62 for &(structure, member) in requirements {
63 if self.enabled(structure, member) != Some(true) {
64 return Err(CallError::FeatureNotEnabled { structure, member });
65 }
66 }
67 Ok(())
68 }
69
70 pub(super) fn record(
71 &mut self,
72 structure: vk::StructureType,
73 members: &[(&'static str, vk::Bool32)],
74 ) -> Result<(), CallError> {
75 if self.structures.contains(&structure) {
76 return Err(CallError::InvalidMetadata(
77 "duplicate enabled-feature record",
78 ));
79 }
80 self
81 .structures
82 .try_reserve(1)
83 .map_err(|_| CallError::HostAllocationFailed)?;
84 self
85 .values
86 .try_reserve(members.len())
87 .map_err(|_| CallError::HostAllocationFailed)?;
88 self.structures.push(structure);
89 self
90 .values
91 .extend(members.iter().map(|&(member, value)| FeatureValue {
92 structure,
93 member,
94 enabled: value != vk::FALSE,
95 }));
96 Ok(())
97 }
98
99 pub(super) unsafe fn capture(info: &vk::DeviceCreateInfo) -> Result<Self, CallError> {
102 const MAX_NODES: usize = 1024;
103 let mut result = Self {
104 values: Vec::new(),
105 structures: Vec::new(),
106 unrecognized: Vec::new(),
107 };
108 let mut visited = Vec::new();
109 let mut node = info.p_next.cast::<vk::BaseInStructure>();
110 let mut features2 = false;
111 while !node.is_null() {
112 if visited.len() == MAX_NODES || visited.contains(&node) {
113 return Err(CallError::InvalidMetadata(
114 "cyclic or oversized device feature chain",
115 ));
116 }
117 visited
118 .try_reserve(1)
119 .map_err(|_| CallError::HostAllocationFailed)?;
120 visited.push(node);
121 let header = unsafe { &*node };
123 if header.s_type == vk::StructureType::PHYSICAL_DEVICE_FEATURES_2 {
124 if !info.p_enabled_features.is_null() {
125 return Err(CallError::InvalidMetadata(
126 "Features2 and p_enabled_features are mutually exclusive",
127 ));
128 }
129 features2 = true;
130 }
131 if !unsafe { super::feature_generated::capture_node(node, &mut result) }? {
133 result
134 .unrecognized
135 .try_reserve(1)
136 .map_err(|_| CallError::HostAllocationFailed)?;
137 result.unrecognized.push(header.s_type);
138 }
139 node = header.p_next;
140 }
141 if !features2 {
142 let defaults = unsafe { std::mem::zeroed::<vk::PhysicalDeviceFeatures>() };
144 let base = unsafe { info.p_enabled_features.as_ref() }.unwrap_or(&defaults);
146 super::feature_generated::capture_base(base, &mut result)?;
147 }
148 Ok(result)
149 }
150}
151
152#[cfg(test)]
153#[path = "../../../test/rs/load/test_feature.rs"]
154mod tests;