Skip to content

Commit

Permalink
generator: Generate low-level structs with bindgen (for vk_video)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarijnS95 committed May 30, 2021
1 parent f97d5f7 commit 7184f0f
Show file tree
Hide file tree
Showing 7 changed files with 7,570 additions and 13 deletions.
3 changes: 3 additions & 0 deletions ash/src/vk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ mod feature_extensions;
pub use feature_extensions::*;
mod features;
pub use features::*;
#[allow(nonstandard_style)]
mod native;
pub use native::*;
mod platform_types;
pub use platform_types::*;
#[doc = r" Iterates through the pointer chain. Includes the item that is passed into the function."]
Expand Down
1 change: 1 addition & 0 deletions ash/src/vk/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::vk::aliases::*;
use crate::vk::bitflags::*;
use crate::vk::constants::*;
use crate::vk::enums::*;
use crate::vk::native::*;
use crate::vk::platform_types::*;
use crate::vk::{ptr_chain_iter, Handle};
use std::fmt;
Expand Down
7,439 changes: 7,439 additions & 0 deletions ash/src/vk/native.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["Maik Klein <maikklein@googlemail.com>"]
edition = "2018"

[dependencies]
bindgen = "0.58"
heck = "0.3"
itertools = "0.10"
nom = "6.0"
Expand Down
7 changes: 2 additions & 5 deletions generator/src/bin/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ use std::path::Path;
fn main() {
let cwd = std::env::current_dir().unwrap();
if cwd.ends_with("generator") {
write_source_code(Path::new("Vulkan-Headers/registry/vk.xml"), "../ash/src");
write_source_code(Path::new("Vulkan-Headers"), "../ash/src");
} else {
write_source_code(
Path::new("generator/Vulkan-Headers/registry/vk.xml"),
"ash/src",
);
write_source_code(Path::new("generator/Vulkan-Headers"), "ash/src");
}
}
130 changes: 123 additions & 7 deletions generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
use itertools::Itertools;
use nom::{
alt,
character::complete::{digit1, hex_digit1},
complete, delimited, do_parse, map, named, one_of, opt, pair, preceded, tag, terminated, value,
alt, char,
character::complete::{digit1, hex_digit1, multispace1},
complete, delimited, do_parse, many1, map, named, none_of, one_of, opt, pair, preceded, tag,
terminated, value,
};
use once_cell::sync::Lazy;
use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree};
Expand Down Expand Up @@ -106,6 +107,23 @@ named!(cfloat<&str, f32>,
terminated!(nom::number::complete::float, one_of!("fF"))
);

// Like a C string, but does not support quote escaping and expects at least one character.
// If needed, use https://github.com/Geal/nom/blob/8e09f0c3029d32421b5b69fb798cef6855d0c8df/tests/json.rs#L61-L81
named!(c_include_string<&str, String>,
delimited!(
char!('"'),
map!(
many1!(none_of!("\"")),
|chars| chars.iter().map(char::to_string).join("")
),
char!('"')
)
);

named!(c_include<&str, String>,
preceded!(tag!("#include"), preceded!(multispace1, c_include_string))
);

