• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 The Vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use heck::SnakeCase;
11 use indexmap::IndexMap;
12 use std::io::Write;
13 use vk_parse::Extension;
14 
15 // This is not included in vk.xml, so it's added here manually
required_if_supported(name: &str) -> bool16 fn required_if_supported(name: &str) -> bool {
17     match name {
18         "VK_KHR_portability_subset" => true,
19         _ => false,
20     }
21 }
22 
conflicts_extensions(name: &str) -> &'static [&'static str]23 fn conflicts_extensions(name: &str) -> &'static [&'static str] {
24     match name {
25         "VK_KHR_buffer_device_address" => &["VK_EXT_buffer_device_address"],
26         "VK_EXT_buffer_device_address" => &["VK_KHR_buffer_device_address"],
27         _ => &[],
28     }
29 }
30 
write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>)31 pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) {
32     write_device_extensions(writer, make_vulkano_extensions("device", &extensions));
33     write!(writer, "\n\n").unwrap();
34     write_instance_extensions(writer, make_vulkano_extensions("instance", &extensions));
35 }
36 
37 #[derive(Clone, Debug)]
38 struct VulkanoExtension {
39     member: String,
40     raw: String,
41     requires_core: (u16, u16),
42     requires_device_extensions: Vec<String>,
43     requires_instance_extensions: Vec<String>,
44     required_if_supported: bool,
45     conflicts_device_extensions: Vec<String>,
46     status: Option<ExtensionStatus>,
47 }
48 
49 #[derive(Clone, Debug)]
50 enum Replacement {
51     Core((u16, u16)),
52     DeviceExtension(String),
53     InstanceExtension(String),
54 }
55 
56 #[derive(Clone, Debug)]
57 enum ExtensionStatus {
58     Promoted(Replacement),
59     Deprecated(Option<Replacement>),
60 }
61 
make_vulkano_extensions( ty: &str, extensions: &IndexMap<&str, &Extension>, ) -> Vec<VulkanoExtension>62 fn make_vulkano_extensions(
63     ty: &str,
64     extensions: &IndexMap<&str, &Extension>,
65 ) -> Vec<VulkanoExtension> {
66     extensions
67         .values()
68         .filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
69         .map(|ext| {
70             let raw = ext.name.to_owned();
71             let member = raw.strip_prefix("VK_").unwrap().to_snake_case();
72             let (major, minor) = ext
73                 .requires_core
74                 .as_ref()
75                 .map(|s| s.as_str())
76                 .unwrap_or("1.0")
77                 .split_once('.')
78                 .unwrap();
79             let requires_extensions: Vec<_> = ext
80                 .requires
81                 .as_ref()
82                 .map(|s| s.split(',').collect())
83                 .unwrap_or_default();
84             let conflicts_extensions = conflicts_extensions(&ext.name);
85 
86             VulkanoExtension {
87                 member: member.clone(),
88                 raw,
89                 requires_core: (major.parse().unwrap(), minor.parse().unwrap()),
90                 requires_device_extensions: requires_extensions
91                     .iter()
92                     .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
93                     .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
94                     .collect(),
95                 requires_instance_extensions: requires_extensions
96                     .iter()
97                     .filter(|&&vk_name| {
98                         extensions[vk_name].ext_type.as_ref().unwrap() == "instance"
99                     })
100                     .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
101                     .collect(),
102                 required_if_supported: required_if_supported(ext.name.as_str()),
103                 conflicts_device_extensions: conflicts_extensions
104                     .iter()
105                     .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
106                     .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
107                     .collect(),
108                 status: ext
109                     .promotedto
110                     .as_ref()
111                     .map(|s| s.as_str())
112                     .and_then(|pr| {
113                         if let Some(version) = pr.strip_prefix("VK_VERSION_") {
114                             let (major, minor) = version.split_once('_').unwrap();
115                             Some(ExtensionStatus::Promoted(Replacement::Core((
116                                 major.parse().unwrap(),
117                                 minor.parse().unwrap(),
118                             ))))
119                         } else {
120                             let member = pr.strip_prefix("VK_").unwrap().to_snake_case();
121                             match extensions[pr].ext_type.as_ref().unwrap().as_str() {
122                                 "device" => Some(ExtensionStatus::Promoted(
123                                     Replacement::DeviceExtension(member),
124                                 )),
125                                 "instance" => Some(ExtensionStatus::Promoted(
126                                     Replacement::InstanceExtension(member),
127                                 )),
128                                 _ => unreachable!(),
129                             }
130                         }
131                     })
132                     .or_else(|| {
133                         ext.deprecatedby
134                             .as_ref()
135                             .map(|s| s.as_str())
136                             .and_then(|depr| {
137                                 if depr.is_empty() {
138                                     Some(ExtensionStatus::Deprecated(None))
139                                 } else if let Some(version) = depr.strip_prefix("VK_VERSION_") {
140                                     let (major, minor) = version.split_once('_').unwrap();
141                                     Some(ExtensionStatus::Deprecated(Some(Replacement::Core((
142                                         major.parse().unwrap(),
143                                         minor.parse().unwrap(),
144                                     )))))
145                                 } else {
146                                     let member = depr.strip_prefix("VK_").unwrap().to_snake_case();
147                                     match extensions[depr].ext_type.as_ref().unwrap().as_str() {
148                                         "device" => Some(ExtensionStatus::Deprecated(Some(
149                                             Replacement::DeviceExtension(member),
150                                         ))),
151                                         "instance" => Some(ExtensionStatus::Deprecated(Some(
152                                             Replacement::InstanceExtension(member),
153                                         ))),
154                                         _ => unreachable!(),
155                                     }
156                                 }
157                             })
158                     }),
159             }
160         })
161         .collect()
162 }
163 
write_device_extensions<W, I>(writer: &mut W, extensions: I) where W: Write, I: IntoIterator<Item = VulkanoExtension>,164 fn write_device_extensions<W, I>(writer: &mut W, extensions: I)
165 where
166     W: Write,
167     I: IntoIterator<Item = VulkanoExtension>,
168 {
169     write!(writer, "crate::device::extensions::device_extensions! {{").unwrap();
170     for ext in extensions {
171         write!(writer, "\n\t{} => {{", ext.member).unwrap();
172         write_doc(writer, &ext);
173         write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
174         write!(
175             writer,
176             "\n\t\trequires_core: crate::Version::V{}_{},",
177             ext.requires_core.0, ext.requires_core.1
178         )
179         .unwrap();
180         write!(
181             writer,
182             "\n\t\trequires_device_extensions: [{}],",
183             ext.requires_device_extensions.join(", ")
184         )
185         .unwrap();
186         write!(
187             writer,
188             "\n\t\trequires_instance_extensions: [{}],",
189             ext.requires_instance_extensions.join(", ")
190         )
191         .unwrap();
192         write!(
193             writer,
194             "\n\t\trequired_if_supported: {},",
195             ext.required_if_supported
196         )
197         .unwrap();
198         write!(
199             writer,
200             "\n\t\tconflicts_device_extensions: [{}],",
201             ext.conflicts_device_extensions.join(", ")
202         )
203         .unwrap();
204 
205         /*if let Some(promoted_to_core) = ext.promoted_to_core {
206             write!(
207                 writer,
208                 "\n\t\tpromoted_to_core: Some(Version::V{}_{}),",
209                 promoted_to_core.0, promoted_to_core.1
210             )
211             .unwrap();
212         } else {
213             write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
214         }*/
215 
216         write!(writer, "\n\t}},").unwrap();
217     }
218     write!(writer, "\n}}").unwrap();
219 }
220 
write_instance_extensions<W, I>(writer: &mut W, extensions: I) where W: Write, I: IntoIterator<Item = VulkanoExtension>,221 fn write_instance_extensions<W, I>(writer: &mut W, extensions: I)
222 where
223     W: Write,
224     I: IntoIterator<Item = VulkanoExtension>,
225 {
226     write!(
227         writer,
228         "crate::instance::extensions::instance_extensions! {{"
229     )
230     .unwrap();
231     for ext in extensions {
232         write!(writer, "\n\t{} => {{", ext.member).unwrap();
233         write_doc(writer, &ext);
234         write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
235         write!(
236             writer,
237             "\n\t\trequires_core: crate::Version::V{}_{},",
238             ext.requires_core.0, ext.requires_core.1
239         )
240         .unwrap();
241         write!(
242             writer,
243             "\n\t\trequires_instance_extensions: [{}],",
244             ext.requires_instance_extensions.join(", ")
245         )
246         .unwrap();
247 
248         /*if let Some(promoted_to_core) = ext.promoted_to_core {
249             write!(
250                 writer,
251                 "\n\t\tpromoted_to_core: Some(crate::Version::V{}_{}),",
252                 promoted_to_core.0, promoted_to_core.1
253             )
254             .unwrap();
255         } else {
256             write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
257         }*/
258 
259         write!(writer, "\n\t}},").unwrap();
260     }
261     write!(writer, "\n}}").unwrap();
262 }
263 
write_doc<W>(writer: &mut W, ext: &VulkanoExtension) where W: Write,264 fn write_doc<W>(writer: &mut W, ext: &VulkanoExtension)
265 where
266     W: Write,
267 {
268     write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{}.html)", ext.raw).unwrap();
269 
270     if ext.requires_core != (1, 0) {
271         write!(
272             writer,
273             "\n\t\t\t- Requires Vulkan {}.{}",
274             ext.requires_core.0, ext.requires_core.1
275         )
276         .unwrap();
277     }
278 
279     if !ext.requires_device_extensions.is_empty() {
280         let links: Vec<_> = ext
281             .requires_device_extensions
282             .iter()
283             .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
284             .collect();
285         write!(
286             writer,
287             "\n\t\t\t- Requires device extension{}: {}",
288             if ext.requires_device_extensions.len() > 1 {
289                 "s"
290             } else {
291                 ""
292             },
293             links.join(", ")
294         )
295         .unwrap();
296     }
297 
298     if !ext.requires_instance_extensions.is_empty() {
299         let links: Vec<_> = ext
300             .requires_instance_extensions
301             .iter()
302             .map(|ext| format!("[`{}`](crate::instance::InstanceExtensions::{0})", ext))
303             .collect();
304         write!(
305             writer,
306             "\n\t\t\t- Requires instance extension{}: {}",
307             if ext.requires_instance_extensions.len() > 1 {
308                 "s"
309             } else {
310                 ""
311             },
312             links.join(", ")
313         )
314         .unwrap();
315     }
316 
317     if ext.required_if_supported {
318         write!(
319             writer,
320             "\n\t\t\t- Must be enabled if it is supported by the physical device",
321         )
322         .unwrap();
323     }
324 
325     if !ext.conflicts_device_extensions.is_empty() {
326         let links: Vec<_> = ext
327             .conflicts_device_extensions
328             .iter()
329             .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
330             .collect();
331         write!(
332             writer,
333             "\n\t\t\t- Conflicts with device extension{}: {}",
334             if ext.conflicts_device_extensions.len() > 1 {
335                 "s"
336             } else {
337                 ""
338             },
339             links.join(", ")
340         )
341         .unwrap();
342     }
343 
344     if let Some(status) = ext.status.as_ref() {
345         match status {
346             ExtensionStatus::Promoted(replacement) => {
347                 write!(writer, "\n\t\t\t- Promoted to ",).unwrap();
348 
349                 match replacement {
350                     Replacement::Core(version) => {
351                         write!(writer, "Vulkan {}.{}", version.0, version.1).unwrap();
352                     }
353                     Replacement::DeviceExtension(ext) => {
354                         write!(writer, "[`{}`](crate::device::DeviceExtensions::{0})", ext)
355                             .unwrap();
356                     }
357                     Replacement::InstanceExtension(ext) => {
358                         write!(
359                             writer,
360                             "[`{}`](crate::instance::InstanceExtensions::{0})",
361                             ext
362                         )
363                         .unwrap();
364                     }
365                 }
366             }
367             ExtensionStatus::Deprecated(replacement) => {
368                 write!(writer, "\n\t\t\t- Deprecated ",).unwrap();
369 
370                 match replacement {
371                     Some(Replacement::Core(version)) => {
372                         write!(writer, "by Vulkan {}.{}", version.0, version.1).unwrap();
373                     }
374                     Some(Replacement::DeviceExtension(ext)) => {
375                         write!(
376                             writer,
377                             "by [`{}`](crate::device::DeviceExtensions::{0})",
378                             ext
379                         )
380                         .unwrap();
381                     }
382                     Some(Replacement::InstanceExtension(ext)) => {
383                         write!(
384                             writer,
385                             "by [`{}`](crate::instance::InstanceExtensions::{0})",
386                             ext
387                         )
388                         .unwrap();
389                     }
390                     None => {
391                         write!(writer, "without a replacement").unwrap();
392                     }
393                 }
394             }
395         }
396     }
397 
398     write!(writer, "\n\t\t\",").unwrap();
399 }
400