From 4de039eb71258b3a7dcff5ac0be7af1ca7e742e4 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 15 Feb 2020 16:28:17 -0800 Subject: [PATCH] Make PipelineDescriptor an Asset that references Handle --- src/app/app_builder.rs | 37 ++-- src/asset/mod.rs | 28 ++- src/render/passes/forward/forward_pipeline.rs | 2 +- src/render/passes/forward_instanced/mod.rs | 2 +- src/render/passes/forward_shadow/mod.rs | 2 +- src/render/passes/shadow/shadow_pipeline.rs | 2 +- src/render/passes/ui/mod.rs | 2 +- .../draw_targets/mesh_draw_target.rs | 2 +- .../draw_targets/ui_draw_target.rs | 2 +- src/render/render_graph_2/pipeline.rs | 24 ++- .../render_graph_2/pipelines/forward/mod.rs | 18 +- .../pipelines/forward_flat/mod.rs | 37 ++-- src/render/render_graph_2/pipelines/ui/mod.rs | 37 ++-- src/render/render_graph_2/render_graph.rs | 51 ++--- src/render/render_graph_2/renderable.rs | 43 ++-- .../render_graph_2/renderers/wgpu_renderer.rs | 201 ++++++------------ src/render/shader.rs | 40 +++- 17 files changed, 275 insertions(+), 255 deletions(-) diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index 2f4d89dd8f..547d52bb5f 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -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::::new()); resources.insert(AssetStorage::::new()); resources.insert(AssetStorage::::new()); + resources.insert(AssetStorage::::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::::new())) - .add_resource_provider(Box::new(UniformResourceProvider::::new())) - .add_forward_pass() - .add_forward_pipeline() - .add_ui_pipeline(); + { + let mut pipeline_storage = self + .world + .resources + .get_mut::>() + .unwrap(); + let mut shader_storage = self + .world + .resources + .get_mut::>() + .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::::new())) + .add_resource_provider(Box::new(UniformResourceProvider::::new())) + .add_forward_pass() + .add_forward_pipeline(&mut pipeline_storage, &mut shader_storage) + .add_ui_pipeline(&mut pipeline_storage, &mut shader_storage); + } self } diff --git a/src/asset/mod.rs b/src/asset/mod.rs index 00a30068ec..94210f2b97 100644 --- a/src/asset/mod.rs +++ b/src/asset/mod.rs @@ -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 { pub id: usize, marker: PhantomData, } +impl Hash for Handle { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl PartialEq for Handle { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for Handle {} + // TODO: somehow handle this gracefully in asset managers. or alternatively remove Default impl Default for Handle { fn default() -> Self { @@ -75,11 +89,19 @@ impl AssetStorage { 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) -> Option<&mut T> { + pub fn get(&self, handle: &Handle) -> Option<&T> { + self.assets.get(&handle.id) + } + + pub fn get_mut(&mut self, handle: &Handle) -> Option<&mut T> { self.assets.get_mut(&handle.id) } } diff --git a/src/render/passes/forward/forward_pipeline.rs b/src/render/passes/forward/forward_pipeline.rs index 128b214b21..3439682576 100644 --- a/src/render/passes/forward/forward_pipeline.rs +++ b/src/render/passes/forward/forward_pipeline.rs @@ -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)]); diff --git a/src/render/passes/forward_instanced/mod.rs b/src/render/passes/forward_instanced/mod.rs index 75099ab869..be19032c89 100644 --- a/src/render/passes/forward_instanced/mod.rs +++ b/src/render/passes/forward_instanced/mod.rs @@ -285,7 +285,7 @@ impl Pipeline for ForwardInstancedPipeline { let mut mesh_storage = world.resources.get_mut::>().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)]); diff --git a/src/render/passes/forward_shadow/mod.rs b/src/render/passes/forward_shadow/mod.rs index 279f071214..ee57ff1db7 100644 --- a/src/render/passes/forward_shadow/mod.rs +++ b/src/render/passes/forward_shadow/mod.rs @@ -176,7 +176,7 @@ impl Pipeline for ForwardShadowPassNew { let mut mesh_storage = world.resources.get_mut::>().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); diff --git a/src/render/passes/shadow/shadow_pipeline.rs b/src/render/passes/shadow/shadow_pipeline.rs index e357b761a0..f1e04cd039 100644 --- a/src/render/passes/shadow/shadow_pipeline.rs +++ b/src/render/passes/shadow/shadow_pipeline.rs @@ -166,7 +166,7 @@ impl Pipeline for ShadowPipeline { let mut mesh_storage = world.resources.get_mut::>().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(), &[]); diff --git a/src/render/passes/ui/mod.rs b/src/render/passes/ui/mod.rs index 528792de9e..ef5dd1518f 100644 --- a/src/render/passes/ui/mod.rs +++ b/src/render/passes/ui/mod.rs @@ -242,7 +242,7 @@ impl Pipeline for UiPipeline { let mut mesh_storage = world.resources.get_mut::>().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)]); diff --git a/src/render/render_graph_2/draw_targets/mesh_draw_target.rs b/src/render/render_graph_2/draw_targets/mesh_draw_target.rs index 8b5b1f7cf5..f65ea9f73e 100644 --- a/src/render/render_graph_2/draw_targets/mesh_draw_target.rs +++ b/src/render/render_graph_2/draw_targets/mesh_draw_target.rs @@ -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::>().unwrap(); + let mesh_storage = world.resources.get_mut::>().unwrap(); let mut current_mesh_id = None; let mut current_mesh_index_length = 0; let mesh_query = <(Read, Read>, Read)>::query() diff --git a/src/render/render_graph_2/draw_targets/ui_draw_target.rs b/src/render/render_graph_2/draw_targets/ui_draw_target.rs index 6d4040e062..f26bf5e5ef 100644 --- a/src/render/render_graph_2/draw_targets/ui_draw_target.rs +++ b/src/render/render_graph_2/draw_targets/ui_draw_target.rs @@ -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::>().unwrap(); + let mesh_storage = world.resources.get_mut::>().unwrap(); // NOTE: this is ugly and borrowing is stupid let result = { let renderer = render_pass.get_renderer(); diff --git a/src/render/render_graph_2/pipeline.rs b/src/render/render_graph_2/pipeline.rs index b061a80d45..b0b49dee06 100644 --- a/src/render/render_graph_2/pipeline.rs +++ b/src/render/render_graph_2/pipeline.rs @@ -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) -> 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, vertex_shader: Shader) -> PipelineBuilder { + PipelineBuilder::new(shader_storage, vertex_shader) } } -pub struct PipelineBuilder { +pub struct PipelineBuilder<'a> { pipeline: PipelineDescriptor, + shader_storage: &'a mut AssetStorage, } -impl PipelineBuilder { - pub fn new(vertex_shader: Shader) -> Self { +impl<'a> PipelineBuilder<'a> { + pub fn new(shader_storage: &'a mut AssetStorage, 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 } diff --git a/src/render/render_graph_2/pipelines/forward/mod.rs b/src/render/render_graph_2/pipelines/forward/mod.rs index 346c61497b..6b10ec6860 100644 --- a/src/render/render_graph_2/pipelines/forward/mod.rs +++ b/src/render/render_graph_2/pipelines/forward/mod.rs @@ -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, shader_storage: &mut AssetStorage) -> Self; } impl ForwardPipelineBuilder for RenderGraphBuilder { - fn add_forward_pipeline(self) -> Self { + fn add_forward_pipeline(self, pipeline_descriptor_storage: &mut AssetStorage, shader_storage: &mut AssetStorage) -> 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, diff --git a/src/render/render_graph_2/pipelines/forward_flat/mod.rs b/src/render/render_graph_2/pipelines/forward_flat/mod.rs index 8c60659c14..a018a0ab8d 100644 --- a/src/render/render_graph_2/pipelines/forward_flat/mod.rs +++ b/src/render/render_graph_2/pipelines/forward_flat/mod.rs @@ -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, + shader_storage: &mut AssetStorage, + ) -> Self; } impl ForwardFlatPipelineBuilder for RenderGraphBuilder { - fn add_forward_flat_pipeline(self) -> Self { + fn add_forward_flat_pipeline( + self, + pipeline_descriptor_storage: &mut AssetStorage, + shader_storage: &mut AssetStorage, + ) -> 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, diff --git a/src/render/render_graph_2/pipelines/ui/mod.rs b/src/render/render_graph_2/pipelines/ui/mod.rs index 12aefa3d02..59ef0d4265 100644 --- a/src/render/render_graph_2/pipelines/ui/mod.rs +++ b/src/render/render_graph_2/pipelines/ui/mod.rs @@ -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, + shader_storage: &mut AssetStorage, + ) -> Self; } impl UiPipelineBuilder for RenderGraphBuilder { - fn add_ui_pipeline(self) -> Self { + fn add_ui_pipeline( + self, + pipeline_descriptor_storage: &mut AssetStorage, + shader_storage: &mut AssetStorage, + ) -> 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, diff --git a/src/render/render_graph_2/render_graph.rs b/src/render/render_graph_2/render_graph.rs index 3e9ad43b85..b794824e93 100644 --- a/src/render/render_graph_2/render_graph.rs +++ b/src/render/render_graph_2/render_graph.rs @@ -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, + pub pipeline_descriptors: HashSet>, // TODO: make this ordered pub pass_descriptors: HashMap, - pub pass_pipelines: HashMap>, + pub pass_pipelines: HashMap>>, pub resource_providers: Vec>, 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) { + 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, + } 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, 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 diff --git a/src/render/render_graph_2/renderable.rs b/src/render/render_graph_2/renderable.rs index f414cd2232..6c2a8719a6 100644 --- a/src/render/render_graph_2/renderable.rs +++ b/src/render/render_graph_2/renderable.rs @@ -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>, + pub pipelines: Vec>, pub shader_defs: HashSet, } @@ -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::().unwrap(); let mut compiled_shader_map = world.resources.get_mut::().unwrap(); let mut shader_storage = world.resources.get_mut::>().unwrap(); + let pipeline_descriptor_storage = world.resources.get_mut::>().unwrap(); for (entity, renderable) in >::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::>(); - 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::>(); + 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() + } } } } diff --git a/src/render/render_graph_2/renderers/wgpu_renderer.rs b/src/render/render_graph_2/renderers/wgpu_renderer.rs index 76906af750..ec7f39be34 100644 --- a/src/render/render_graph_2/renderers/wgpu_renderer.rs +++ b/src/render/render_graph_2/renderers/wgpu_renderer.rs @@ -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, pub encoder: Option, pub swap_chain_descriptor: wgpu::SwapChainDescriptor, - pub render_pipelines: HashMap, + pub render_pipelines: HashMap, wgpu::RenderPipeline>, pub buffers: HashMap, pub textures: HashMap, pub resource_info: HashMap, @@ -69,12 +73,14 @@ impl WgpuRenderer { pipeline_descriptor: &mut PipelineDescriptor, bind_group_layouts: &mut HashMap, 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 >::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 >::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::>() + .unwrap(); + let shader_storage = world.resources.get::>().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); } } } diff --git a/src/render/shader.rs b/src/render/shader.rs index 03df701cd6..02db99ec6d 100644 --- a/src/render/shader.rs +++ b/src/render/shader.rs @@ -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 { 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, + pub vertex: Handle, + pub fragment: Option>, } impl ShaderStages { - pub fn new(vertex_shader: Shader) -> Self { + pub fn new(vertex_shader: Handle) -> 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; + fn next(&mut self) -> Option<&'a Handle> { + match self.index { + 0 => Some(&self.shader_stages.vertex), + 1 => { + if let Some(ref fragment) = self.shader_stages.fragment { + Some(fragment) + } else { + None + } + } + _ => None, + } + } }