216 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
// 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 indexmap::IndexMap;
 | 
						|
use std::{collections::HashMap, io::Write, path::Path};
 | 
						|
use vk_parse::{
 | 
						|
    Extension, ExtensionChild, Feature, InterfaceItem, Registry, RegistryChild, Type,
 | 
						|
    TypeCodeMarkup, TypeSpec, TypesChild,
 | 
						|
};
 | 
						|
 | 
						|
mod extensions;
 | 
						|
mod features;
 | 
						|
mod fns;
 | 
						|
mod properties;
 | 
						|
 | 
						|
pub fn write<W: Write>(writer: &mut W) {
 | 
						|
    let registry = get_registry("vk.xml");
 | 
						|
    let aliases = get_aliases(®istry);
 | 
						|
    let extensions = get_extensions(®istry);
 | 
						|
    let features = get_features(®istry);
 | 
						|
    let types = get_types(®istry, &aliases, &features, &extensions);
 | 
						|
    let header_version = get_header_version(®istry);
 | 
						|
 | 
						|
    write!(
 | 
						|
        writer,
 | 
						|
        "\
 | 
						|
        // This file is auto-generated by vulkano-gen from vk.xml header version {}.\n\
 | 
						|
        // It should not be edited manually. Changes should be made by editing vulkano-gen.\n\
 | 
						|
        \n",
 | 
						|
        header_version
 | 
						|
    )
 | 
						|
    .unwrap();
 | 
						|
 | 
						|
    extensions::write(writer, &extensions);
 | 
						|
    write!(writer, "\n\n").unwrap();
 | 
						|
    fns::write(writer, &extensions);
 | 
						|
    write!(writer, "\n\n").unwrap();
 | 
						|
    features::write(writer, &types, &extensions);
 | 
						|
    write!(writer, "\n\n").unwrap();
 | 
						|
    properties::write(writer, &types, &extensions);
 | 
						|
    write!(writer, "\n").unwrap();
 | 
						|
}
 | 
						|
 | 
						|
fn get_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
 | 
						|
    let (registry, errors) = vk_parse::parse_file(path.as_ref()).unwrap();
 | 
						|
 | 
						|
    if !errors.is_empty() {
 | 
						|
        eprintln!("The following errors were found while parsing the file:");
 | 
						|
 | 
						|
        for error in errors {
 | 
						|
            eprintln!("{:?}", error);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    registry
 | 
						|
}
 | 
						|
 | 
						|
fn get_aliases(registry: &Registry) -> HashMap<&str, &str> {
 | 
						|
    registry
 | 
						|
        .0
 | 
						|
        .iter()
 | 
						|
        .filter_map(|child| {
 | 
						|
            if let RegistryChild::Types(types) = child {
 | 
						|
                return Some(types.children.iter().filter_map(|ty| {
 | 
						|
                    if let TypesChild::Type(ty) = ty {
 | 
						|
                        if let Some(alias) = ty.alias.as_ref().map(|s| s.as_str()) {
 | 
						|
                            return Some((ty.name.as_ref().unwrap().as_str(), alias));
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    None
 | 
						|
                }));
 | 
						|
            }
 | 
						|
            None
 | 
						|
        })
 | 
						|
        .flatten()
 | 
						|
        .collect()
 | 
						|
}
 | 
						|
 | 
						|
fn get_extensions(registry: &Registry) -> IndexMap<&str, &Extension> {
 | 
						|
    let iter = registry
 | 
						|
        .0
 | 
						|
        .iter()
 | 
						|
        .filter_map(|child| {
 | 
						|
            if let RegistryChild::Extensions(ext) = child {
 | 
						|
                return Some(ext.children.iter().filter_map(|ext| {
 | 
						|
                    if ext.supported.as_ref().map(|s| s.as_str()) == Some("vulkan")
 | 
						|
                        && ext.obsoletedby.is_none()
 | 
						|
                    {
 | 
						|
                        return Some(ext);
 | 
						|
                    }
 | 
						|
                    None
 | 
						|
                }));
 | 
						|
            }
 | 
						|
            None
 | 
						|
        })
 | 
						|
        .flatten();
 | 
						|
 | 
						|
    let extensions: HashMap<&str, &Extension> =
 | 
						|
        iter.clone().map(|ext| (ext.name.as_str(), ext)).collect();
 | 
						|
    let mut names: Vec<_> = iter.map(|ext| ext.name.as_str()).collect();
 | 
						|
    names.sort_unstable_by_key(|name| {
 | 
						|
        if name.starts_with("VK_KHR_") {
 | 
						|
            (0, name.to_owned())
 | 
						|
        } else if name.starts_with("VK_EXT_") {
 | 
						|
            (1, name.to_owned())
 | 
						|
        } else {
 | 
						|
            (2, name.to_owned())
 | 
						|
        }
 | 
						|
    });
 | 
						|
 | 
						|
    names.iter().map(|&name| (name, extensions[name])).collect()
 | 
						|
}
 | 
						|
 | 
						|
fn get_features(registry: &Registry) -> IndexMap<&str, &Feature> {
 | 
						|
    registry
 | 
						|
        .0
 | 
						|
        .iter()
 | 
						|
        .filter_map(|child| {
 | 
						|
            if let RegistryChild::Feature(feat) = child {
 | 
						|
                return Some((feat.name.as_str(), feat));
 | 
						|
            }
 | 
						|
 | 
						|
            None
 | 
						|
        })
 | 
						|
        .collect()
 | 
						|
}
 | 
						|
 | 
						|
fn get_types<'a>(
 | 
						|
    registry: &'a Registry,
 | 
						|
    aliases: &'a HashMap<&str, &str>,
 | 
						|
    features: &'a IndexMap<&str, &Feature>,
 | 
						|
    extensions: &'a IndexMap<&str, &Extension>,
 | 
						|
) -> HashMap<&'a str, (&'a Type, Vec<&'a str>)> {
 | 
						|
    let mut types: HashMap<&str, (&Type, Vec<&str>)> = registry
 | 
						|
        .0
 | 
						|
        .iter()
 | 
						|
        .filter_map(|child| {
 | 
						|
            if let RegistryChild::Types(types) = child {
 | 
						|
                return Some(types.children.iter().filter_map(|ty| {
 | 
						|
                    if let TypesChild::Type(ty) = ty {
 | 
						|
                        if ty.alias.is_none() {
 | 
						|
                            return ty.name.as_ref().map(|name| (name.as_str(), (ty, vec![])));
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    None
 | 
						|
                }));
 | 
						|
            }
 | 
						|
            None
 | 
						|
        })
 | 
						|
        .flatten()
 | 
						|
        .collect();
 | 
						|
 | 
						|
    features
 | 
						|
        .iter()
 | 
						|
        .map(|(name, feature)| (name, &feature.children))
 | 
						|
        .chain(extensions.iter().map(|(name, ext)| (name, &ext.children)))
 | 
						|
        .for_each(|(provided_by, children)| {
 | 
						|
            children
 | 
						|
                .iter()
 | 
						|
                .filter_map(|child| {
 | 
						|
                    if let ExtensionChild::Require { items, .. } = child {
 | 
						|
                        return Some(items.iter());
 | 
						|
                    }
 | 
						|
                    None
 | 
						|
                })
 | 
						|
                .flatten()
 | 
						|
                .filter_map(|item| {
 | 
						|
                    if let InterfaceItem::Type { name, .. } = item {
 | 
						|
                        return Some(name.as_str());
 | 
						|
                    }
 | 
						|
                    None
 | 
						|
                })
 | 
						|
                .for_each(|item_name| {
 | 
						|
                    let item_name = aliases.get(item_name).unwrap_or(&item_name);
 | 
						|
                    if let Some(ty) = types.get_mut(item_name) {
 | 
						|
                        if !ty.1.contains(provided_by) {
 | 
						|
                            ty.1.push(provided_by);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                });
 | 
						|
        });
 | 
						|
 | 
						|
    types
 | 
						|
        .into_iter()
 | 
						|
        .filter(|(_key, val)| !val.1.is_empty())
 | 
						|
        .collect()
 | 
						|
}
 | 
						|
 | 
						|
fn get_header_version(registry: &Registry) -> u16 {
 | 
						|
    registry.0.iter()
 | 
						|
        .find_map(|child| -> Option<u16> {
 | 
						|
            if let RegistryChild::Types(types) = child {
 | 
						|
                return types.children.iter().find_map(|ty| -> Option<u16> {
 | 
						|
                    if let TypesChild::Type(ty) = ty {
 | 
						|
                        if let TypeSpec::Code(code) = &ty.spec {
 | 
						|
                            if code.markup.iter().any(|mkup| matches!(mkup, TypeCodeMarkup::Name(name) if name == "VK_HEADER_VERSION")) {
 | 
						|
                                return Some(code.code.rsplit_once(' ').unwrap().1.parse().unwrap());
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
 | 
						|
                    None
 | 
						|
                });
 | 
						|
            }
 | 
						|
 | 
						|
            None
 | 
						|
        })
 | 
						|
        .unwrap()
 | 
						|
}
 |