diff options
Diffstat (limited to 'autogen/extensions.rs')
-rw-r--r-- | autogen/extensions.rs | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/autogen/extensions.rs b/autogen/extensions.rs new file mode 100644 index 0000000..b303da1 --- /dev/null +++ b/autogen/extensions.rs @@ -0,0 +1,399 @@ +// Copyright (c) 2021 The Vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use heck::SnakeCase; +use indexmap::IndexMap; +use std::io::Write; +use vk_parse::Extension; + +// This is not included in vk.xml, so it's added here manually +fn required_if_supported(name: &str) -> bool { + match name { + "VK_KHR_portability_subset" => true, + _ => false, + } +} + +fn conflicts_extensions(name: &str) -> &'static [&'static str] { + match name { + "VK_KHR_buffer_device_address" => &["VK_EXT_buffer_device_address"], + "VK_EXT_buffer_device_address" => &["VK_KHR_buffer_device_address"], + _ => &[], + } +} + +pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) { + write_device_extensions(writer, make_vulkano_extensions("device", &extensions)); + write!(writer, "\n\n").unwrap(); + write_instance_extensions(writer, make_vulkano_extensions("instance", &extensions)); +} + +#[derive(Clone, Debug)] +struct VulkanoExtension { + member: String, + raw: String, + requires_core: (u16, u16), + requires_device_extensions: Vec<String>, + requires_instance_extensions: Vec<String>, + required_if_supported: bool, + conflicts_device_extensions: Vec<String>, + status: Option<ExtensionStatus>, +} + +#[derive(Clone, Debug)] +enum Replacement { + Core((u16, u16)), + DeviceExtension(String), + InstanceExtension(String), +} + +#[derive(Clone, Debug)] +enum ExtensionStatus { + Promoted(Replacement), + Deprecated(Option<Replacement>), +} + +fn make_vulkano_extensions( + ty: &str, + extensions: &IndexMap<&str, &Extension>, +) -> Vec<VulkanoExtension> { + extensions + .values() + .filter(|ext| ext.ext_type.as_ref().unwrap() == ty) + .map(|ext| { + let raw = ext.name.to_owned(); + let member = raw.strip_prefix("VK_").unwrap().to_snake_case(); + let (major, minor) = ext + .requires_core + .as_ref() + .map(|s| s.as_str()) + .unwrap_or("1.0") + .split_once('.') + .unwrap(); + let requires_extensions: Vec<_> = ext + .requires + .as_ref() + .map(|s| s.split(',').collect()) + .unwrap_or_default(); + let conflicts_extensions = conflicts_extensions(&ext.name); + + VulkanoExtension { + member: member.clone(), + raw, + requires_core: (major.parse().unwrap(), minor.parse().unwrap()), + requires_device_extensions: requires_extensions + .iter() + .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device") + .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case()) + .collect(), + requires_instance_extensions: requires_extensions + .iter() + .filter(|&&vk_name| { + extensions[vk_name].ext_type.as_ref().unwrap() == "instance" + }) + .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case()) + .collect(), + required_if_supported: required_if_supported(ext.name.as_str()), + conflicts_device_extensions: conflicts_extensions + .iter() + .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device") + .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case()) + .collect(), + status: ext + .promotedto + .as_ref() + .map(|s| s.as_str()) + .and_then(|pr| { + if let Some(version) = pr.strip_prefix("VK_VERSION_") { + let (major, minor) = version.split_once('_').unwrap(); + Some(ExtensionStatus::Promoted(Replacement::Core(( + major.parse().unwrap(), + minor.parse().unwrap(), + )))) + } else { + let member = pr.strip_prefix("VK_").unwrap().to_snake_case(); + match extensions[pr].ext_type.as_ref().unwrap().as_str() { + "device" => Some(ExtensionStatus::Promoted( + Replacement::DeviceExtension(member), + )), + "instance" => Some(ExtensionStatus::Promoted( + Replacement::InstanceExtension(member), + )), + _ => unreachable!(), + } + } + }) + .or_else(|| { + ext.deprecatedby + .as_ref() + .map(|s| s.as_str()) + .and_then(|depr| { + if depr.is_empty() { + Some(ExtensionStatus::Deprecated(None)) + } else if let Some(version) = depr.strip_prefix("VK_VERSION_") { + let (major, minor) = version.split_once('_').unwrap(); + Some(ExtensionStatus::Deprecated(Some(Replacement::Core(( + major.parse().unwrap(), + minor.parse().unwrap(), + ))))) + } else { + let member = depr.strip_prefix("VK_").unwrap().to_snake_case(); + match extensions[depr].ext_type.as_ref().unwrap().as_str() { + "device" => Some(ExtensionStatus::Deprecated(Some( + Replacement::DeviceExtension(member), + ))), + "instance" => Some(ExtensionStatus::Deprecated(Some( + Replacement::InstanceExtension(member), + ))), + _ => unreachable!(), + } + } + }) + }), + } + }) + .collect() +} + +fn write_device_extensions<W, I>(writer: &mut W, extensions: I) +where + W: Write, + I: IntoIterator<Item = VulkanoExtension>, +{ + write!(writer, "crate::device::extensions::device_extensions! {{").unwrap(); + for ext in extensions { + write!(writer, "\n\t{} => {{", ext.member).unwrap(); + write_doc(writer, &ext); + write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap(); + write!( + writer, + "\n\t\trequires_core: crate::Version::V{}_{},", + ext.requires_core.0, ext.requires_core.1 + ) + .unwrap(); + write!( + writer, + "\n\t\trequires_device_extensions: [{}],", + ext.requires_device_extensions.join(", ") + ) + .unwrap(); + write!( + writer, + "\n\t\trequires_instance_extensions: [{}],", + ext.requires_instance_extensions.join(", ") + ) + .unwrap(); + write!( + writer, + "\n\t\trequired_if_supported: {},", + ext.required_if_supported + ) + .unwrap(); + write!( + writer, + "\n\t\tconflicts_device_extensions: [{}],", + ext.conflicts_device_extensions.join(", ") + ) + .unwrap(); + + /*if let Some(promoted_to_core) = ext.promoted_to_core { + write!( + writer, + "\n\t\tpromoted_to_core: Some(Version::V{}_{}),", + promoted_to_core.0, promoted_to_core.1 + ) + .unwrap(); + } else { + write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap(); + }*/ + + write!(writer, "\n\t}},").unwrap(); + } + write!(writer, "\n}}").unwrap(); +} + +fn write_instance_extensions<W, I>(writer: &mut W, extensions: I) +where + W: Write, + I: IntoIterator<Item = VulkanoExtension>, +{ + write!( + writer, + "crate::instance::extensions::instance_extensions! {{" + ) + .unwrap(); + for ext in extensions { + write!(writer, "\n\t{} => {{", ext.member).unwrap(); + write_doc(writer, &ext); + write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap(); + write!( + writer, + "\n\t\trequires_core: crate::Version::V{}_{},", + ext.requires_core.0, ext.requires_core.1 + ) + .unwrap(); + write!( + writer, + "\n\t\trequires_instance_extensions: [{}],", + ext.requires_instance_extensions.join(", ") + ) + .unwrap(); + + /*if let Some(promoted_to_core) = ext.promoted_to_core { + write!( + writer, + "\n\t\tpromoted_to_core: Some(crate::Version::V{}_{}),", + promoted_to_core.0, promoted_to_core.1 + ) + .unwrap(); + } else { + write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap(); + }*/ + + write!(writer, "\n\t}},").unwrap(); + } + write!(writer, "\n}}").unwrap(); +} + +fn write_doc<W>(writer: &mut W, ext: &VulkanoExtension) +where + W: Write, +{ + 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(); + + if ext.requires_core != (1, 0) { + write!( + writer, + "\n\t\t\t- Requires Vulkan {}.{}", + ext.requires_core.0, ext.requires_core.1 + ) + .unwrap(); + } + + if !ext.requires_device_extensions.is_empty() { + let links: Vec<_> = ext + .requires_device_extensions + .iter() + .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext)) + .collect(); + write!( + writer, + "\n\t\t\t- Requires device extension{}: {}", + if ext.requires_device_extensions.len() > 1 { + "s" + } else { + "" + }, + links.join(", ") + ) + .unwrap(); + } + + if !ext.requires_instance_extensions.is_empty() { + let links: Vec<_> = ext + .requires_instance_extensions + .iter() + .map(|ext| format!("[`{}`](crate::instance::InstanceExtensions::{0})", ext)) + .collect(); + write!( + writer, + "\n\t\t\t- Requires instance extension{}: {}", + if ext.requires_instance_extensions.len() > 1 { + "s" + } else { + "" + }, + links.join(", ") + ) + .unwrap(); + } + + if ext.required_if_supported { + write!( + writer, + "\n\t\t\t- Must be enabled if it is supported by the physical device", + ) + .unwrap(); + } + + if !ext.conflicts_device_extensions.is_empty() { + let links: Vec<_> = ext + .conflicts_device_extensions + .iter() + .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext)) + .collect(); + write!( + writer, + "\n\t\t\t- Conflicts with device extension{}: {}", + if ext.conflicts_device_extensions.len() > 1 { + "s" + } else { + "" + }, + links.join(", ") + ) + .unwrap(); + } + + if let Some(status) = ext.status.as_ref() { + match status { + ExtensionStatus::Promoted(replacement) => { + write!(writer, "\n\t\t\t- Promoted to ",).unwrap(); + + match replacement { + Replacement::Core(version) => { + write!(writer, "Vulkan {}.{}", version.0, version.1).unwrap(); + } + Replacement::DeviceExtension(ext) => { + write!(writer, "[`{}`](crate::device::DeviceExtensions::{0})", ext) + .unwrap(); + } + Replacement::InstanceExtension(ext) => { + write!( + writer, + "[`{}`](crate::instance::InstanceExtensions::{0})", + ext + ) + .unwrap(); + } + } + } + ExtensionStatus::Deprecated(replacement) => { + write!(writer, "\n\t\t\t- Deprecated ",).unwrap(); + + match replacement { + Some(Replacement::Core(version)) => { + write!(writer, "by Vulkan {}.{}", version.0, version.1).unwrap(); + } + Some(Replacement::DeviceExtension(ext)) => { + write!( + writer, + "by [`{}`](crate::device::DeviceExtensions::{0})", + ext + ) + .unwrap(); + } + Some(Replacement::InstanceExtension(ext)) => { + write!( + writer, + "by [`{}`](crate::instance::InstanceExtensions::{0})", + ext + ) + .unwrap(); + } + None => { + write!(writer, "without a replacement").unwrap(); + } + } + } + } + } + + write!(writer, "\n\t\t\",").unwrap(); +} |