mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-08 20:01:30 +11:00
Start piet-gpu-derive
This version will be similar but somewhat different to what's in piet-metal now. Hopefully a little simpler to use (no distinction between packed and unpacked structs) and better structured.
This commit is contained in:
parent
1e1b9ff319
commit
afd47a7edd
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -25,6 +25,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "piet-gpu-derive"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "piet-gpu-hal"
|
||||
version = "0.1.0"
|
||||
|
@ -32,6 +41,41 @@ dependencies = [
|
|||
"ash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
|
||||
members = [
|
||||
"piet-gpu-derive",
|
||||
"piet-gpu-hal"
|
||||
]
|
||||
|
|
17
piet-gpu-derive/Cargo.toml
Normal file
17
piet-gpu-derive/Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "piet-gpu-derive"
|
||||
version = "0.0.0"
|
||||
authors = ["Raph Levien <raph.levien@gmail.com>"]
|
||||
description = "Proc macro derives for piet-gpu."
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
keywords = ["graphics", "2d"]
|
||||
categories = ["rendering::graphics-api"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = {version = "1.0.17", features = ["extra-traits", "full"]}
|
||||
quote = "1.0.3"
|
||||
proc-macro2 = "1.0.10"
|
16
piet-gpu-derive/src/lib.rs
Normal file
16
piet-gpu-derive/src/lib.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
mod parse;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::parse_macro_input;
|
||||
|
||||
use parse::GpuModule;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn piet_gpu(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as syn::ItemMod);
|
||||
//println!("input: {:#?}", input);
|
||||
let module = GpuModule::from_syn(&input).unwrap();
|
||||
let expanded = quote! {};
|
||||
expanded.into()
|
||||
}
|
199
piet-gpu-derive/src/parse.rs
Normal file
199
piet-gpu-derive/src/parse.rs
Normal file
|
@ -0,0 +1,199 @@
|
|||
//! Parsing of the source
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syn::{
|
||||
Expr, ExprLit, Fields, FieldsNamed, FieldsUnnamed, GenericArgument, ItemEnum, ItemStruct,
|
||||
Lit, PathArguments, TypeArray, TypePath,
|
||||
};
|
||||
|
||||
/// A scalar that can be represented in a packed data structure.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum GpuScalar {
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
F32,
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
// TODO: Add F16
|
||||
}
|
||||
|
||||
/// An algebraic datatype.
|
||||
#[derive(Clone)]
|
||||
pub enum GpuType {
|
||||
Scalar(GpuScalar),
|
||||
Vector(GpuScalar, usize),
|
||||
/// Used mostly for the body of enum variants.
|
||||
InlineStruct(String),
|
||||
Ref(Box<GpuType>),
|
||||
}
|
||||
|
||||
pub struct GpuEnum {
|
||||
pub name: String,
|
||||
pub variants: Vec<(String, Vec<GpuType>)>,
|
||||
}
|
||||
|
||||
pub enum GpuTypeDef {
|
||||
Struct(String, Vec<(String, GpuType)>),
|
||||
Enum(GpuEnum),
|
||||
}
|
||||
|
||||
pub struct GpuModule {
|
||||
pub name: String,
|
||||
pub defs: Vec<GpuTypeDef>,
|
||||
}
|
||||
|
||||
impl GpuScalar {
|
||||
fn from_syn(ty: &syn::Type) -> Option<Self> {
|
||||
ty_as_single_ident(ty).and_then(|ident| match ident.as_str() {
|
||||
"f32" => Some(GpuScalar::F32),
|
||||
"i8" => Some(GpuScalar::I8),
|
||||
"i16" => Some(GpuScalar::I16),
|
||||
"i32" => Some(GpuScalar::I32),
|
||||
"u8" => Some(GpuScalar::U8),
|
||||
"u16" => Some(GpuScalar::U16),
|
||||
"u32" => Some(GpuScalar::U32),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_as_single_ident(ty: &syn::Type) -> Option<String> {
|
||||
if let syn::Type::Path(TypePath {
|
||||
path: syn::Path { segments, .. },
|
||||
..
|
||||
}) = ty
|
||||
{
|
||||
if segments.len() == 1 {
|
||||
let seg = &segments[0];
|
||||
if seg.arguments == PathArguments::None {
|
||||
return Some(seg.ident.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl GpuType {
|
||||
fn from_syn(ty: &syn::Type) -> Result<Self, String> {
|
||||
//println!("gputype {:#?}", ty);
|
||||
if let Some(scalar) = GpuScalar::from_syn(ty) {
|
||||
return Ok(GpuType::Scalar(scalar));
|
||||
}
|
||||
if let Some(name) = ty_as_single_ident(ty) {
|
||||
// Note: we're not doing any validation here.
|
||||
return Ok(GpuType::InlineStruct(name));
|
||||
}
|
||||
match ty {
|
||||
syn::Type::Path(TypePath {
|
||||
path: syn::Path { segments, .. },
|
||||
..
|
||||
}) => {
|
||||
if segments.len() == 1 {
|
||||
let seg = &segments[0];
|
||||
if seg.ident == "Ref" {
|
||||
if let PathArguments::AngleBracketed(args) = &seg.arguments {
|
||||
if args.args.len() == 1 {
|
||||
if let GenericArgument::Type(inner) = &args.args[0] {
|
||||
let inner_ty = GpuType::from_syn(inner)?;
|
||||
return Ok(GpuType::Ref(Box::new(inner_ty)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err("unknown path case".into())
|
||||
}
|
||||
syn::Type::Array(TypeArray { elem, len, .. }) => {
|
||||
if let Some(elem) = GpuScalar::from_syn(&elem) {
|
||||
if let Some(len) = expr_int_lit(len) {
|
||||
// maybe sanity-check length here
|
||||
Ok(GpuType::Vector(elem, len))
|
||||
} else {
|
||||
Err("can't deal with variable length scalar arrays".into())
|
||||
}
|
||||
} else {
|
||||
Err("can't deal with non-scalar arrays".into())
|
||||
}
|
||||
}
|
||||
_ => Err("unknown type".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuTypeDef {
|
||||
fn from_syn(item: &syn::Item) -> Result<Self, String> {
|
||||
match item {
|
||||
syn::Item::Struct(ItemStruct {
|
||||
ident,
|
||||
fields: Fields::Named(FieldsNamed { named, .. }),
|
||||
..
|
||||
}) => {
|
||||
let mut fields = Vec::new();
|
||||
for field in named {
|
||||
let field_ty = GpuType::from_syn(&field.ty)?;
|
||||
let field_name = field.ident.as_ref().ok_or("need name".to_string())?;
|
||||
fields.push((field_name.to_string(), field_ty));
|
||||
}
|
||||
Ok(GpuTypeDef::Struct(ident.to_string(), fields))
|
||||
}
|
||||
syn::Item::Enum(ItemEnum {
|
||||
ident, variants, ..
|
||||
}) => {
|
||||
let mut v = Vec::new();
|
||||
for variant in variants {
|
||||
let vname = variant.ident.to_string();
|
||||
let mut fields = Vec::new();
|
||||
if let Fields::Unnamed(FieldsUnnamed { unnamed, .. }) = &variant.fields {
|
||||
for field in unnamed {
|
||||
fields.push(GpuType::from_syn(&field.ty)?);
|
||||
}
|
||||
}
|
||||
v.push((vname, fields));
|
||||
}
|
||||
let en = GpuEnum {
|
||||
name: ident.to_string(),
|
||||
variants: v,
|
||||
};
|
||||
Ok(GpuTypeDef::Enum(en))
|
||||
}
|
||||
_ => {
|
||||
eprintln!("{:#?}", item);
|
||||
Err("unknown item".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuModule {
|
||||
pub fn from_syn(module: &syn::ItemMod) -> Result<Self, String> {
|
||||
let name = module.ident.to_string();
|
||||
let mut defs = Vec::new();
|
||||
if let Some((_brace, items)) = &module.content {
|
||||
for item in items {
|
||||
let def = GpuTypeDef::from_syn(item)?;
|
||||
defs.push(def);
|
||||
}
|
||||
}
|
||||
Ok(GpuModule {
|
||||
name,
|
||||
defs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_int_lit(e: &Expr) -> Option<usize> {
|
||||
if let Expr::Lit(ExprLit {
|
||||
lit: Lit::Int(lit_int),
|
||||
..
|
||||
}) = e
|
||||
{
|
||||
lit_int.base10_parse().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue