move shader defs updates to their own systems. make UniformResourceProvider::update World read-only
This commit is contained in:
		
							parent
							
								
									394b7ce940
								
							
						
					
					
						commit
						b9f4c0a53b
					
				| @ -98,6 +98,7 @@ impl AppPlugin for RenderPlugin { | ||||
|         app.add_system(build_entity_render_resource_assignments_system()) | ||||
|             .build_system_on_stage(stage::POST_UPDATE, camera::camera_update_system) | ||||
|             .add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system()) | ||||
|             .add_system_to_stage(stage::POST_UPDATE, shader::asset_handle_shader_def_system::<StandardMaterial>()) | ||||
|             .add_stage_after(stage::POST_UPDATE, RENDER_STAGE) | ||||
|             .add_resource(RenderGraph::default()) | ||||
|             .add_resource(AssetStorage::<Mesh>::new()) | ||||
|  | ||||
| @ -53,6 +53,15 @@ struct QueuedBufferWrite { | ||||
| } | ||||
| 
 | ||||
| // TODO: make these queries only update changed T components
 | ||||
| type UniformQueryRead<T> = Query< | ||||
|     (Read<T>, Read<Renderable>), | ||||
|     EntityFilterTuple< | ||||
|         And<(ComponentFilter<T>, ComponentFilter<Renderable>)>, | ||||
|         And<(Passthrough, Passthrough)>, | ||||
|         And<(Passthrough, Passthrough)>, | ||||
|     >, | ||||
| >; | ||||
| 
 | ||||
| type UniformQuery<T> = Query< | ||||
|     (Read<T>, Write<Renderable>), | ||||
|     EntityFilterTuple< | ||||
| @ -62,6 +71,15 @@ type UniformQuery<T> = Query< | ||||
|     >, | ||||
| >; | ||||
| 
 | ||||
| type UniformHandleQueryRead<T> = Query< | ||||
|     (Read<Handle<T>>, Read<Renderable>), | ||||
|     EntityFilterTuple< | ||||
|         And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>, | ||||
|         And<(Passthrough, Passthrough)>, | ||||
|         And<(Passthrough, Passthrough)>, | ||||
|     >, | ||||
| >; | ||||
| 
 | ||||
| type UniformHandleQuery<T> = Query< | ||||
|     (Read<Handle<T>>, Write<Renderable>), | ||||
|     EntityFilterTuple< | ||||
| @ -82,9 +100,9 @@ where | ||||
|     // PERF: somehow remove this HashSet
 | ||||
|     uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>, | ||||
|     instance_buffer_status: Option<BufferArrayStatus>, | ||||
|     query: Option<UniformQuery<T>>, | ||||
|     query: Option<UniformQueryRead<T>>, | ||||
|     query_finish: Option<UniformQuery<T>>, | ||||
|     handle_query: Option<UniformHandleQuery<T>>, | ||||
|     handle_query: Option<UniformHandleQueryRead<T>>, | ||||
|     handle_query_finish: Option<UniformHandleQuery<T>>, | ||||
| } | ||||
| 
 | ||||
| @ -102,14 +120,26 @@ where | ||||
|             use_dynamic_uniforms, | ||||
|             instance_buffer_status: None, | ||||
|             is_instanceable, | ||||
|             query: Some(<(Read<T>, Write<Renderable>)>::query()), | ||||
|             query: Some(<(Read<T>, Read<Renderable>)>::query()), | ||||
|             query_finish: Some(<(Read<T>, Write<Renderable>)>::query()), | ||||
|             handle_query: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()), | ||||
|             handle_query: Some(<(Read<Handle<T>>, Read<Renderable>)>::query()), | ||||
|             handle_query_finish: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()), | ||||
|             _marker: PhantomData, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn update_readonly( | ||||
|         &mut self, | ||||
|         _render_context: &mut dyn RenderContext, | ||||
|         world: &World, | ||||
|         resources: &Resources, | ||||
|     ) { | ||||
|         self.reset_buffer_array_status_counts(); | ||||
|         self.update_uniforms_info(world); | ||||
|         self.update_uniform_handles_info(world, resources); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     fn reset_buffer_array_status_counts(&mut self) { | ||||
|         for buffer_status in self.uniform_buffer_status.iter_mut() { | ||||
|             if let Some((_name, buffer_status)) = buffer_status { | ||||
| @ -122,9 +152,9 @@ where | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn update_uniforms_info(&mut self, world: &mut World) { | ||||
|     fn update_uniforms_info(&mut self, world: &World) { | ||||
|         let query = self.query.take().unwrap(); | ||||
|         for (uniforms, mut renderable) in query.iter_mut(world) { | ||||
|         for (uniforms, renderable) in query.iter(world) { | ||||
|             if !renderable.is_visible { | ||||
|                 return; | ||||
|             } | ||||
| @ -141,19 +171,17 @@ where | ||||
|             } else { | ||||
|                 self.increment_uniform_counts(&uniforms); | ||||
|             } | ||||
| 
 | ||||
|             Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments); | ||||
|         } | ||||
| 
 | ||||
|         self.query = Some(query); | ||||
|     } | ||||
| 
 | ||||
|     fn update_uniform_handles_info(&mut self, world: &mut World, resources: &Resources) { | ||||
|     fn update_uniform_handles_info(&mut self, world: &World, resources: &Resources) { | ||||
|         let handle_query = self.handle_query.take().unwrap(); | ||||
|         let assets = resources.get::<AssetStorage<T>>(); | ||||
|         let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap(); | ||||
|         if let Some(assets) = assets { | ||||
|             for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) { | ||||
|             for (entity, (handle, renderable)) in handle_query.iter_entities(world) { | ||||
|                 if !renderable.is_visible { | ||||
|                     return; | ||||
|                 } | ||||
| @ -175,7 +203,6 @@ where | ||||
|                     let uniforms = assets | ||||
|                         .get(&handle) | ||||
|                         .expect("Handle points to a non-existent resource"); | ||||
|                     Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments); | ||||
| 
 | ||||
|                     self.increment_uniform_counts(&uniforms); | ||||
|                 } | ||||
| @ -253,17 +280,6 @@ where | ||||
|         BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize) | ||||
|     } | ||||
| 
 | ||||
|     fn update_shader_defs( | ||||
|         uniforms: &T, | ||||
|         render_resource_assignments: &mut RenderResourceAssignments, | ||||
|     ) { | ||||
|         if let Some(shader_defs) = uniforms.get_shader_defs() { | ||||
|             for shader_def in shader_defs { | ||||
|                 render_resource_assignments.shader_defs.insert(shader_def); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn setup_uniform_buffer_resources( | ||||
|         &mut self, | ||||
|         uniforms: &T, | ||||
| @ -566,8 +582,6 @@ where | ||||
|                         resources, | ||||
|                         &mut batch.render_resource_assignments, | ||||
|                     ); | ||||
| 
 | ||||
|                     Self::update_shader_defs(&uniforms, &mut batch.render_resource_assignments); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -723,9 +737,7 @@ where | ||||
|         world: &mut World, | ||||
|         resources: &Resources, | ||||
|     ) { | ||||
|         self.reset_buffer_array_status_counts(); | ||||
|         self.update_uniforms_info(world); | ||||
|         self.update_uniform_handles_info(world, resources); | ||||
|         self.update_readonly(_render_context, world, resources); | ||||
|     } | ||||
| 
 | ||||
|     fn finish_update( | ||||
|  | ||||
| @ -2,10 +2,12 @@ use crate::{ | ||||
|     color::ColorSource, | ||||
|     pipeline::{BindType, VertexBufferDescriptor}, | ||||
|     texture::Texture, | ||||
|     Renderable, | ||||
| }; | ||||
| 
 | ||||
| use bevy_asset::Handle; | ||||
| use bevy_asset::{AssetStorage, Handle}; | ||||
| use bevy_core::bytes::GetBytes; | ||||
| use legion::prelude::*; | ||||
| 
 | ||||
| pub trait AsUniforms { | ||||
|     fn get_field_infos() -> &'static [FieldInfo]; | ||||
| @ -17,6 +19,44 @@ pub trait AsUniforms { | ||||
|     fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor>; | ||||
| } | ||||
| 
 | ||||
| pub fn shader_def_system<T>() -> Box<dyn Schedulable> | ||||
| where | ||||
|     T: AsUniforms + Send + Sync + 'static, | ||||
| { | ||||
|     SystemBuilder::new(format!( | ||||
|         "shader_def::{}", | ||||
|         std::any::type_name::<T>() | ||||
|     )) | ||||
|     .with_query(<(Read<T>, Write<Renderable>)>::query()) | ||||
|     .build(|_, world, _, query| { | ||||
|         for (uniforms, mut renderable) in query.iter_mut(world) { | ||||
|             if let Some(shader_defs) = uniforms.get_shader_defs() { | ||||
|                 renderable.render_resource_assignments.shader_defs.extend(shader_defs) | ||||
|             } | ||||
|         } | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn asset_handle_shader_def_system<T>() -> Box<dyn Schedulable> | ||||
| where | ||||
|     T: AsUniforms + Send + Sync + 'static, | ||||
| { | ||||
|     SystemBuilder::new(format!( | ||||
|         "asset_handle_shader_def::{}", | ||||
|         std::any::type_name::<T>() | ||||
|     )) | ||||
|     .read_resource::<AssetStorage<T>>() | ||||
|     .with_query(<(Read<Handle<T>>, Write<Renderable>)>::query()) | ||||
|     .build(|_, world, asset_storage, query| { | ||||
|         for (uniform_handle, mut renderable) in query.iter_mut(world) { | ||||
|             let uniforms = asset_storage.get(&uniform_handle).unwrap(); | ||||
|             if let Some(shader_defs) = uniforms.get_shader_defs() { | ||||
|                 renderable.render_resource_assignments.shader_defs.extend(shader_defs) | ||||
|             } | ||||
|         } | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub trait ShaderDefSuffixProvider { | ||||
|     fn get_shader_def(&self) -> Option<&'static str>; | ||||
| } | ||||
|  | ||||
							
								
								
									
										110
									
								
								examples/shader_custom_material.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								examples/shader_custom_material.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | ||||
| use bevy::{prelude::*}; | ||||
| 
 | ||||
| fn main() { | ||||
|     App::build() | ||||
|         .add_default_plugins() | ||||
|         .setup(setup) | ||||
|         .run(); | ||||
| } | ||||
| 
 | ||||
| #[derive(Uniforms, Default)] | ||||
| struct MyMaterial { | ||||
|     pub color: Color, | ||||
| } | ||||
| 
 | ||||
| fn add_shader_to_render_graph(resources: &mut Resources) { | ||||
|     let mut render_graph = resources.get_mut::<RenderGraph>().unwrap(); | ||||
|     let mut pipelines = resources | ||||
|         .get_mut::<AssetStorage<PipelineDescriptor>>() | ||||
|         .unwrap(); | ||||
|     let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap(); | ||||
| 
 | ||||
|     render_graph | ||||
|         .build(&mut pipelines, &mut shaders) | ||||
|         .add_resource_provider(UniformResourceProvider::<MyMaterial>::new(true)) | ||||
|         .add_pipeline_to_pass(resource_name::pass::MAIN, "MyMaterial", |builder| { | ||||
|             builder | ||||
|                 .with_vertex_shader(Shader::from_glsl( | ||||
|                     ShaderStage::Vertex, | ||||
|                     r#" | ||||
|                     #version 450 | ||||
|                     layout(location = 0) in vec4 Vertex_Position; | ||||
|                     layout(location = 0) out vec4 v_Position; | ||||
|                     layout(set = 0, binding = 0) uniform Camera { | ||||
|                         mat4 ViewProj; | ||||
|                     }; | ||||
|                     layout(set = 1, binding = 0) uniform Object { | ||||
|                         mat4 Model; | ||||
|                     }; | ||||
|                     void main() { | ||||
|                         v_Position = Model * Vertex_Position; | ||||
|                         gl_Position = ViewProj * v_Position; | ||||
|                     } | ||||
|                 "#,
 | ||||
|                 )) | ||||
|                 .with_fragment_shader(Shader::from_glsl( | ||||
|                     ShaderStage::Fragment, | ||||
|                     r#" | ||||
|                     #version 450 | ||||
|                     layout(location = 0) in vec4 v_Position; | ||||
|                     layout(location = 0) out vec4 o_Target; | ||||
|                     layout(set = 1, binding = 1) uniform MyMaterial_color { | ||||
|                         vec4 color; | ||||
|                     }; | ||||
|                     void main() { | ||||
|                         o_Target = color; | ||||
|                     } | ||||
|                 "#,
 | ||||
|                 )) | ||||
|                 .with_default_config(); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| fn setup(world: &mut World, resources: &mut Resources) { | ||||
|     // add our shader to the render graph
 | ||||
|     add_shader_to_render_graph(resources); | ||||
| 
 | ||||
|     // create materials
 | ||||
|     let mut material_storage = AssetStorage::<MyMaterial>::new(); | ||||
|     let material = material_storage.add(MyMaterial { | ||||
|         color: Color::rgb(0.0, 0.8, 0.0), | ||||
|     }); | ||||
| 
 | ||||
|     resources.insert(material_storage); | ||||
| 
 | ||||
|     // batch materials to improve performance
 | ||||
|     let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap(); | ||||
|     asset_batchers.batch_types2::<Mesh, MyMaterial>(); | ||||
| 
 | ||||
|     // get a handle to our newly created shader pipeline
 | ||||
|     let mut pipeline_storage = resources | ||||
|         .get_mut::<AssetStorage<PipelineDescriptor>>() | ||||
|         .unwrap(); | ||||
|     let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap(); | ||||
| 
 | ||||
|     let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|     let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube)); | ||||
| 
 | ||||
|     world | ||||
|         .build() | ||||
|         // cube
 | ||||
|         .add_entity(MeshMaterialEntity::<MyMaterial> { | ||||
|             mesh: cube_handle, | ||||
|             renderable: Renderable { | ||||
|                 pipelines: vec![pipeline_handle], | ||||
|                 ..Default::default() | ||||
|             }, | ||||
|             material, | ||||
|             translation: Translation::new(0.0, 0.0, 0.0), | ||||
|             ..Default::default() | ||||
|         }) | ||||
|         // camera
 | ||||
|         .add_entity(CameraEntity { | ||||
|             local_to_world: LocalToWorld(Mat4::look_at_rh( | ||||
|                 Vec3::new(3.0, 8.0, 5.0), | ||||
|                 Vec3::new(0.0, 0.0, 0.0), | ||||
|                 Vec3::new(0.0, 0.0, 1.0), | ||||
|             )), | ||||
|             ..Default::default() | ||||
|         }); | ||||
| } | ||||
| @ -1,7 +1,14 @@ | ||||
| use bevy::prelude::*; | ||||
| use bevy::{prelude::*, render::shader}; | ||||
| 
 | ||||
| fn main() { | ||||
|     App::build().add_default_plugins().setup(setup).run(); | ||||
|     App::build() | ||||
|         .add_default_plugins() | ||||
|         .setup(setup) | ||||
|         .add_system_to_stage( | ||||
|             stage::POST_UPDATE, | ||||
|             shader::asset_handle_shader_def_system::<MyMaterial>(), | ||||
|         ) | ||||
|         .run(); | ||||
| } | ||||
| 
 | ||||
| #[derive(Uniforms, Default)] | ||||
| @ -1,5 +1,5 @@ | ||||
| pub use crate::AddDefaultPlugins; | ||||
| pub use crate::app::{App, AppBuilder, AppPlugin, EntityArchetype, EventReader, Events, GetEventReader}; | ||||
| pub use crate::app::{App, AppBuilder, AppPlugin, EntityArchetype, EventReader, Events, GetEventReader, stage}; | ||||
| #[cfg(feature = "asset")] | ||||
| pub use crate::asset::{Asset, AssetStorage, Handle}; | ||||
| #[cfg(feature = "derive")] | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson