From d0298a4f89d6f0abe18cc6ea2f721fc249b98423 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 7 Jun 2020 13:00:58 -0700 Subject: [PATCH] split AsVertexBufferDescriptor out from Uniforms --- .../src/as_vertex_buffer_descriptor.rs | 136 ++++++++++++++++++ crates/bevy_derive/src/lib.rs | 17 ++- crates/bevy_derive/src/uniforms.rs | 76 ---------- crates/bevy_render/src/lib.rs | 1 - crates/bevy_render/src/mesh.rs | 6 +- crates/bevy_render/src/pipeline/mod.rs | 2 +- .../src/pipeline/vertex_buffer_descriptor.rs | 6 + .../src/render_graph/nodes/uniform_node.rs | 14 -- crates/bevy_render/src/shader/mod.rs | 2 +- crates/bevy_render/src/shader/uniform.rs | 12 +- .../src/shader/uniforms/local_to_world.rs | 41 +----- crates/bevy_render/src/vertex.rs | 9 +- src/prelude.rs | 1 - 13 files changed, 166 insertions(+), 157 deletions(-) create mode 100644 crates/bevy_derive/src/as_vertex_buffer_descriptor.rs diff --git a/crates/bevy_derive/src/as_vertex_buffer_descriptor.rs b/crates/bevy_derive/src/as_vertex_buffer_descriptor.rs new file mode 100644 index 0000000000..e5da0a16cc --- /dev/null +++ b/crates/bevy_derive/src/as_vertex_buffer_descriptor.rs @@ -0,0 +1,136 @@ +use crate::modules::{get_modules, get_path}; +use darling::FromMeta; +use inflector::Inflector; +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Path}; + +#[derive(FromMeta, Debug, Default)] +struct VertexAttributeArgs { + #[darling(default)] + pub ignore: Option, + #[darling(default)] + pub instance: Option, +} + +#[derive(Default)] +struct VertexAttributes { + pub ignore: bool, + pub instance: bool, +} + +impl From for VertexAttributes { + fn from(args: VertexAttributeArgs) -> Self { + VertexAttributes { + ignore: args.ignore.unwrap_or(false), + instance: args.instance.unwrap_or(false), + } + } +} + +static UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform"; + +pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let modules = get_modules(&ast); + + let bevy_render_path: Path = get_path(&modules.bevy_render); + + let fields = match &ast.data { + Data::Struct(DataStruct { + fields: Fields::Named(fields), + .. + }) => &fields.named, + _ => panic!("expected a struct with named fields"), + }; + + let field_attributes = fields + .iter() + .map(|f| { + ( + f, + f.attrs + .iter() + .find(|a| { + a.path.get_ident().as_ref().unwrap().to_string() == UNIFORM_ATTRIBUTE_NAME + }) + .map(|a| { + VertexAttributes::from( + VertexAttributeArgs::from_meta(&a.parse_meta().unwrap()) + .unwrap_or_else(|_err| VertexAttributeArgs::default()), + ) + }) + .unwrap_or_else(|| VertexAttributes::default()), + ) + }) + .collect::>(); + + let struct_name = &ast.ident; + + let mut vertex_buffer_field_names_pascal = Vec::new(); + let mut vertex_buffer_field_types = Vec::new(); + for (f, attrs) in field_attributes.iter() { + if attrs.ignore { + continue; + } + + vertex_buffer_field_types.push(&f.ty); + let pascal_field = f.ident.as_ref().unwrap().to_string().to_pascal_case(); + vertex_buffer_field_names_pascal.push(if attrs.instance { + format!("I_{}_{}", struct_name, pascal_field) + } else { + format!("{}_{}", struct_name, pascal_field) + }); + } + + let struct_name_string = struct_name.to_string(); + let struct_name_uppercase = struct_name_string.to_uppercase(); + let vertex_buffer_descriptor_ident = + format_ident!("{}_VERTEX_BUFFER_DESCRIPTOR", struct_name_uppercase); + + TokenStream::from(quote! { + static #vertex_buffer_descriptor_ident: #bevy_render_path::once_cell::sync::Lazy<#bevy_render_path::pipeline::VertexBufferDescriptor> = + #bevy_render_path::once_cell::sync::Lazy::new(|| { + use #bevy_render_path::pipeline::{VertexFormat, AsVertexFormats, VertexAttributeDescriptor}; + + let mut vertex_formats: Vec<(&str,&[VertexFormat])> = vec![ + #((#vertex_buffer_field_names_pascal, <#vertex_buffer_field_types>::as_vertex_formats()),)* + ]; + + let mut shader_location = 0; + let mut offset = 0; + let vertex_attribute_descriptors = vertex_formats.drain(..).map(|(name, formats)| { + formats.iter().enumerate().map(|(i, format)| { + let size = format.get_size(); + let formatted_name = if formats.len() > 1 { + format!("{}_{}", name, i) + } else { + format!("{}", name) + }; + let descriptor = VertexAttributeDescriptor { + name: formatted_name.into(), + offset, + format: *format, + shader_location, + }; + offset += size; + shader_location += 1; + descriptor + }).collect::>() + }).flatten().collect::>(); + + #bevy_render_path::pipeline::VertexBufferDescriptor { + attributes: vertex_attribute_descriptors, + name: #struct_name_string.into(), + step_mode: #bevy_render_path::pipeline::InputStepMode::Instance, + stride: offset, + } + }); + + impl #bevy_render_path::pipeline::AsVertexBufferDescriptor for #struct_name { + fn as_vertex_buffer_descriptor() -> &'static #bevy_render_path::pipeline::VertexBufferDescriptor { + &#vertex_buffer_descriptor_ident + } + } + }) +} \ No newline at end of file diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index fb2dcca995..0885da75bc 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -6,6 +6,7 @@ mod entity_archetype; mod modules; mod resource; mod uniforms; +mod as_vertex_buffer_descriptor; use proc_macro::TokenStream; @@ -24,16 +25,22 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream { uniforms::derive_uniform(input) } -#[proc_macro_derive(EntityArchetype, attributes(tag, module))] -pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { - entity_archetype::derive_entity_archetype(input) -} - #[proc_macro_derive(Uniforms, attributes(uniform, module))] pub fn derive_uniforms(input: TokenStream) -> TokenStream { uniforms::derive_uniforms(input) } +#[proc_macro_derive(AsVertexBufferDescriptor, attributes(vertex, module))] +pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream { + as_vertex_buffer_descriptor::derive_as_vertex_buffer_descriptor(input) +} + +#[proc_macro_derive(EntityArchetype, attributes(tag, module))] +pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { + entity_archetype::derive_entity_archetype(input) +} + + #[proc_macro_derive(DynamicAppPlugin)] pub fn derive_app_plugin(input: TokenStream) -> TokenStream { app_plugin::derive_dynamic_app_plugin(input) diff --git a/crates/bevy_derive/src/uniforms.rs b/crates/bevy_derive/src/uniforms.rs index 6e08ff896d..37ca65935c 100644 --- a/crates/bevy_derive/src/uniforms.rs +++ b/crates/bevy_derive/src/uniforms.rs @@ -12,10 +12,6 @@ struct UniformAttributeArgs { #[darling(default)] pub shader_def: Option, #[darling(default)] - pub instance: Option, - #[darling(default)] - pub vertex: Option, - #[darling(default)] pub buffer: Option, } @@ -23,8 +19,6 @@ struct UniformAttributeArgs { struct UniformAttributes { pub ignore: bool, pub shader_def: bool, - pub instance: bool, - pub vertex: bool, pub buffer: bool, } @@ -33,8 +27,6 @@ impl From for UniformAttributes { UniformAttributes { ignore: args.ignore.unwrap_or(false), shader_def: args.shader_def.unwrap_or(false), - instance: args.instance.unwrap_or(false), - vertex: args.vertex.unwrap_or(false), buffer: args.buffer.unwrap_or(false), } } @@ -89,9 +81,6 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { let mut field_infos = Vec::new(); let mut get_field_bind_types = Vec::new(); - let mut vertex_buffer_field_names_pascal = Vec::new(); - let mut vertex_buffer_field_types = Vec::new(); - let mut shader_def_field_names = Vec::new(); let mut shader_def_field_names_screaming_snake = Vec::new(); @@ -109,13 +98,11 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { texture_and_sampler_name_strings.push(sampler.clone()); texture_and_sampler_name_idents.push(f.ident.clone()); texture_and_sampler_name_idents.push(f.ident.clone()); - let is_instanceable = attrs.instance; field_infos.push(quote!(#bevy_render_path::shader::FieldInfo { name: #field_name, uniform_name: #uniform, texture_name: #texture, sampler_name: #sampler, - is_instanceable: #is_instanceable, })); if attrs.buffer { @@ -137,67 +124,17 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { shader_def_field_names.push(&f.ident); shader_def_field_names_screaming_snake.push(field_name.to_screaming_snake_case()) } - - if attrs.instance || attrs.vertex { - vertex_buffer_field_types.push(&f.ty); - let pascal_field = f.ident.as_ref().unwrap().to_string().to_pascal_case(); - vertex_buffer_field_names_pascal.push(if attrs.instance { - format!("I_{}_{}", struct_name, pascal_field) - } else { - format!("{}_{}", struct_name, pascal_field) - }); - } } let struct_name_string = struct_name.to_string(); let struct_name_uppercase = struct_name_string.to_uppercase(); let field_infos_ident = format_ident!("{}_FIELD_INFO", struct_name_uppercase); - let vertex_buffer_descriptor_ident = - format_ident!("{}_VERTEX_BUFFER_DESCRIPTOR", struct_name_uppercase); TokenStream::from(quote! { static #field_infos_ident: &[#bevy_render_path::shader::FieldInfo] = &[ #(#field_infos,)* ]; - static #vertex_buffer_descriptor_ident: #bevy_render_path::once_cell::sync::Lazy<#bevy_render_path::pipeline::VertexBufferDescriptor> = - #bevy_render_path::once_cell::sync::Lazy::new(|| { - use #bevy_render_path::pipeline::{VertexFormat, AsVertexFormats, VertexAttributeDescriptor}; - - let mut vertex_formats: Vec<(&str,&[VertexFormat])> = vec![ - #((#vertex_buffer_field_names_pascal, <#vertex_buffer_field_types>::as_vertex_formats()),)* - ]; - - let mut shader_location = 0; - let mut offset = 0; - let vertex_attribute_descriptors = vertex_formats.drain(..).map(|(name, formats)| { - formats.iter().enumerate().map(|(i, format)| { - let size = format.get_size(); - let formatted_name = if formats.len() > 1 { - format!("{}_{}", name, i) - } else { - format!("{}", name) - }; - let descriptor = VertexAttributeDescriptor { - name: formatted_name.into(), - offset, - format: *format, - shader_location, - }; - offset += size; - shader_location += 1; - descriptor - }).collect::>() - }).flatten().collect::>(); - - #bevy_render_path::pipeline::VertexBufferDescriptor { - attributes: vertex_attribute_descriptors, - name: #struct_name_string.into(), - step_mode: #bevy_render_path::pipeline::InputStepMode::Instance, - stride: offset, - } - }); - impl #bevy_render_path::shader::Uniforms for #struct_name { fn get_field_infos() -> &'static [#bevy_render_path::shader::FieldInfo] { #field_infos_ident @@ -248,14 +185,6 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { .map(|(f, shader_def)| format!("{}_{}{}", #struct_name_uppercase, f, shader_def.unwrap())) .collect::>()) } - - fn get_vertex_buffer_descriptor() -> Option<&'static #bevy_render_path::pipeline::VertexBufferDescriptor> { - if #vertex_buffer_descriptor_ident.attributes.len() == 0 { - None - } else { - Some(&#vertex_buffer_descriptor_ident) - } - } } }) } @@ -283,7 +212,6 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream { uniform_name: #struct_name_string, texture_name: #struct_name_string, sampler_name: #struct_name_string, - is_instanceable: false, } ]; &FIELD_INFOS @@ -322,10 +250,6 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream { fn get_shader_defs(&self) -> Option> { None } - - fn get_vertex_buffer_descriptor() -> Option<&'static #bevy_render_path::pipeline::VertexBufferDescriptor> { - None - } } }) } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 6ee2a63a20..05b393b5bd 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -25,7 +25,6 @@ mod renderable; pub mod texture; pub use once_cell; -pub use bevy_derive::{Uniform, Uniforms}; use self::{ mesh::Mesh, diff --git a/crates/bevy_render/src/mesh.rs b/crates/bevy_render/src/mesh.rs index e5c6aaeddd..a9d353858d 100644 --- a/crates/bevy_render/src/mesh.rs +++ b/crates/bevy_render/src/mesh.rs @@ -2,10 +2,10 @@ use crate::{ pipeline::{ state_descriptors::{IndexFormat, PrimitiveTopology}, VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat, + AsVertexBufferDescriptor, }, render_resource::{BufferInfo, BufferUsage}, renderer::{RenderResourceContext, RenderResources}, - shader::Uniforms, Renderable, Vertex, }; use bevy_app::{EventReader, Events}; @@ -339,7 +339,7 @@ pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box().unwrap(); let mut mesh_event_reader = EventReader::>::default(); // TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format - let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap(); + let vertex_buffer_descriptor = Vertex::as_vertex_buffer_descriptor(); vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); (move |world: &mut SubWorld, render_resources: Res, @@ -479,7 +479,7 @@ mod tests { }, ]; - let descriptor = Vertex::get_vertex_buffer_descriptor().unwrap(); + let descriptor = Vertex::as_vertex_buffer_descriptor(); assert_eq!( mesh.get_vertex_buffer_bytes(descriptor).unwrap(), expected_vertices.as_bytes(), diff --git a/crates/bevy_render/src/pipeline/mod.rs b/crates/bevy_render/src/pipeline/mod.rs index fba0051530..e307aa6108 100644 --- a/crates/bevy_render/src/pipeline/mod.rs +++ b/crates/bevy_render/src/pipeline/mod.rs @@ -13,4 +13,4 @@ pub use pipeline::*; pub use pipeline_compiler::*; pub use pipeline_layout::*; pub use vertex_buffer_descriptor::*; -pub use vertex_format::*; +pub use vertex_format::*; \ No newline at end of file diff --git a/crates/bevy_render/src/pipeline/vertex_buffer_descriptor.rs b/crates/bevy_render/src/pipeline/vertex_buffer_descriptor.rs index fca4edd323..f55ae98ca0 100644 --- a/crates/bevy_render/src/pipeline/vertex_buffer_descriptor.rs +++ b/crates/bevy_render/src/pipeline/vertex_buffer_descriptor.rs @@ -1,6 +1,8 @@ use super::VertexFormat; use std::{borrow::Cow, collections::HashMap}; +pub use bevy_derive::AsVertexBufferDescriptor; + #[derive(Clone, Debug, Eq, PartialEq)] pub struct VertexBufferDescriptor { pub name: Cow<'static, str>, @@ -60,3 +62,7 @@ impl VertexBufferDescriptors { self.descriptors.get(name) } } + +pub trait AsVertexBufferDescriptor { + fn as_vertex_buffer_descriptor() -> &'static VertexBufferDescriptor; +} \ No newline at end of file diff --git a/crates/bevy_render/src/render_graph/nodes/uniform_node.rs b/crates/bevy_render/src/render_graph/nodes/uniform_node.rs index e5923723e7..cec2083bb0 100644 --- a/crates/bevy_render/src/render_graph/nodes/uniform_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/uniform_node.rs @@ -1,5 +1,4 @@ use crate::{ - pipeline::VertexBufferDescriptors, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_resource::{ BufferInfo, BufferUsage, EntitiesWaitingForAssets, RenderResourceId, @@ -671,19 +670,6 @@ where } } -#[allow(dead_code)] -fn initialize_vertex_buffer_descriptor(vertex_buffer_descriptors: &mut VertexBufferDescriptors) -where - T: Uniforms, -{ - let vertex_buffer_descriptor = T::get_vertex_buffer_descriptor(); - if let Some(vertex_buffer_descriptor) = vertex_buffer_descriptor { - if let None = vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) { - vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone()); - } - } -} - fn setup_uniform_texture_resources( entity: Entity, uniforms: &T, diff --git a/crates/bevy_render/src/shader/mod.rs b/crates/bevy_render/src/shader/mod.rs index db7728b1bf..2923813364 100644 --- a/crates/bevy_render/src/shader/mod.rs +++ b/crates/bevy_render/src/shader/mod.rs @@ -5,4 +5,4 @@ pub mod uniforms; pub use shader::*; pub use shader_reflect::*; -pub use uniform::*; +pub use uniform::*; \ No newline at end of file diff --git a/crates/bevy_render/src/shader/uniform.rs b/crates/bevy_render/src/shader/uniform.rs index 04705edfb1..53e74e1637 100644 --- a/crates/bevy_render/src/shader/uniform.rs +++ b/crates/bevy_render/src/shader/uniform.rs @@ -1,14 +1,11 @@ -use crate::{ - color::ColorSource, - pipeline::{BindType, VertexBufferDescriptor}, - texture::Texture, - Renderable, -}; +use crate::{color::ColorSource, pipeline::BindType, texture::Texture, Renderable}; use bevy_asset::{Assets, Handle}; use bevy_core::bytes::Bytes; use legion::prelude::*; +pub use bevy_derive::{Uniform, Uniforms}; + pub trait Uniforms: Send + Sync + 'static { fn get_field_infos() -> &'static [FieldInfo]; fn write_uniform_bytes(&self, name: &str, buffer: &mut [u8]); @@ -16,7 +13,6 @@ pub trait Uniforms: Send + Sync + 'static { fn get_uniform_texture(&self, name: &str) -> Option>; fn get_shader_defs(&self) -> Option>; fn get_field_bind_type(&self, name: &str) -> Option; - fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor>; } pub fn shader_def_system(uniforms: Com, mut renderable: ComMut) @@ -70,7 +66,6 @@ impl ShaderDefSuffixProvider for bool { #[derive(Clone, Debug, Eq, PartialEq)] pub enum FieldBindType { - // TODO: maybe change this to Buffer Uniform { size: usize }, Buffer { size: usize }, Texture, @@ -81,7 +76,6 @@ pub struct FieldInfo { pub uniform_name: &'static str, pub texture_name: &'static str, pub sampler_name: &'static str, - pub is_instanceable: bool, } pub trait GetFieldBindType { diff --git a/crates/bevy_render/src/shader/uniforms/local_to_world.rs b/crates/bevy_render/src/shader/uniforms/local_to_world.rs index ec0ec41fdd..b5f19f50ca 100644 --- a/crates/bevy_render/src/shader/uniforms/local_to_world.rs +++ b/crates/bevy_render/src/shader/uniforms/local_to_world.rs @@ -1,53 +1,17 @@ use crate::{ - pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat}, - shader::{Uniforms, FieldBindType, FieldInfo, GetFieldBindType}, + shader::{FieldBindType, FieldInfo, GetFieldBindType, Uniforms}, texture::Texture, }; use bevy_asset::Handle; use bevy_core::bytes::Bytes; -use once_cell::sync::Lazy; static LOCAL_TO_WORLD_FIELD_INFOS: &[FieldInfo] = &[FieldInfo { name: "object", uniform_name: "Object", texture_name: "", sampler_name: "", - is_instanceable: true, }]; -static VERTEX_BUFFER_DESCRIPTOR: Lazy = - Lazy::new(|| VertexBufferDescriptor { - attributes: vec![ - VertexAttributeDescriptor { - name: "I_Object_Model_0".into(), - format: VertexFormat::Float4, - offset: 0, - shader_location: 0, - }, - VertexAttributeDescriptor { - name: "I_Object_Model_1".into(), - format: VertexFormat::Float4, - offset: 16, - shader_location: 1, - }, - VertexAttributeDescriptor { - name: "I_Object_Model_2".into(), - format: VertexFormat::Float4, - offset: 32, - shader_location: 2, - }, - VertexAttributeDescriptor { - name: "I_Object_Model_3".into(), - format: VertexFormat::Float4, - offset: 48, - shader_location: 3, - }, - ], - name: "Object".into(), - step_mode: InputStepMode::Instance, - stride: 64, - }); - impl Uniforms for bevy_transform::prelude::LocalToWorld { fn get_field_infos() -> &'static [FieldInfo] { LOCAL_TO_WORLD_FIELD_INFOS @@ -66,9 +30,6 @@ impl Uniforms for bevy_transform::prelude::LocalToWorld { None } - fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor> { - Some(&VERTEX_BUFFER_DESCRIPTOR) - } fn write_uniform_bytes(&self, name: &str, buffer: &mut [u8]) { match name { "Object" => self.value.write_bytes(buffer), diff --git a/crates/bevy_render/src/vertex.rs b/crates/bevy_render/src/vertex.rs index 9a76546d8f..feb78daa64 100644 --- a/crates/bevy_render/src/vertex.rs +++ b/crates/bevy_render/src/vertex.rs @@ -1,17 +1,14 @@ use bevy_core::bytes::Byteable; -use bevy_derive::Uniforms; +use crate::pipeline::AsVertexBufferDescriptor; #[repr(C)] -#[derive(Clone, Copy, Uniforms)] +#[derive(Clone, Copy, AsVertexBufferDescriptor)] #[module(bevy_render = "crate")] pub struct Vertex { - #[uniform(vertex)] pub position: [f32; 3], - #[uniform(vertex)] pub normal: [f32; 3], - #[uniform(vertex)] pub uv: [f32; 2], } // SAFE: Vertex is repr(C) containing primitives -unsafe impl Byteable for Vertex {} +unsafe impl Byteable for Vertex {} \ No newline at end of file diff --git a/src/prelude.rs b/src/prelude.rs index 0e9f394852..683dc12796 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -28,7 +28,6 @@ pub use crate::{ shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages}, texture::Texture, Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable, - Uniforms, Uniform, }, scene::{Scene, SceneSpawner}, sprite::{