Make PipelineDescriptor an Asset that references Handle<Shader>
This commit is contained in:
		
							parent
							
								
									478d475219
								
							
						
					
					
						commit
						4de039eb71
					
				| @ -16,7 +16,7 @@ use crate::{ | ||||
| }; | ||||
| 
 | ||||
| use bevy_transform::{prelude::LocalToWorld, transform_system_bundle}; | ||||
| use render_graph_2::CompiledShaderMap; | ||||
| use render_graph_2::{CompiledShaderMap, PipelineDescriptor}; | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| pub struct AppBuilder { | ||||
| @ -166,6 +166,7 @@ impl AppBuilder { | ||||
|         resources.insert(AssetStorage::<Mesh>::new()); | ||||
|         resources.insert(AssetStorage::<Texture>::new()); | ||||
|         resources.insert(AssetStorage::<Shader>::new()); | ||||
|         resources.insert(AssetStorage::<PipelineDescriptor>::new()); | ||||
|         resources.insert(ShaderAssignments::new()); | ||||
|         resources.insert(CompiledShaderMap::new()); | ||||
|         self | ||||
| @ -181,17 +182,29 @@ impl AppBuilder { | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_render_graph_defaults(mut self) -> Self { | ||||
|         self.render_graph_builder = self | ||||
|             .render_graph_builder | ||||
|             .add_resource_provider(Box::new(CameraResourceProvider)) | ||||
|             .add_resource_provider(Box::new(Camera2dResourceProvider)) | ||||
|             .add_resource_provider(Box::new(LightResourceProvider::new(10))) | ||||
|             .add_resource_provider(Box::new(UiResourceProvider::new())) | ||||
|             .add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new())) | ||||
|             .add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new())) | ||||
|             .add_forward_pass() | ||||
|             .add_forward_pipeline() | ||||
|             .add_ui_pipeline(); | ||||
|         { | ||||
|             let mut pipeline_storage = self | ||||
|                 .world | ||||
|                 .resources | ||||
|                 .get_mut::<AssetStorage<PipelineDescriptor>>() | ||||
|                 .unwrap(); | ||||
|             let mut shader_storage = self | ||||
|                 .world | ||||
|                 .resources | ||||
|                 .get_mut::<AssetStorage<Shader>>() | ||||
|                 .unwrap(); | ||||
|             self.render_graph_builder = self | ||||
|                 .render_graph_builder | ||||
|                 .add_resource_provider(Box::new(CameraResourceProvider)) | ||||
|                 .add_resource_provider(Box::new(Camera2dResourceProvider)) | ||||
|                 .add_resource_provider(Box::new(LightResourceProvider::new(10))) | ||||
|                 .add_resource_provider(Box::new(UiResourceProvider::new())) | ||||
|                 .add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new())) | ||||
|                 .add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new())) | ||||
|                 .add_forward_pass() | ||||
|                 .add_forward_pipeline(&mut pipeline_storage, &mut shader_storage) | ||||
|                 .add_ui_pipeline(&mut pipeline_storage, &mut shader_storage); | ||||
|         } | ||||
| 
 | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @ -3,17 +3,31 @@ mod mesh; | ||||
| mod texture; | ||||
| 
 | ||||
| pub use self::gltf::load_gltf; | ||||
| use std::hash::{Hash, Hasher}; | ||||
| pub use mesh::*; | ||||
| pub use texture::*; | ||||
| 
 | ||||
| use std::{collections::HashMap, marker::PhantomData}; | ||||
| 
 | ||||
| #[derive(Hash, Eq, PartialEq)] | ||||
| pub struct Handle<T> { | ||||
|     pub id: usize, | ||||
|     marker: PhantomData<T>, | ||||
| } | ||||
| 
 | ||||
| impl<T> Hash for Handle<T> { | ||||
|     fn hash<H: Hasher>(&self, state: &mut H) { | ||||
|         self.id.hash(state); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> PartialEq for Handle<T> { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.id == other.id | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> Eq for Handle<T> {} | ||||
| 
 | ||||
| // TODO: somehow handle this gracefully in asset managers. or alternatively remove Default
 | ||||
| impl<T> Default for Handle<T> { | ||||
|     fn default() -> Self { | ||||
| @ -75,11 +89,19 @@ impl<T> AssetStorage<T> { | ||||
|         handle | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_id(&mut self, id: usize) -> Option<&mut T> { | ||||
|     pub fn get_id(&self, id: usize) -> Option<&T> { | ||||
|         self.assets.get(&id) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_id_mut(&mut self, id: usize) -> Option<&mut T> { | ||||
|         self.assets.get_mut(&id) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&mut self, handle: &Handle<T>) -> Option<&mut T> { | ||||
|     pub fn get(&self, handle: &Handle<T>) -> Option<&T> { | ||||
|         self.assets.get(&handle.id) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_mut(&mut self, handle: &Handle<T>) -> Option<&mut T> { | ||||
|         self.assets.get_mut(&handle.id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -157,7 +157,7 @@ impl Pipeline for ForwardPipeline { | ||||
|             } | ||||
| 
 | ||||
|             if should_load_mesh { | ||||
|                 if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) { | ||||
|                 if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) { | ||||
|                     mesh_asset.setup_buffers(&render_graph.device); | ||||
|                     pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); | ||||
|                     pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); | ||||
|  | ||||
| @ -285,7 +285,7 @@ impl Pipeline for ForwardInstancedPipeline { | ||||
| 
 | ||||
|         let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|         for instance_buffer_info in self.instance_buffer_infos.as_ref().unwrap().iter() { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.mesh_id) { | ||||
|                 mesh_asset.setup_buffers(&render_graph.device); | ||||
|                 pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); | ||||
|                 pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); | ||||
|  | ||||
| @ -176,7 +176,7 @@ impl Pipeline for ForwardShadowPassNew { | ||||
| 
 | ||||
|         let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|         for (material, mesh) in mesh_query.iter(world) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) { | ||||
|                 mesh_asset.setup_buffers(&render_graph.device); | ||||
|                 pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]); | ||||
|                 pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); | ||||
|  | ||||
| @ -166,7 +166,7 @@ impl Pipeline for ShadowPipeline { | ||||
| 
 | ||||
|         let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|         for (material, mesh) in mesh_query.iter(world) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id_mut(mesh.id) { | ||||
|                 mesh_asset.setup_buffers(&render_graph.device); | ||||
| 
 | ||||
|                 pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]); | ||||
|  | ||||
| @ -242,7 +242,7 @@ impl Pipeline for UiPipeline { | ||||
| 
 | ||||
|         let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|         for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id(instance_buffer_info.mesh_id) { | ||||
|             if let Some(mesh_asset) = mesh_storage.get_id_mut(instance_buffer_info.mesh_id) { | ||||
|                 mesh_asset.setup_buffers(&render_graph.device); | ||||
|                 pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); | ||||
|                 pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); | ||||
|  | ||||
| @ -10,7 +10,7 @@ use crate::{ | ||||
| use zerocopy::AsBytes; | ||||
| 
 | ||||
| pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) { | ||||
|     let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|     let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|     let mut current_mesh_id = None; | ||||
|     let mut current_mesh_index_length = 0; | ||||
|     let mesh_query = <(Read<ShaderUniforms>, Read<Handle<Mesh>>, Read<Renderable>)>::query() | ||||
|  | ||||
| @ -7,7 +7,7 @@ use crate::{ | ||||
| use zerocopy::AsBytes; | ||||
| 
 | ||||
| pub fn ui_draw_target(world: &World, render_pass: &mut dyn RenderPass) { | ||||
|     let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|     let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap(); | ||||
|     // NOTE: this is ugly and borrowing is stupid
 | ||||
|     let result = { | ||||
|         let renderer = render_pass.get_renderer(); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use crate::render::{ | ||||
| use crate::{asset::{AssetStorage, Handle}, render::{ | ||||
|     render_graph_2::{BindGroup, DrawTarget, PipelineLayout}, | ||||
|     shader::{Shader, ShaderStages}, | ||||
| }; | ||||
| }}; | ||||
| 
 | ||||
| pub struct VertexBufferDescriptor { | ||||
|     pub stride: wgpu::BufferAddress, | ||||
| @ -55,7 +55,7 @@ pub struct PipelineDescriptor { | ||||
| } | ||||
| 
 | ||||
| impl PipelineDescriptor { | ||||
|     fn new(vertex_shader: Shader) -> Self { | ||||
|     fn new(vertex_shader: Handle<Shader>) -> Self { | ||||
|         PipelineDescriptor { | ||||
|             pipeline_layout: PipelineLayout::new(), | ||||
|             color_states: Vec::new(), | ||||
| @ -80,19 +80,22 @@ impl PipelineDescriptor { | ||||
| } | ||||
| 
 | ||||
| impl PipelineDescriptor { | ||||
|     pub fn build(vertex_shader: Shader) -> PipelineBuilder { | ||||
|         PipelineBuilder::new(vertex_shader) | ||||
|     pub fn build(shader_storage: &mut AssetStorage<Shader>, vertex_shader: Shader) -> PipelineBuilder { | ||||
|         PipelineBuilder::new(shader_storage, vertex_shader) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct PipelineBuilder { | ||||
| pub struct PipelineBuilder<'a> { | ||||
|     pipeline: PipelineDescriptor, | ||||
|     shader_storage: &'a mut AssetStorage<Shader>, | ||||
| } | ||||
| 
 | ||||
| impl PipelineBuilder { | ||||
|     pub fn new(vertex_shader: Shader) -> Self { | ||||
| impl<'a> PipelineBuilder<'a> { | ||||
|     pub fn new(shader_storage: &'a mut AssetStorage<Shader>, vertex_shader: Shader) -> Self { | ||||
|         let vertex_shader_handle = shader_storage.add(vertex_shader); | ||||
|         PipelineBuilder { | ||||
|             pipeline: PipelineDescriptor::new(vertex_shader), | ||||
|             pipeline: PipelineDescriptor::new(vertex_shader_handle), | ||||
|             shader_storage, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -101,7 +104,8 @@ impl PipelineBuilder { | ||||
|     } | ||||
| 
 | ||||
|     pub fn with_fragment_shader(mut self, fragment_shader: Shader) -> Self { | ||||
|         self.pipeline.shader_stages.fragment = Some(fragment_shader); | ||||
|         let fragment_shader_handle = self.shader_storage.add(fragment_shader); | ||||
|         self.pipeline.shader_stages.fragment = Some(fragment_shader_handle); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,22 +1,22 @@ | ||||
| use crate::render::{ | ||||
| use crate::{asset::AssetStorage, render::{ | ||||
|     render_graph_2::{ | ||||
|         draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder, | ||||
|     }, | ||||
|     shader::{Shader, ShaderStage}, | ||||
|     Vertex, | ||||
| }; | ||||
| }}; | ||||
| pub trait ForwardPipelineBuilder { | ||||
|     fn add_forward_pipeline(self) -> Self; | ||||
|     fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self; | ||||
| } | ||||
| 
 | ||||
| impl ForwardPipelineBuilder for RenderGraphBuilder { | ||||
|     fn add_forward_pipeline(self) -> Self { | ||||
|     fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, shader_storage: &mut AssetStorage<Shader>) -> Self { | ||||
|         self.add_pipeline( | ||||
|             "forward", | ||||
|             PipelineDescriptor::build(Shader::from_glsl( | ||||
|                 include_str!("forward.vert"), | ||||
|                 ShaderStage::Vertex, | ||||
|             )) | ||||
|             pipeline_descriptor_storage, | ||||
|             PipelineDescriptor::build( | ||||
|                 shader_storage, | ||||
|                 Shader::from_glsl(include_str!("forward.vert"), ShaderStage::Vertex), | ||||
|             ) | ||||
|             .with_fragment_shader(Shader::from_glsl( | ||||
|                 include_str!("forward.frag"), | ||||
|                 ShaderStage::Fragment, | ||||
|  | ||||
| @ -1,22 +1,35 @@ | ||||
| use crate::render::{ | ||||
|     render_graph_2::{ | ||||
|         draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, RenderGraphBuilder, | ||||
| use crate::{ | ||||
|     asset::AssetStorage, | ||||
|     render::{ | ||||
|         render_graph_2::{ | ||||
|             draw_targets::mesh_draw_target, pipeline_layout::*, PipelineDescriptor, | ||||
|             RenderGraphBuilder, | ||||
|         }, | ||||
|         shader::{Shader, ShaderStage}, | ||||
|         Vertex, | ||||
|     }, | ||||
|     shader::{Shader, ShaderStage}, | ||||
|     Vertex, | ||||
| }; | ||||
| 
 | ||||
| pub trait ForwardFlatPipelineBuilder { | ||||
|     fn add_forward_flat_pipeline(self) -> Self; | ||||
|     fn add_forward_flat_pipeline( | ||||
|         self, | ||||
|         pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, | ||||
|         shader_storage: &mut AssetStorage<Shader>, | ||||
|     ) -> Self; | ||||
| } | ||||
| 
 | ||||
| impl ForwardFlatPipelineBuilder for RenderGraphBuilder { | ||||
|     fn add_forward_flat_pipeline(self) -> Self { | ||||
|     fn add_forward_flat_pipeline( | ||||
|         self, | ||||
|         pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, | ||||
|         shader_storage: &mut AssetStorage<Shader>, | ||||
|     ) -> Self { | ||||
|         self.add_pipeline( | ||||
|             "forward_flat", | ||||
|             PipelineDescriptor::build(Shader::from_glsl( | ||||
|                 include_str!("forward_flat.vert"), | ||||
|                 ShaderStage::Vertex, | ||||
|             )) | ||||
|             pipeline_descriptor_storage, | ||||
|             PipelineDescriptor::build( | ||||
|                 shader_storage, | ||||
|                 Shader::from_glsl(include_str!("forward_flat.vert"), ShaderStage::Vertex), | ||||
|             ) | ||||
|             .with_fragment_shader(Shader::from_glsl( | ||||
|                 include_str!("forward_flat.frag"), | ||||
|                 ShaderStage::Fragment, | ||||
|  | ||||
| @ -1,23 +1,34 @@ | ||||
| use crate::render::{ | ||||
|     render_graph_2::{ | ||||
|         draw_targets::ui_draw_target, pipeline_layout::*, resource_providers::RectData, | ||||
|         PipelineDescriptor, RenderGraphBuilder, VertexBufferDescriptor, | ||||
| use crate::{ | ||||
|     asset::AssetStorage, | ||||
|     render::{ | ||||
|         render_graph_2::{ | ||||
|             draw_targets::ui_draw_target, pipeline_layout::*, resource_providers::RectData, | ||||
|             PipelineDescriptor, RenderGraphBuilder, VertexBufferDescriptor, | ||||
|         }, | ||||
|         shader::{Shader, ShaderStage}, | ||||
|         Vertex, | ||||
|     }, | ||||
|     shader::{Shader, ShaderStage}, | ||||
|     Vertex, | ||||
| }; | ||||
| pub trait UiPipelineBuilder { | ||||
|     fn add_ui_pipeline(self) -> Self; | ||||
|     fn add_ui_pipeline( | ||||
|         self, | ||||
|         pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, | ||||
|         shader_storage: &mut AssetStorage<Shader>, | ||||
|     ) -> Self; | ||||
| } | ||||
| 
 | ||||
| impl UiPipelineBuilder for RenderGraphBuilder { | ||||
|     fn add_ui_pipeline(self) -> Self { | ||||
|     fn add_ui_pipeline( | ||||
|         self, | ||||
|         pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, | ||||
|         shader_storage: &mut AssetStorage<Shader>, | ||||
|     ) -> Self { | ||||
|         self.add_pipeline( | ||||
|             "ui", | ||||
|             PipelineDescriptor::build(Shader::from_glsl( | ||||
|                 include_str!("ui.vert"), | ||||
|                 ShaderStage::Vertex, | ||||
|             )) | ||||
|             pipeline_descriptor_storage, | ||||
|             PipelineDescriptor::build( | ||||
|                 shader_storage, | ||||
|                 Shader::from_glsl(include_str!("ui.vert"), ShaderStage::Vertex), | ||||
|             ) | ||||
|             .with_fragment_shader(Shader::from_glsl( | ||||
|                 include_str!("ui.frag"), | ||||
|                 ShaderStage::Fragment, | ||||
|  | ||||
| @ -1,13 +1,16 @@ | ||||
| use crate::render::render_graph_2::{ | ||||
|     PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor, | ||||
| use crate::{ | ||||
|     asset::{AssetStorage, Handle}, | ||||
|     render::{ | ||||
|         render_graph_2::{PassDescriptor, PipelineDescriptor, ResourceProvider, TextureDescriptor}, | ||||
|     }, | ||||
| }; | ||||
| use std::collections::HashMap; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| 
 | ||||
| pub struct RenderGraph { | ||||
|     pub pipeline_descriptors: HashMap<String, PipelineDescriptor>, | ||||
|     pub pipeline_descriptors: HashSet<Handle<PipelineDescriptor>>, | ||||
|     // TODO: make this ordered
 | ||||
|     pub pass_descriptors: HashMap<String, PassDescriptor>, | ||||
|     pub pass_pipelines: HashMap<String, Vec<String>>, | ||||
|     pub pass_pipelines: HashMap<String, Vec<Handle<PipelineDescriptor>>>, | ||||
|     pub resource_providers: Vec<Box<dyn ResourceProvider>>, | ||||
|     pub queued_textures: Vec<(String, TextureDescriptor)>, | ||||
| } | ||||
| @ -15,7 +18,7 @@ pub struct RenderGraph { | ||||
| impl Default for RenderGraph { | ||||
|     fn default() -> Self { | ||||
|         RenderGraph { | ||||
|             pipeline_descriptors: HashMap::new(), | ||||
|             pipeline_descriptors: HashSet::new(), | ||||
|             pass_descriptors: HashMap::new(), | ||||
|             pass_pipelines: HashMap::new(), | ||||
|             resource_providers: Vec::new(), | ||||
| @ -24,9 +27,23 @@ impl Default for RenderGraph { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl RenderGraph { | ||||
|     pub fn add_pipeline(&mut self, pass: &str, pipeline: Handle<PipelineDescriptor>) { | ||||
|         self.pipeline_descriptors.insert(pipeline.clone()); | ||||
| 
 | ||||
|         if let None = self.pass_pipelines.get(pass) { | ||||
|             self.pass_pipelines.insert(pass.to_string(), Vec::new()); | ||||
|         } | ||||
| 
 | ||||
|         let pass_pipelines = self.pass_pipelines.get_mut(pass).unwrap(); | ||||
|         pass_pipelines.push(pipeline); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct RenderGraphBuilder { | ||||
|     render_graph: RenderGraph, | ||||
|     current_pass: Option<String>, | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| impl RenderGraphBuilder { | ||||
| @ -45,24 +62,10 @@ impl RenderGraphBuilder { | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_pipeline(mut self, name: &str, pipeline: PipelineDescriptor) -> Self { | ||||
|         self.render_graph | ||||
|             .pipeline_descriptors | ||||
|             .insert(name.to_string(), pipeline); | ||||
| 
 | ||||
|         if let Some(current_pass) = self.current_pass.as_ref() { | ||||
|             if let None = self.render_graph.pass_pipelines.get(current_pass) { | ||||
|                 self.render_graph | ||||
|                     .pass_pipelines | ||||
|                     .insert(current_pass.to_string(), Vec::new()); | ||||
|             } | ||||
| 
 | ||||
|             let pass_pipelines = self | ||||
|                 .render_graph | ||||
|                 .pass_pipelines | ||||
|                 .get_mut(current_pass) | ||||
|                 .unwrap(); | ||||
|             pass_pipelines.push(name.to_string()); | ||||
|     pub fn add_pipeline(mut self, pipeline_descriptor_storage: &mut AssetStorage<PipelineDescriptor>, pipeline: PipelineDescriptor) -> Self { | ||||
|         if let Some(ref pass) = self.current_pass { | ||||
|             let pipeline_descriptor_handle = pipeline_descriptor_storage.add(pipeline); | ||||
|             self.render_graph.add_pipeline(&pass, pipeline_descriptor_handle); | ||||
|         } | ||||
| 
 | ||||
|         self | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| use crate::{ | ||||
|     asset::{AssetStorage, Handle}, | ||||
|     render::{render_graph_2::RenderGraph, Shader}, | ||||
|     render::{render_graph_2::RenderGraph, Shader, ShaderStages}, | ||||
| }; | ||||
| use legion::prelude::*; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| use super::PipelineDescriptor; | ||||
| 
 | ||||
| pub struct Renderable { | ||||
|     pub is_visible: bool, | ||||
|     pub shaders: Vec<Handle<Shader>>, | ||||
|     pub pipelines: Vec<Handle<PipelineDescriptor>>, | ||||
|     pub shader_defs: HashSet<String>, | ||||
| } | ||||
| 
 | ||||
| @ -15,7 +16,7 @@ impl Default for Renderable { | ||||
|     fn default() -> Self { | ||||
|         Renderable { | ||||
|             is_visible: true, | ||||
|             shaders: Vec::new(), | ||||
|             pipelines: Vec::new(), | ||||
|             shader_defs: HashSet::new(), | ||||
|         } | ||||
|     } | ||||
| @ -53,24 +54,28 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra | ||||
|         let shader_assignments = world.resources.get_mut::<ShaderAssignments>().unwrap(); | ||||
|         let mut compiled_shader_map = world.resources.get_mut::<CompiledShaderMap>().unwrap(); | ||||
|         let mut shader_storage = world.resources.get_mut::<AssetStorage<Shader>>().unwrap(); | ||||
|         let pipeline_descriptor_storage = world.resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap(); | ||||
|         for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) { | ||||
|             for shader in renderable.shaders.iter() { | ||||
|                 if let None = compiled_shader_map.source_to_compiled.get(shader) { | ||||
|                     compiled_shader_map | ||||
|                         .source_to_compiled | ||||
|                         .insert(shader.clone(), Vec::new()); | ||||
|                 } | ||||
|             for pipeline_handle in renderable.pipelines.iter() { | ||||
|                 let pipeline_descriptor = pipeline_descriptor_storage.get(pipeline_handle).unwrap(); | ||||
|                 for shader_handle in pipeline_descriptor.shader_stages.iter() { | ||||
|                     if let None = compiled_shader_map.source_to_compiled.get(shader_handle) { | ||||
|                         compiled_shader_map | ||||
|                             .source_to_compiled | ||||
|                             .insert(shader_handle.clone(), Vec::new()); | ||||
|                     } | ||||
| 
 | ||||
|                 let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader).unwrap(); | ||||
|                 if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) { | ||||
|                     let shader_resource = shader_storage.get(shader).unwrap(); | ||||
|                     let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>(); | ||||
|                     let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec)); | ||||
|                     compiled_shaders.push((renderable.shader_defs.clone(), shader.clone())); | ||||
|                     let compiled_shader_handle = shader_storage.add(compiled_shader); | ||||
|                     // TODO: collecting assigments in a map means they won't be removed when the macro changes
 | ||||
|                     // TODO: need to somehow grab base shader's pipeline, then copy it 
 | ||||
|                     // shader_assignments.assignments.insert()
 | ||||
|                     let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader_handle).unwrap(); | ||||
|                     if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) { | ||||
|                         let shader_resource = shader_storage.get(shader_handle).unwrap(); | ||||
|                         let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>(); | ||||
|                         let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec)); | ||||
|                         compiled_shaders.push((renderable.shader_defs.clone(), shader_handle.clone())); | ||||
|                         let compiled_shader_handle = shader_storage.add(compiled_shader); | ||||
|                         // TODO: collecting assigments in a map means they won't be removed when the macro changes
 | ||||
|                         // TODO: need to somehow grab base shader's pipeline, then copy it 
 | ||||
|                         // shader_assignments.assignments.insert()
 | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -1,11 +1,15 @@ | ||||
| use crate::{ | ||||
|     asset::{AssetStorage, Handle}, | ||||
|     legion::prelude::*, | ||||
|     render::{Shader, render_graph_2::{ | ||||
|         resource_name, update_shader_assignments, BindGroup, BindType, DynamicUniformBufferInfo, | ||||
|         PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass, | ||||
|         RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, Renderer, | ||||
|         ResourceInfo, ShaderUniforms, TextureDescriptor, | ||||
|     }}, | ||||
|     render::{ | ||||
|         render_graph_2::{ | ||||
|             resource_name, update_shader_assignments, BindGroup, BindType, | ||||
|             DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass, | ||||
|             RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, | ||||
|             Renderer, ResourceInfo, TextureDescriptor, | ||||
|         }, | ||||
|         Shader, | ||||
|     }, | ||||
| }; | ||||
| use std::{collections::HashMap, ops::Deref}; | ||||
| 
 | ||||
| @ -15,7 +19,7 @@ pub struct WgpuRenderer { | ||||
|     pub surface: Option<wgpu::Surface>, | ||||
|     pub encoder: Option<wgpu::CommandEncoder>, | ||||
|     pub swap_chain_descriptor: wgpu::SwapChainDescriptor, | ||||
|     pub render_pipelines: HashMap<String, wgpu::RenderPipeline>, | ||||
|     pub render_pipelines: HashMap<Handle<PipelineDescriptor>, wgpu::RenderPipeline>, | ||||
|     pub buffers: HashMap<String, wgpu::Buffer>, | ||||
|     pub textures: HashMap<String, wgpu::TextureView>, | ||||
|     pub resource_info: HashMap<String, ResourceInfo>, | ||||
| @ -69,12 +73,14 @@ impl WgpuRenderer { | ||||
|         pipeline_descriptor: &mut PipelineDescriptor, | ||||
|         bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>, | ||||
|         device: &wgpu::Device, | ||||
|         vertex_shader: &Shader, | ||||
|         fragment_shader: Option<&Shader>, | ||||
|     ) -> wgpu::RenderPipeline { | ||||
|         let vertex_shader_module = Self::create_shader_module(device, &pipeline_descriptor | ||||
|             .shader_stages | ||||
|             .vertex, None); | ||||
|         let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment { | ||||
|             Some(ref fragment_shader) => Some(Self::create_shader_module(device, fragment_shader, None)), | ||||
|         let vertex_shader_module = Self::create_shader_module(device, vertex_shader, None); | ||||
|         let fragment_shader_module = match fragment_shader { | ||||
|             Some(fragment_shader) => { | ||||
|                 Some(Self::create_shader_module(device, fragment_shader, None)) | ||||
|             } | ||||
|             None => None, | ||||
|         }; | ||||
| 
 | ||||
| @ -121,10 +127,10 @@ impl WgpuRenderer { | ||||
|             layout: &pipeline_layout, | ||||
|             vertex_stage: wgpu::ProgrammableStageDescriptor { | ||||
|                 module: &vertex_shader_module, | ||||
|                 entry_point: &pipeline_descriptor.shader_stages.vertex.entry_point, | ||||
|                 entry_point: &vertex_shader.entry_point, | ||||
|             }, | ||||
|             fragment_stage: match pipeline_descriptor.shader_stages.fragment { | ||||
|                 Some(ref fragment_shader) => Some(wgpu::ProgrammableStageDescriptor { | ||||
|             fragment_stage: match fragment_shader { | ||||
|                 Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor { | ||||
|                     entry_point: &fragment_shader.entry_point, | ||||
|                     module: fragment_shader_module.as_ref().unwrap(), | ||||
|                 }), | ||||
| @ -303,115 +309,11 @@ impl WgpuRenderer { | ||||
|         bind_group_id | ||||
|     } | ||||
| 
 | ||||
|     // TODO: remove me
 | ||||
|     #[allow(dead_code)] | ||||
|     fn setup_dynamic_entity_shader_uniforms( | ||||
|         &mut self, | ||||
|         world: &World, | ||||
|         render_graph: &RenderGraph, | ||||
|         encoder: &mut wgpu::CommandEncoder, | ||||
|     ) { | ||||
|         // retrieve all uniforms buffers that aren't aleady set. these are "dynamic" uniforms, which are set by the user in ShaderUniforms
 | ||||
|         // TODO: this breaks down in multiple ways:
 | ||||
|         // (1) resource_info will be set after the first run so this won't update.
 | ||||
|         // (2) if we create new buffers, the old bind groups will be invalid
 | ||||
|         for pipeline in render_graph.pipeline_descriptors.values() { | ||||
|             for bind_group in pipeline.pipeline_layout.bind_groups.iter() { | ||||
|                 for binding in bind_group.bindings.iter() { | ||||
|                     // if let None = self.resource_info.get(&binding.name) {
 | ||||
|                     if let BindType::Uniform { dynamic: true, .. } = &binding.bind_type { | ||||
|                         if self.dynamic_uniform_buffer_info.contains_key(&binding.name) { | ||||
|                             continue; | ||||
|                         } | ||||
| 
 | ||||
|                         self.dynamic_uniform_buffer_info.insert( | ||||
|                             binding.name.to_string(), | ||||
|                             DynamicUniformBufferInfo { | ||||
|                                 capacity: 0, | ||||
|                                 count: 0, | ||||
|                                 size: binding.bind_type.get_uniform_size().unwrap(), | ||||
|                                 indices: HashMap::new(), | ||||
|                                 offsets: HashMap::new(), | ||||
|                             }, | ||||
|                         ); | ||||
|                     } | ||||
|                     // }
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // count the number of entities providing each uniform
 | ||||
|         for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() { | ||||
|             info.count = 0; | ||||
|             for (entity, shader_uniforms) in <Read<ShaderUniforms>>::query().iter_entities(world) { | ||||
|                 if let Some(_) = shader_uniforms.get_uniform_info(world, entity, name) { | ||||
|                     info.count += 1; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // allocate uniform buffers
 | ||||
|         for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() { | ||||
|             if self.buffers.contains_key(name) && info.count < info.capacity { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if info.count >= info.capacity && info.capacity != 0 { | ||||
|                 panic!("resizing dynamic uniform buffers isn't supported yet. we still need to support updating bind groups"); | ||||
|             } | ||||
| 
 | ||||
|             // allocate enough space for twice as many entities as there are currently;
 | ||||
|             info.capacity = info.count * 2; | ||||
|             let size = wgpu::BIND_BUFFER_ALIGNMENT * info.capacity; | ||||
| 
 | ||||
|             // TODO: remove this code duplication in favor of self.create_buffer(). this will likely require a refactor
 | ||||
|             // the following is a flattening of the content in self.create_buffer(), which can't be called because
 | ||||
|             // of rust's ownership rules. sometimes rust makes me unhappy
 | ||||
| 
 | ||||
|             let buffer_usage = wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM; | ||||
|             let buffer = self.device.create_buffer(&wgpu::BufferDescriptor { | ||||
|                 size, | ||||
|                 usage: buffer_usage, | ||||
|             }); | ||||
| 
 | ||||
|             self.resource_info.insert( | ||||
|                 name.to_string(), | ||||
|                 ResourceInfo::Buffer { buffer_usage, size }, | ||||
|             ); | ||||
| 
 | ||||
|             self.buffers.insert(name.to_string(), buffer); | ||||
|         } | ||||
| 
 | ||||
|         // copy entity uniform data to buffers
 | ||||
|         for (name, info) in self.dynamic_uniform_buffer_info.iter_mut() { | ||||
|             let size = wgpu::BIND_BUFFER_ALIGNMENT * info.count; | ||||
|             let mapped = self | ||||
|                 .device | ||||
|                 .create_buffer_mapped(size as usize, wgpu::BufferUsage::COPY_SRC); | ||||
|             let alignment = wgpu::BIND_BUFFER_ALIGNMENT as usize; | ||||
|             let mut offset = 0usize; | ||||
| 
 | ||||
|             for (i, (entity, shader_uniforms)) in <Read<ShaderUniforms>>::query() | ||||
|                 .iter_entities(world) | ||||
|                 .enumerate() | ||||
|             { | ||||
|                 // TODO: check if index has changed. if it has, then entity should be updated
 | ||||
|                 // TODO: only mem-map entities if their data has changed
 | ||||
|                 info.offsets.insert(entity, offset as u64); | ||||
|                 info.indices.insert(i, entity); | ||||
|                 if let Some(bytes) = shader_uniforms.get_uniform_bytes(world, entity, name) { | ||||
|                     mapped.data[offset..(offset + bytes.len())].copy_from_slice(bytes.as_slice()); | ||||
|                     offset += alignment; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let temp_buffer = mapped.finish(); | ||||
|             let uniform_buffer = self.buffers.get(name); | ||||
|             encoder.copy_buffer_to_buffer(&temp_buffer, 0, uniform_buffer.unwrap(), 0, size); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_shader_module(device: &wgpu::Device, shader: &Shader, macros: Option<&[String]>) -> wgpu::ShaderModule { | ||||
|     pub fn create_shader_module( | ||||
|         device: &wgpu::Device, | ||||
|         shader: &Shader, | ||||
|         macros: Option<&[String]>, | ||||
|     ) -> wgpu::ShaderModule { | ||||
|         device.create_shader_module(&shader.get_spirv(macros)) | ||||
|     } | ||||
| } | ||||
| @ -489,16 +391,38 @@ impl Renderer for WgpuRenderer { | ||||
|         // self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder);
 | ||||
| 
 | ||||
|         // setup, pipelines, bind groups, and resources
 | ||||
|         for (pipeline_name, pipeline_descriptor) in render_graph.pipeline_descriptors.iter_mut() { | ||||
|         let mut pipeline_storage = world | ||||
|             .resources | ||||
|             .get_mut::<AssetStorage<PipelineDescriptor>>() | ||||
|             .unwrap(); | ||||
|         let shader_storage = world.resources.get::<AssetStorage<Shader>>().unwrap(); | ||||
| 
 | ||||
|         for pipeline_descriptor_handle in render_graph.pipeline_descriptors.iter() { | ||||
|             let pipeline_descriptor = pipeline_storage | ||||
|                 .get_mut(pipeline_descriptor_handle) | ||||
|                 .unwrap(); | ||||
|             // create pipelines
 | ||||
|             if let None = self.render_pipelines.get(pipeline_name) { | ||||
|             if !self | ||||
|                 .render_pipelines | ||||
|                 .contains_key(pipeline_descriptor_handle) | ||||
|             { | ||||
|                 let vertex_shader = shader_storage | ||||
|                     .get(&pipeline_descriptor.shader_stages.vertex) | ||||
|                     .unwrap(); | ||||
|                 let fragment_shader = pipeline_descriptor | ||||
|                     .shader_stages | ||||
|                     .fragment | ||||
|                     .as_ref() | ||||
|                     .map(|handle| &*shader_storage.get(&handle).unwrap()); | ||||
|                 let render_pipeline = WgpuRenderer::create_render_pipeline( | ||||
|                     pipeline_descriptor, | ||||
|                     &mut self.bind_group_layouts, | ||||
|                     &self.device, | ||||
|                     vertex_shader, | ||||
|                     fragment_shader, | ||||
|                 ); | ||||
|                 self.render_pipelines | ||||
|                     .insert(pipeline_name.to_string(), render_pipeline); | ||||
|                     .insert(pipeline_descriptor_handle.clone(), render_pipeline); | ||||
|             } | ||||
| 
 | ||||
|             // create bind groups
 | ||||
| @ -512,21 +436,18 @@ impl Renderer for WgpuRenderer { | ||||
|             let mut render_pass = self.create_render_pass(pass_descriptor, &mut encoder, &frame); | ||||
|             if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) { | ||||
|                 for pass_pipeline in pass_pipelines.iter() { | ||||
|                     if let Some(pipeline_descriptor) = | ||||
|                         render_graph.pipeline_descriptors.get(pass_pipeline) | ||||
|                     { | ||||
|                         let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap(); | ||||
|                         render_pass.set_pipeline(render_pipeline); | ||||
|                     let pipeline_descriptor = pipeline_storage.get(pass_pipeline).unwrap(); | ||||
|                     let render_pipeline = self.render_pipelines.get(pass_pipeline).unwrap(); | ||||
|                     render_pass.set_pipeline(render_pipeline); | ||||
| 
 | ||||
|                         let mut render_pass = WgpuRenderPass { | ||||
|                             render_pass: &mut render_pass, | ||||
|                             renderer: self, | ||||
|                             pipeline_descriptor, | ||||
|                         }; | ||||
|                     let mut render_pass = WgpuRenderPass { | ||||
|                         render_pass: &mut render_pass, | ||||
|                         renderer: self, | ||||
|                         pipeline_descriptor, | ||||
|                     }; | ||||
| 
 | ||||
|                         for draw_target in pipeline_descriptor.draw_targets.iter() { | ||||
|                             draw_target(world, &mut render_pass); | ||||
|                         } | ||||
|                     for draw_target in pipeline_descriptor.draw_targets.iter() { | ||||
|                         draw_target(world, &mut render_pass); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| use crate::asset::Handle; | ||||
| use std::marker::Copy; | ||||
| 
 | ||||
| #[derive(Hash, Eq, PartialEq, Copy, Clone)] | ||||
| @ -69,9 +70,7 @@ impl Shader { | ||||
|     pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec<u32> { | ||||
|         match self.source { | ||||
|             ShaderSource::Spirv(ref bytes) => bytes.clone(), | ||||
|             ShaderSource::Glsl(ref source) => { | ||||
|                 glsl_to_spirv(&source, self.stage, macros) | ||||
|             } | ||||
|             ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, macros), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -85,15 +84,44 @@ impl Shader { | ||||
| } | ||||
| 
 | ||||
| pub struct ShaderStages { | ||||
|     pub vertex: Shader, | ||||
|     pub fragment: Option<Shader>, | ||||
|     pub vertex: Handle<Shader>, | ||||
|     pub fragment: Option<Handle<Shader>>, | ||||
| } | ||||
| 
 | ||||
| impl ShaderStages { | ||||
|     pub fn new(vertex_shader: Shader) -> Self { | ||||
|     pub fn new(vertex_shader: Handle<Shader>) -> Self { | ||||
|         ShaderStages { | ||||
|             vertex: vertex_shader, | ||||
|             fragment: None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> ShaderStagesIter { | ||||
|         ShaderStagesIter { | ||||
|             shader_stages: self, | ||||
|             index: 0, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct ShaderStagesIter<'a> { | ||||
|     pub shader_stages: &'a ShaderStages, | ||||
|     pub index: usize, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Iterator for ShaderStagesIter<'a> { | ||||
|     type Item = &'a Handle<Shader>; | ||||
|     fn next(&mut self) -> Option<&'a Handle<Shader>> { | ||||
|         match self.index { | ||||
|             0 => Some(&self.shader_stages.vertex), | ||||
|             1 => { | ||||
|                 if let Some(ref fragment) = self.shader_stages.fragment { | ||||
|                     Some(fragment) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson