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()) |         app.add_system(build_entity_render_resource_assignments_system()) | ||||||
|             .build_system_on_stage(stage::POST_UPDATE, camera::camera_update_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, 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_stage_after(stage::POST_UPDATE, RENDER_STAGE) | ||||||
|             .add_resource(RenderGraph::default()) |             .add_resource(RenderGraph::default()) | ||||||
|             .add_resource(AssetStorage::<Mesh>::new()) |             .add_resource(AssetStorage::<Mesh>::new()) | ||||||
|  | |||||||
| @ -53,6 +53,15 @@ struct QueuedBufferWrite { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: make these queries only update changed T components
 | // 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< | type UniformQuery<T> = Query< | ||||||
|     (Read<T>, Write<Renderable>), |     (Read<T>, Write<Renderable>), | ||||||
|     EntityFilterTuple< |     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< | type UniformHandleQuery<T> = Query< | ||||||
|     (Read<Handle<T>>, Write<Renderable>), |     (Read<Handle<T>>, Write<Renderable>), | ||||||
|     EntityFilterTuple< |     EntityFilterTuple< | ||||||
| @ -82,9 +100,9 @@ where | |||||||
|     // PERF: somehow remove this HashSet
 |     // PERF: somehow remove this HashSet
 | ||||||
|     uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>, |     uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>, | ||||||
|     instance_buffer_status: Option<BufferArrayStatus>, |     instance_buffer_status: Option<BufferArrayStatus>, | ||||||
|     query: Option<UniformQuery<T>>, |     query: Option<UniformQueryRead<T>>, | ||||||
|     query_finish: Option<UniformQuery<T>>, |     query_finish: Option<UniformQuery<T>>, | ||||||
|     handle_query: Option<UniformHandleQuery<T>>, |     handle_query: Option<UniformHandleQueryRead<T>>, | ||||||
|     handle_query_finish: Option<UniformHandleQuery<T>>, |     handle_query_finish: Option<UniformHandleQuery<T>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -102,14 +120,26 @@ where | |||||||
|             use_dynamic_uniforms, |             use_dynamic_uniforms, | ||||||
|             instance_buffer_status: None, |             instance_buffer_status: None, | ||||||
|             is_instanceable, |             is_instanceable, | ||||||
|             query: Some(<(Read<T>, Write<Renderable>)>::query()), |             query: Some(<(Read<T>, Read<Renderable>)>::query()), | ||||||
|             query_finish: Some(<(Read<T>, Write<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()), |             handle_query_finish: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()), | ||||||
|             _marker: PhantomData, |             _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) { |     fn reset_buffer_array_status_counts(&mut self) { | ||||||
|         for buffer_status in self.uniform_buffer_status.iter_mut() { |         for buffer_status in self.uniform_buffer_status.iter_mut() { | ||||||
|             if let Some((_name, buffer_status)) = buffer_status { |             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(); |         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 { |             if !renderable.is_visible { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @ -141,19 +171,17 @@ where | |||||||
|             } else { |             } else { | ||||||
|                 self.increment_uniform_counts(&uniforms); |                 self.increment_uniform_counts(&uniforms); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         self.query = Some(query); |         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 handle_query = self.handle_query.take().unwrap(); | ||||||
|         let assets = resources.get::<AssetStorage<T>>(); |         let assets = resources.get::<AssetStorage<T>>(); | ||||||
|         let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap(); |         let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap(); | ||||||
|         if let Some(assets) = assets { |         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 { |                 if !renderable.is_visible { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
| @ -175,7 +203,6 @@ where | |||||||
|                     let uniforms = assets |                     let uniforms = assets | ||||||
|                         .get(&handle) |                         .get(&handle) | ||||||
|                         .expect("Handle points to a non-existent resource"); |                         .expect("Handle points to a non-existent resource"); | ||||||
|                     Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments); |  | ||||||
| 
 | 
 | ||||||
|                     self.increment_uniform_counts(&uniforms); |                     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) |         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( |     fn setup_uniform_buffer_resources( | ||||||
|         &mut self, |         &mut self, | ||||||
|         uniforms: &T, |         uniforms: &T, | ||||||
| @ -566,8 +582,6 @@ where | |||||||
|                         resources, |                         resources, | ||||||
|                         &mut batch.render_resource_assignments, |                         &mut batch.render_resource_assignments, | ||||||
|                     ); |                     ); | ||||||
| 
 |  | ||||||
|                     Self::update_shader_defs(&uniforms, &mut batch.render_resource_assignments); |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -723,9 +737,7 @@ where | |||||||
|         world: &mut World, |         world: &mut World, | ||||||
|         resources: &Resources, |         resources: &Resources, | ||||||
|     ) { |     ) { | ||||||
|         self.reset_buffer_array_status_counts(); |         self.update_readonly(_render_context, world, resources); | ||||||
|         self.update_uniforms_info(world); |  | ||||||
|         self.update_uniform_handles_info(world, resources); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn finish_update( |     fn finish_update( | ||||||
|  | |||||||
| @ -2,10 +2,12 @@ use crate::{ | |||||||
|     color::ColorSource, |     color::ColorSource, | ||||||
|     pipeline::{BindType, VertexBufferDescriptor}, |     pipeline::{BindType, VertexBufferDescriptor}, | ||||||
|     texture::Texture, |     texture::Texture, | ||||||
|  |     Renderable, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use bevy_asset::Handle; | use bevy_asset::{AssetStorage, Handle}; | ||||||
| use bevy_core::bytes::GetBytes; | use bevy_core::bytes::GetBytes; | ||||||
|  | use legion::prelude::*; | ||||||
| 
 | 
 | ||||||
| pub trait AsUniforms { | pub trait AsUniforms { | ||||||
|     fn get_field_infos() -> &'static [FieldInfo]; |     fn get_field_infos() -> &'static [FieldInfo]; | ||||||
| @ -17,6 +19,44 @@ pub trait AsUniforms { | |||||||
|     fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor>; |     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 { | pub trait ShaderDefSuffixProvider { | ||||||
|     fn get_shader_def(&self) -> Option<&'static str>; |     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() { | 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)] | #[derive(Uniforms, Default)] | ||||||
| @ -1,5 +1,5 @@ | |||||||
| pub use crate::AddDefaultPlugins; | 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")] | #[cfg(feature = "asset")] | ||||||
| pub use crate::asset::{Asset, AssetStorage, Handle}; | pub use crate::asset::{Asset, AssetStorage, Handle}; | ||||||
| #[cfg(feature = "derive")] | #[cfg(feature = "derive")] | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson