这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ members = [
[dependencies]
bevy_interleave_interface = { path = "crates/bevy_interleave_interface", version = "0.1.0" }
bevy_interleave_macros = { path = "crates/bevy_interleave_macros", version = "0.1.0" }
bytemuck = "1.14"
serde = "1.0"

# [dependencies.bevy]
# version = "0.12"
# default-features = false
[dependencies.bevy]
version = "0.12"
default-features = false


[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_interleave_interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ keywords = [
"bevy",
"shader-types",
]


[dependencies.bevy]
version = "0.12"
default-features = false
features = ["bevy_render"]
44 changes: 39 additions & 5 deletions crates/bevy_interleave_interface/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@

pub trait Planar<T> {
fn get(&self, index: usize) -> T;
pub trait GpuStoragePlanar {
type PackedType;
type PlanarType;

fn bind_group(
&self,
render_device: &bevy::render::renderer::RenderDevice,
layout: &bevy::render::render_resource::BindGroupLayout,
) -> bevy::render::render_resource::BindGroup;

fn bind_group_layout(
&self,
render_device: &bevy::render::renderer::RenderDevice,
read_only: bool,
) -> bevy::render::render_resource::BindGroupLayout;

fn ordered_field_names(&self) -> &'static [&'static str];

fn prepare(
render_device: &bevy::render::renderer::RenderDevice,
planar: &Self::PlanarType,
) -> Self;
}


pub trait MinBindingSize {
type PackedType;

fn min_binding_sizes() -> &'static [usize];
}


pub trait Planar {
type PackedType;

fn get(&self, index: usize) -> Self::PackedType;
fn is_empty(&self) -> bool;
fn len(&self) -> usize;
fn set(&mut self, index: usize, value: T);
fn to_interleaved(&self) -> Vec<T>;
fn set(&mut self, index: usize, value: Self::PackedType);
fn to_interleaved(&self) -> Vec<Self::PackedType>;

fn from_interleaved(packed: Vec<T>) -> Self where Self: Sized;
fn from_interleaved(packed: Vec<Self::PackedType>) -> Self where Self: Sized;
}
12 changes: 10 additions & 2 deletions crates/bevy_interleave_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ keywords = [

[dependencies]
bevy_interleave_interface = { path = "../bevy_interleave_interface", version = "0.1.0" }
syn = "2.0"
quote = "1.0"
bytemuck = "1.14"
convert_case = "0.6"
proc-macro2 = "1.0"
quote = "1.0"
sha1 = "0.10"
syn = "2.0"

[dependencies.bevy]
version = "0.12"
default-features = false
features = ["bevy_render"]


[lib]
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_interleave_macros/src/bindings/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod storage;
pub mod texture;
202 changes: 202 additions & 0 deletions crates/bevy_interleave_macros/src/bindings/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
use convert_case::{
Case,
Casing,
};
use quote::quote;
use syn::{
Data,
DeriveInput,
Error,
Fields,
FieldsNamed,
Ident,
Result,
};


pub fn storage_bindings(input: &DeriveInput) -> Result<quote::__private::TokenStream> {
let name = &input.ident;

let planar_name = Ident::new(&format!("Planar{}", name), name.span());
let gpu_planar_name = Ident::new(&format!("GpuPlanar{}", name), name.span());

let fields_struct = if let Data::Struct(ref data_struct) = input.data {
match data_struct.fields {
Fields::Named(ref fields) => fields,
_ => return Err(Error::new_spanned(input, "Unsupported struct type")),
}
} else {
return Err(Error::new_spanned(input, "Planar macro only supports structs"));
};

let field_names = fields_struct.named.iter().map(|f| f.ident.as_ref().unwrap());
let field_types = fields_struct.named.iter().map(|_| {
quote! { bevy::render::render_resource::Buffer }
});

let bind_group = generate_bind_group_method(name, fields_struct);
let bind_group_layout = generate_bind_group_layout_method(name, fields_struct);
let prepare = generate_prepare_method(fields_struct);
let ordered_field_names = generate_ordered_field_names_method(fields_struct);

let expanded = quote! {
#[derive(Debug, Clone)]
pub struct #gpu_planar_name {
#(pub #field_names: #field_types,)*
}

impl GpuStoragePlanar for #gpu_planar_name {
type PackedType = #name;
type PlanarType = #planar_name;

#bind_group
#bind_group_layout
#prepare
#ordered_field_names
}
};

Ok(expanded)
}


pub fn generate_bind_group_method(struct_name: &Ident, fields_named: &FieldsNamed) -> quote::__private::TokenStream {
let struct_name_snake = struct_name.to_string().to_case(Case::Snake);
let bind_group_name = format!("{}_bind_group", struct_name_snake);

let bind_group_entries = fields_named.named
.iter()
.enumerate()
.map(|(idx, field)| {
let name = field.ident.as_ref().unwrap();
quote! {
bevy::render::render_resource::BindGroupEntry {
binding: #idx as u32,
resource: bevy::render::render_resource::BindingResource::Buffer(
bevy::render::render_resource::BufferBinding {
buffer: &self.#name,
offset: 0,
size: bevy::render::render_resource::BufferSize::new(self.#name.size()),
}
),
},
}
});

quote! {
fn bind_group(
&self,
render_device: &bevy::render::renderer::RenderDevice,
layout: &bevy::render::render_resource::BindGroupLayout,
) -> bevy::render::render_resource::BindGroup {
render_device.create_bind_group(
#bind_group_name,
&layout,
&[
#(#bind_group_entries)*
]
)
}
}
}


pub fn generate_bind_group_layout_method(struct_name: &Ident, fields_named: &FieldsNamed) -> quote::__private::TokenStream {
let struct_name_snake = struct_name.to_string().to_case(Case::Snake);
let bind_group_layout_name = format!("{}_bind_group_layout", struct_name_snake);

let bind_group_layout_entries = fields_named.named
.iter()
.enumerate()
.map(|(idx, _)| {
quote! {
bevy::render::render_resource::BindGroupLayoutEntry {
binding: #idx as u32,
visibility: bevy::render::render_resource::ShaderStages::all(),
ty: bevy::render::render_resource::BindingType::Buffer {
ty: bevy::render::render_resource::BufferBindingType::Storage { read_only },
has_dynamic_offset: false,
min_binding_size: bevy::render::render_resource::BufferSize::new(Self::PackedType::min_binding_sizes()[#idx] as u64),
},
count: None,
},
}
});

quote! {
fn bind_group_layout(
&self,
render_device: &bevy::render::renderer::RenderDevice,
read_only: bool,
) -> bevy::render::render_resource::BindGroupLayout {
render_device.create_bind_group_layout(
&bevy::render::render_resource::BindGroupLayoutDescriptor {
label: Some(#bind_group_layout_name),
entries: &[
#(#bind_group_layout_entries)*
],
}
)
}
}
}


pub fn generate_prepare_method(fields_named: &FieldsNamed) -> quote::__private::TokenStream {
let buffers = fields_named.named
.iter()
.map(|field| {
let name = field.ident.as_ref().unwrap();
let buffer_name_string = format!("{}_buffer", name);

quote! {
let #name = render_device.create_buffer_with_data(
&bevy::render::render_resource::BufferInitDescriptor {
label: Some(#buffer_name_string),
contents: bytemuck::cast_slice(planar.#name.as_slice()),
usage: bevy::render::render_resource::BufferUsages::COPY_DST
| bevy::render::render_resource::BufferUsages::STORAGE,
}
);
}
});

let buffer_names = fields_named.named
.iter()
.map(|field| {
let name = field.ident.as_ref().unwrap();
quote! { #name }
});

quote! {
fn prepare(
render_device: &bevy::render::renderer::RenderDevice,
planar: &Self::PlanarType,
) -> Self {
#(#buffers)*

Self {
#(#buffer_names),*
}
}
}
}


pub fn generate_ordered_field_names_method(fields_named: &FieldsNamed) -> quote::__private::TokenStream {
let string_field_names = fields_named.named
.iter()
.map(|field| {
let name = field.ident.as_ref().unwrap();
let name_str = name.to_string();
quote! { #name_str }
});

quote! {
fn ordered_field_names(&self) -> &'static [&'static str] {
&[
#(#string_field_names),*
]
}
}
}
Empty file.
34 changes: 33 additions & 1 deletion crates/bevy_interleave_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use syn::{
parse_macro_input,
};


mod planar;
use planar::generate_planar_struct;


#[proc_macro_derive(Planar)]
pub fn planar_macro_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand All @@ -21,3 +21,35 @@ pub fn planar_macro_derive(input: TokenStream) -> TokenStream {

TokenStream::from(output)
}


mod packed;
use packed::generate_min_binding_sizes;

#[proc_macro_derive(MinBindingSize)]
pub fn min_binding_size_macro_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

let output = match generate_min_binding_sizes(&input) {
Ok(quote) => quote,
Err(e) => return e.to_compile_error().into(),
};

TokenStream::from(output)
}


mod bindings;
use bindings::storage::storage_bindings;

#[proc_macro_derive(StorageBindings)]
pub fn storage_bindings_macro_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

let output = match storage_bindings(&input) {
Ok(quote) => quote,
Err(e) => return e.to_compile_error().into(),
};

TokenStream::from(output)
}
Loading