fn khronos_link<S: Display + ?Sized>(name: &S) -> Literal {
Literal::string(&format!(
"<https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{name}.html>",
Expand Down Expand Up @@ -2493,6 +2511,62 @@ pub fn generate_const_debugs(const_values: &BTreeMap<Ident, ConstantTypeInfo>) -
#(#impls)*
}
}
pub fn extract_native_types(registry: &vk_parse::Registry) -> (Vec<(String, String)>, Vec<String>) {
// Not a HashMap so that headers are processed in order of definition:
let mut header_includes = vec![];
let mut header_types = vec![];

let types = registry
.0
.iter()
.filter_map(|item| match item {
vk_parse::RegistryChild::Types(ref ty) => {
Some(ty.children.iter().filter_map(|child| match child {
vk_parse::TypesChild::Type(ty) => Some(ty),
_ => None,
}))
}
_ => None,
})
.flatten();

for ty in types {
match ty.category.as_deref() {
Some("include") => {
// `category="include"` lacking an `#include` directive are generally "irrelevant" system headers.
if let vk_parse::TypeSpec::Code(code) = &ty.spec {
let name = ty
.name
.clone()
.expect("Include type must provide header name");
assert!(
header_includes
.iter()
.all(|(other_name, _)| other_name != &name),
"Header `{}` being redefined",
name
);

let (rem, path) = c_include(&code.code)
.expect("Failed to parse `#include` from `category=\"include\"` directive");
assert!(rem.is_empty());
header_includes.push((name, path));
}
}
Some(_) => {}
None => {
if let Some(header_name) = ty.requires.clone() {
if header_includes.iter().any(|(name, _)| name == &header_name) {
// Omit types from system and other headers
header_types.push(ty.name.clone().expect("Type must have a name"));
}
}
}
};
}

(header_includes, header_types)
}
pub fn generate_aliases_of_types(
types: &vk_parse::Types,
ty_cache: &mut HashSet<Ident, impl BuildHasher>,
Expand All @@ -2519,10 +2593,11 @@ pub fn generate_aliases_of_types(
#(#aliases)*
}
}
pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
pub fn write_source_code<P: AsRef<Path>>(vk_headers_dir: &Path, src_dir: P) {
let vk_xml = vk_headers_dir.join("registry/vk.xml");
use std::fs::File;
use std::io::Write;
let (spec2, _errors) = vk_parse::parse_file(vk_xml).expect("Invalid xml file");
let (spec2, _errors) = vk_parse::parse_file(&vk_xml).expect("Invalid xml file");
let extensions: &Vec<vk_parse::Extension> = spec2
.0
.iter()
Expand All @@ -2544,7 +2619,7 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
})
.collect();

let spec = vk_parse::parse_file_as_vkxml(vk_xml).expect("Invalid xml file.");
let spec = vk_parse::parse_file_as_vkxml(&vk_xml).expect("Invalid xml file.");
let cmd_aliases: HashMap<String, String> = spec2
.0
.iter()
Expand Down Expand Up @@ -2743,11 +2818,12 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
use std::fmt;
use std::os::raw::*;
use crate::vk::{Handle, ptr_chain_iter};
use crate::vk::platform_types::*;
use crate::vk::aliases::*;
use crate::vk::bitflags::*;
use crate::vk::constants::*;
use crate::vk::enums::*;
use crate::vk::native::*;
use crate::vk::platform_types::*;
#(#definition_code)*
};

Expand Down Expand Up @@ -2825,6 +2901,9 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
pub use feature_extensions::*;
mod features;
pub use features::*;
#[allow(nonstandard_style)]
mod native;
pub use native::*;
mod platform_types;
pub use platform_types::*;

Expand Down Expand Up @@ -2857,4 +2936,41 @@ pub fn write_source_code<P: AsRef<Path>>(vk_xml: &Path, src_dir: P) {
write!(&mut vk_aliases_file, "{}", aliases).expect("Unable to write vk/aliases.rs");
write!(&mut vk_rs_file, "{} {}", vk_rs_clippy_lints, vk_rs_code)
.expect("Unable to write vk.rs");

let vk_include = vk_headers_dir.join("include");

let mut bindings = bindgen::Builder::default()
.clang_arg(format!(
"-I{}",
vk_include.to_str().expect("Valid UTF8 string")
))
.clang_arg(format!(
"-I{}",
vk_include
.join("vulkan")
.to_str()
.expect("Valid UTF8 string")
));

let (header_includes, header_types) = extract_native_types(&spec2);

for (_name, path) in header_includes {
let path = if path == "vk_platform.h" {
// Fix broken path, https://github.com/KhronosGroup/Vulkan-Docs/pull/1538
vk_include.join("vulkan").join(path)
} else {
vk_include.join(path)
};
bindings = bindings.header(path.to_str().expect("Valid UTF8 string"));
}

for typ in header_types {
bindings = bindings.allowlist_type(typ);
}

bindings
.generate()
.expect("Unable to generate native bindings")
.write_to_file(vk_dir.join("native.rs"))
.expect("Couldn't write native bindings!");
}

0 comments on commit 7184f0f

Please sign in to comment.