diff --git a/examples/simple.rs b/examples/simple.rs index 8a6a1c3f22..6eb25476e8 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -183,15 +183,15 @@ fn main() { // scheduler.add_system(ApplicationStage::Update, build_spawner_system(&mut world)); scheduler.add_system(ApplicationStage::Update, build_print_status_system()); - // world.insert((), vec![ - // // plane - // ( - // Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)), - // plane_handle.clone(), - // LocalToWorld::identity(), - // Translation::new(0.0, 0.0, 0.0) - // ), - // ]); + world.insert((), vec![ + // plane + ( + Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)), + plane_handle.clone(), + LocalToWorld::identity(), + Translation::new(0.0, 0.0, 0.0) + ), + ]); let x = *world.insert((), vec![ // lights @@ -263,7 +263,7 @@ fn main() { ]); let mut rng = StdRng::from_entropy(); - for _ in 0 .. 70000 { + for _ in 0 .. 1000 { create_person(&mut world, _cube_handle.clone(), Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0))); } diff --git a/src/application.rs b/src/application.rs index 85e4eb3711..a45a87fa00 100644 --- a/src/application.rs +++ b/src/application.rs @@ -5,58 +5,46 @@ use winit::{ window::Window, }; -use zerocopy::AsBytes; use legion::prelude::*; -use std::mem; - -use wgpu::{Surface, Device, Queue, SwapChain, SwapChainDescriptor}; - -use crate::{vertex::*, render::*, LocalToWorld, ApplicationStage, Time}; +use crate::{render::*, ApplicationStage, Time}; pub struct Application { pub universe: Universe, pub world: World, - pub device: Device, - pub queue: Queue, - pub surface: Surface, pub window: Window, - pub swap_chain: SwapChain, - pub swap_chain_descriptor: SwapChainDescriptor, + pub render_graph: RenderGraph, pub scheduler: SystemScheduler, - pub render_resources: RenderResources, - pub render_passes: Vec>, } impl Application { fn add_default_passes(&mut self) { - let vertex_size = mem::size_of::(); - let vertex_buffer_descriptor = wgpu::VertexBufferDescriptor { - stride: vertex_size as wgpu::BufferAddress, - step_mode: wgpu::InputStepMode::Vertex, - attributes: &[ - wgpu::VertexAttributeDescriptor { - format: wgpu::VertexFormat::Float4, - offset: 0, - shader_location: 0, - }, - wgpu::VertexAttributeDescriptor { - format: wgpu::VertexFormat::Float4, - offset: 4 * 4, - shader_location: 1, - }, - ], - }; + let local_bind_group_layout = + self.render_graph.data.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + + self.render_graph.add_render_resource_manager(Box::new(render_resources::MaterialResourceManager)); + self.render_graph.add_render_resource_manager(Box::new(render_resources::LightResourceManager::new(10))); + self.render_graph.add_render_resource_manager(Box::new(render_resources::CameraResourceManager)); + + self.render_graph.data.set_bind_group_layout("local", local_bind_group_layout); // let shadow_pass = ShadowPass::new(&mut self.device, &mut self.world, &self.render_resources, vertex_buffer_descriptor.clone()); // let forward_shadow_pass = ForwardShadowPass::new(&mut self.device, &self.world, &self.render_resources, &shadow_pass, vertex_buffer_descriptor.clone(), &self.swap_chain_descriptor); // let forward_pass = ForwardPass::new(&mut self.device, &self.world, &self.render_resources, vertex_buffer_descriptor.clone(), &self.swap_chain_descriptor); - let forward_instanced_pass = ForwardInstancedPass::new(&mut self.device, &self.world, &self.render_resources, vertex_buffer_descriptor, &self.swap_chain_descriptor); + // let forward_instanced_pass = ForwardInstancedPass::new(&mut self.device, &self.world, &self.render_resources, vertex_buffer_descriptor, &self.swap_chain_descriptor); // self.render_passes.push(Box::new(shadow_pass)); // self.render_passes.push(Box::new(forward_shadow_pass)); // self.render_passes.push(Box::new(forward_pass)); - self.render_passes.push(Box::new(forward_instanced_pass)); + // self.render_passes.push(Box::new(forward_instanced_pass)); + self.render_graph.set_pass("forward", Box::new(ForwardPass::new())); + self.render_graph.set_pipeline("forward", Box::new(ForwardPipelineNew::new())); } fn update(&mut self) { @@ -74,32 +62,7 @@ impl Application { fn resize(&mut self, width: u32, height: u32) { - self.swap_chain_descriptor.width = width; - self.swap_chain_descriptor.height = height; - self.swap_chain = self.device.create_swap_chain(&self.surface, &self.swap_chain_descriptor); - - let mut encoder = - self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - - for (mut camera, local_to_world) in <(Write, Read)>::query().iter(&mut self.world) { - camera.update(self.swap_chain_descriptor.width, self.swap_chain_descriptor.height); - let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); - let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64; - let temp_camera_buffer = - self.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC); - for pass in self.render_passes.iter() { - if let Some(buffer) = pass.get_camera_uniform_buffer() { - encoder.copy_buffer_to_buffer(&temp_camera_buffer, 0, buffer, 0, matrix_size); - } - } - } - - let command_buffer = encoder.finish(); - - for pass in self.render_passes.iter_mut() { - pass.resize(&mut self.device, &mut self.swap_chain_descriptor); - } - self.queue.submit(&[command_buffer]); + self.render_graph.resize(width, height, &mut self.world); } fn handle_event(&mut self, _: WindowEvent) @@ -108,77 +71,7 @@ impl Application { fn render(&mut self) { - let mut frame = self.swap_chain - .get_next_texture() - .expect("Timeout when acquiring next swap chain texture"); - - let mut encoder = - self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - - let mut entities = <(Write, Read)>::query() - .filter(!component::()); - let entities_count = entities.iter(&mut self.world).count(); - let size = mem::size_of::(); - let temp_buf_data = self.device - .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); - - for ((material, transform), slot) in entities.iter(&mut self.world) - .zip(temp_buf_data.data.chunks_exact_mut(size)) - { - slot.copy_from_slice( - MaterialUniforms { - model: transform.0.to_cols_array_2d(), - color: material.color.into(), - } - .as_bytes(), - ); - } - - self.render_resources.update_lights(&self.device, &mut encoder, &mut self.world); - - for mut material in >::query().filter(!component::()).iter(&mut self.world) { - if let None = material.bind_group { - let material_uniform_size = mem::size_of::() as wgpu::BufferAddress; - let uniform_buf = self.device.create_buffer(&wgpu::BufferDescriptor { - size: material_uniform_size, - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - }); - - let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &self.render_resources.local_bind_group_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &uniform_buf, - range: 0 .. material_uniform_size, - }, - }], - }); - - material.bind_group = Some(bind_group); - material.uniform_buf = Some(uniform_buf); - } - } - - let temp_buf = temp_buf_data.finish(); - - for pass in self.render_passes.iter_mut() { - pass.render(&mut self.device, &mut frame, &mut encoder, &mut self.world, &self.render_resources); - } - - // TODO: this should happen before rendering - for (i, (material, _)) in entities.iter(&mut self.world).enumerate() { - encoder.copy_buffer_to_buffer( - &temp_buf, - (i * size) as wgpu::BufferAddress, - material.uniform_buf.as_ref().unwrap(), - 0, - size as wgpu::BufferAddress, - ); - } - - let command_buffer = encoder.finish(); - self.queue.submit(&[command_buffer]); + self.render_graph.render(&mut self.world); } #[allow(dead_code)] @@ -195,7 +88,7 @@ impl Application { ) .unwrap(); - let (mut device, queue) = adapter.request_device(&wgpu::DeviceDescriptor { + let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor { extensions: wgpu::Extensions { anisotropic_filtering: false, }, @@ -223,24 +116,18 @@ impl Application { world.resources.insert(Time::new()); - let render_resources = RenderResources::new(&mut device, 10); - log::info!("Initializing the example..."); + let render_graph = RenderGraph::new(device, swap_chain_descriptor, swap_chain, queue, surface); let mut app = Application { universe, world, - device, - surface, window, - queue, - swap_chain, - swap_chain_descriptor, - render_resources, + render_graph, scheduler: system_scheduler, - render_passes: Vec::new(), }; app.add_default_passes(); + app.render_graph.initialize(&mut app.world); log::info!("Entering render loop..."); event_loop.run(move |event, _, control_flow| { diff --git a/src/render/forward/mod.rs b/src/render/forward/mod.rs index cd6a843b13..f7c812909d 100644 --- a/src/render/forward/mod.rs +++ b/src/render/forward/mod.rs @@ -1,8 +1,8 @@ -use crate::{render::*, asset::*, render::mesh::*, math}; +use crate::{render::*, asset::*, render::mesh::*, vertex::Vertex}; use legion::prelude::*; use std::mem; use zerocopy::{AsBytes, FromBytes}; -use wgpu::{Buffer, CommandEncoder, Device, VertexBufferDescriptor, SwapChainDescriptor, SwapChainOutput}; +use wgpu::{Device, SwapChainDescriptor, SwapChainOutput}; #[repr(C)] #[derive(Clone, Copy, AsBytes, FromBytes)] @@ -11,19 +11,51 @@ pub struct ForwardUniforms { pub num_lights: [u32; 4], } -pub struct ForwardPass { - pub pipeline: wgpu::RenderPipeline, - pub bind_group: wgpu::BindGroup, - pub forward_uniform_buffer: wgpu::Buffer, - pub depth_texture: wgpu::TextureView, +pub struct ForwardPipelineNew { + pub pipeline: Option, + pub depth_format: wgpu::TextureFormat, + pub local_bind_group: Option, } +pub struct ForwardPass { + pub depth_format: wgpu::TextureFormat, +} + +impl ForwardPass { + pub fn new() -> Self { + ForwardPass { + depth_format: wgpu::TextureFormat::Depth32Float + } + } + fn get_depth_texture(&self, device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { + let texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: swap_chain_descriptor.width, + height: swap_chain_descriptor.height, + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: self.depth_format, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); + + texture.create_default_view() + } +} + +const DEPTH_TEXTURE_NAME: &str = "forward_depth"; + impl Pass for ForwardPass { - fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, _: &RenderResources) { - let mut mesh_query = - <(Read, Read>)>::query() - .filter(!component::()); - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + fn initialize(&self, render_graph: &mut RenderGraphData) { + let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); + render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); + } + fn begin<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> wgpu::RenderPass<'a> { + let depth_texture = render_graph.get_texture(DEPTH_TEXTURE_NAME); + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { attachment: &frame.view, resolve_target: None, @@ -37,7 +69,7 @@ impl Pass for ForwardPass { }, }], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &self.depth_texture, + attachment: depth_texture.unwrap(), depth_load_op: wgpu::LoadOp::Clear, depth_store_op: wgpu::StoreOp::Store, stencil_load_op: wgpu::LoadOp::Clear, @@ -45,50 +77,26 @@ impl Pass for ForwardPass { clear_depth: 1.0, clear_stencil: 0, }), - }); - pass.set_pipeline(&self.pipeline); - pass.set_bind_group(0, &self.bind_group, &[]); - - let mut mesh_storage = world.resources.get_mut::>().unwrap(); - let mut last_mesh_id = None; - for (entity, mesh) in mesh_query.iter_immutable(world) { - let current_mesh_id = *mesh.id.read().unwrap(); - - let mut should_load_mesh = last_mesh_id == None; - if let Some(last) = last_mesh_id { - should_load_mesh = last != current_mesh_id; - } - - if should_load_mesh { - if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - mesh_asset.setup_buffers(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)]); - }; - } - - if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); - pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); - }; - - last_mesh_id = Some(current_mesh_id); - } + }) } - - fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor) { - self.depth_texture = Self::get_depth_texture(device, frame); - } - - fn get_camera_uniform_buffer(&self) -> Option<&Buffer> { - Some(&self.forward_uniform_buffer) + fn resize(&self, render_graph: &mut RenderGraphData) { + let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); + render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); } } -impl ForwardPass { - pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - - pub fn new(device: &Device, world: &World, render_resources: &RenderResources, vertex_buffer_descriptor: VertexBufferDescriptor, swap_chain_descriptor: &SwapChainDescriptor) -> Self { +impl ForwardPipelineNew { + pub fn new() -> Self { + ForwardPipelineNew { + pipeline: None, + local_bind_group: None, + depth_format: wgpu::TextureFormat::Depth32Float + } + } +} + +impl PipelineNew for ForwardPipelineNew { + fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { let vs_bytes = shader::load_glsl( include_str!("forward.vert"), shader::ShaderStage::Vertex, @@ -99,7 +107,7 @@ impl ForwardPass { ); let bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + render_graph.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[ wgpu::BindGroupLayoutBinding { binding: 0, // global @@ -114,47 +122,56 @@ impl ForwardPass { ], }); - let light_count = >::query().iter_immutable(world).count(); - let forward_uniforms = ForwardUniforms { - proj: math::Mat4::identity().to_cols_array_2d(), - num_lights: [light_count as u32, 0, 0, 0], + self.local_bind_group = Some({ + + let forward_uniform_buffer = render_graph.get_uniform_buffer(render_resources::FORWARD_UNIFORM_BUFFER_NAME).unwrap(); + let light_uniform_buffer = render_graph.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME).unwrap(); + + // Create bind group + render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: forward_uniform_buffer.get_binding_resource(), + }, + wgpu::Binding { + binding: 1, + resource: light_uniform_buffer.get_binding_resource(), + } + ], + }) + }); + + // TODO: fix this inline "local" + let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); + + let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout, local_bind_group_layout], + }); + + let vertex_size = mem::size_of::(); + let vertex_buffer_descriptor = wgpu::VertexBufferDescriptor { + stride: vertex_size as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[ + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float4, + offset: 0, + shader_location: 0, + }, + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Float4, + offset: 4 * 4, + shader_location: 1, + }, + ], }; - let uniform_size = mem::size_of::() as wgpu::BufferAddress; - let forward_uniform_buffer = device.create_buffer_with_data( - forward_uniforms.as_bytes(), - wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - ); + let vs_module = render_graph.device.create_shader_module(&vs_bytes); + let fs_module = render_graph.device.create_shader_module(&fs_bytes); - // Create bind group - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - bindings: &[ - wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &forward_uniform_buffer, - range: 0 .. uniform_size, - }, - }, - wgpu::Binding { - binding: 1, - resource: wgpu::BindingResource::Buffer { - buffer: &render_resources.light_uniform_buffer.buffer, - range: 0 .. render_resources.light_uniform_buffer.size, - }, - } - ], - }); - - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout, &render_resources.local_bind_group_layout], - }); - - let vs_module = device.create_shader_module(&vs_bytes); - let fs_module = device.create_shader_module(&fs_bytes); - - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + self.pipeline = Some(render_graph.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vs_module, @@ -174,14 +191,14 @@ impl ForwardPass { primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[ wgpu::ColorStateDescriptor { - format: swap_chain_descriptor.format, + format: render_graph.swap_chain_descriptor.format, color_blend: wgpu::BlendDescriptor::REPLACE, alpha_blend: wgpu::BlendDescriptor::REPLACE, write_mask: wgpu::ColorWrite::ALL, }, ], depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { - format: Self::DEPTH_FORMAT, + format: self.depth_format, depth_write_enabled: true, depth_compare: wgpu::CompareFunction::Less, stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, @@ -194,32 +211,44 @@ impl ForwardPass { sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, - }); + })); + } + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World) { + pass.set_bind_group(0, self.local_bind_group.as_ref().unwrap(), &[]); - ForwardPass { - pipeline, - bind_group, - forward_uniform_buffer, - depth_texture: Self::get_depth_texture(device, swap_chain_descriptor) + let mut mesh_storage = world.resources.get_mut::>().unwrap(); + let mut last_mesh_id = None; + let mut mesh_query = + <(Read, Read>)>::query() + .filter(!component::()); + for (entity, mesh) in mesh_query.iter_immutable(world) { + let current_mesh_id = *mesh.id.read().unwrap(); + + let mut should_load_mesh = last_mesh_id == None; + if let Some(last) = last_mesh_id { + should_load_mesh = last != current_mesh_id; + } + + if should_load_mesh { + if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { + 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)]); + }; + } + + if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { + pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); + pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); + }; + + last_mesh_id = Some(current_mesh_id); } } - - fn get_depth_texture(device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { - let texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: swap_chain_descriptor.width, - height: swap_chain_descriptor.height, - depth: 1, - }, - array_layer_count: 1, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }); + fn resize(&mut self, render_graph: &RenderGraphData) { - texture.create_default_view() } -} - + fn get_pipeline(&self) -> &wgpu::RenderPipeline { + self.pipeline.as_ref().unwrap() + } +} \ No newline at end of file diff --git a/src/render/forward_instanced/mod.rs b/src/render/forward_instanced/mod.rs index a6fdba6172..9b44045db9 100644 --- a/src/render/forward_instanced/mod.rs +++ b/src/render/forward_instanced/mod.rs @@ -19,7 +19,7 @@ pub struct ForwardInstancedPass { pub instance_buffer_infos: Vec, } -impl Pass for ForwardInstancedPass { +impl Pipeline for ForwardInstancedPass { fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, _: &RenderResources) { self.instance_buffer_infos = ForwardInstancedPass::create_instance_buffer_infos(device, world); let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -245,6 +245,38 @@ impl ForwardInstancedPass { instance_buffer_infos } + + fn create_instance_buffer_infos_direct(device: &Device, world: &World) -> Vec { + let mut entities = <(Read, Read, Read>, Read)>::query(); + let entities_count = entities.iter_immutable(world).count(); + + let mut last_mesh_id = None; + let mut data = Vec::with_capacity(entities_count); + for (material, transform, mesh, _) in entities.iter_immutable(world) + { + + last_mesh_id = Some(*mesh.id.read().unwrap()); + let (_, _, translation) = transform.0.to_scale_rotation_translation(); + + data.push(SimpleMaterialUniforms { + position: translation.into(), + color: material.color.into(), + }); + } + + let buffer = device + .create_buffer_with_data(data.as_bytes(), wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX); + + + let mut instance_buffer_infos = Vec::new(); + instance_buffer_infos.push(InstanceBufferInfo { + mesh_id: last_mesh_id.unwrap(), + buffer: buffer, + instance_count: entities_count, + }); + + instance_buffer_infos + } fn get_depth_texture(device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { let texture = device.create_texture(&wgpu::TextureDescriptor { diff --git a/src/render/forward_shadow/mod.rs b/src/render/forward_shadow/mod.rs index 20a658257c..36451d3121 100644 --- a/src/render/forward_shadow/mod.rs +++ b/src/render/forward_shadow/mod.rs @@ -18,7 +18,7 @@ pub struct ForwardShadowPass { pub depth_texture: wgpu::TextureView, } -impl Pass for ForwardShadowPass { +impl Pipeline for ForwardShadowPass { fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, _: &RenderResources) { let mut mesh_query = <(Read, Read>)>::query(); let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { diff --git a/src/render/mod.rs b/src/render/mod.rs index 82709a2f24..ead6e6210d 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,21 +1,23 @@ pub mod camera; pub mod shader; pub mod mesh; +pub mod render_resources; mod forward; mod forward_shadow; mod forward_instanced; mod shadow; mod light; +mod pipeline; mod pass; mod material; -mod render_resources; -pub use forward::{ForwardPass, ForwardUniforms}; +pub use forward::{ForwardUniforms, ForwardPipelineNew, ForwardPass}; pub use forward_shadow::{ForwardShadowPass}; pub use forward_instanced::ForwardInstancedPass; pub use shadow::ShadowPass; pub use light::*; pub use shader::*; +pub use pipeline::*; pub use pass::*; pub use material::*; pub use mesh::*; @@ -25,4 +27,13 @@ pub use render_resources::RenderResources; pub struct UniformBuffer { pub buffer: wgpu::Buffer, pub size: u64, +} + +impl UniformBuffer { + pub fn get_binding_resource<'a>(&'a self) -> wgpu::BindingResource<'a> { + wgpu::BindingResource::Buffer { + buffer: &self.buffer, + range: 0 .. self.size, + } + } } \ No newline at end of file diff --git a/src/render/pass.rs b/src/render/pass.rs index 139796c543..17d29b5efb 100644 --- a/src/render/pass.rs +++ b/src/render/pass.rs @@ -1,9 +1,158 @@ +use crate::render::{PipelineNew, UniformBuffer}; +use std::collections::HashMap; use legion::world::World; -use wgpu::{Buffer, CommandEncoder, Device, SwapChainDescriptor, SwapChainOutput}; -use crate::render::RenderResources; pub trait Pass { - fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, render_resources: &RenderResources); - fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor); - fn get_camera_uniform_buffer(&self) -> Option<&Buffer>; + fn initialize(&self, render_graph: &mut RenderGraphData); + fn begin<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> wgpu::RenderPass<'a>; + fn resize(&self, render_graph: &mut RenderGraphData); +} + +pub trait RenderResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World); + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); +} + +pub struct RenderGraph { + pub data: RenderGraphData, + passes: HashMap>, + pipelines: HashMap>, + render_resource_managers: Vec>, + pub swap_chain: wgpu::SwapChain, // TODO: this is weird +} + +pub struct RenderGraphData { + pub swap_chain_descriptor: wgpu::SwapChainDescriptor, + pub device: wgpu::Device, + pub queue: wgpu::Queue, + pub surface: wgpu::Surface, + textures: HashMap, + uniform_buffers: HashMap, + bind_group_layouts: HashMap, +} +impl RenderGraphData { + pub fn new(device: wgpu::Device, swap_chain_descriptor: wgpu::SwapChainDescriptor, queue: wgpu::Queue, surface: wgpu::Surface) -> Self { + RenderGraphData { + textures: HashMap::new(), + uniform_buffers: HashMap::new(), + bind_group_layouts: HashMap::new(), + device, + swap_chain_descriptor, + queue, + surface, + } + } + + pub fn set_uniform_buffer(&mut self, name: &str, uniform_buffer: UniformBuffer) { + self.uniform_buffers.insert(name.to_string(), uniform_buffer); + } + + pub fn get_uniform_buffer(&self, name: &str) -> Option<&UniformBuffer> { + self.uniform_buffers.get(name) + } + + pub fn set_bind_group_layout(&mut self, name: &str, bind_group_layout: wgpu::BindGroupLayout) { + self.bind_group_layouts.insert(name.to_string(), bind_group_layout); + } + + pub fn get_bind_group_layout(&self, name: &str) -> Option<&wgpu::BindGroupLayout> { + self.bind_group_layouts.get(name) + } + + pub fn set_texture(&mut self, name: &str, texture: wgpu::TextureView) { + self.textures.insert(name.to_string(), texture); + } + + pub fn get_texture(&self, name: &str) -> Option<&wgpu::TextureView> { + self.textures.get(name) + } +} + +impl RenderGraph { + pub fn new(device: wgpu::Device, swap_chain_descriptor: wgpu::SwapChainDescriptor, swap_chain: wgpu::SwapChain, queue: wgpu::Queue, surface: wgpu::Surface) -> Self { + RenderGraph { + passes: HashMap::new(), + pipelines: HashMap::new(), + swap_chain, + render_resource_managers: Vec::new(), + data: RenderGraphData::new(device, swap_chain_descriptor, queue, surface), + } + } + + pub fn initialize(&mut self, world: &mut World) { + for render_resource_manager in self.render_resource_managers.iter_mut() { + render_resource_manager.initialize(&mut self.data, world); + } + + for pass in self.passes.values_mut() { + pass.initialize(&mut self.data); + } + + for pipeline in self.pipelines.values_mut() { + pipeline.initialize(&mut self.data, world); + } + } + + pub fn render(&mut self, world: &mut World) { + let frame = self.swap_chain + .get_next_texture() + .expect("Timeout when acquiring next swap chain texture"); + + let mut encoder = + self.data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + + for render_resource_manager in self.render_resource_managers.iter_mut() { + render_resource_manager.update(&mut self.data, &mut encoder, world); + } + + for pass in self.passes.values_mut() { + let mut render_pass = pass.begin(&mut self.data, &mut encoder, &frame); + // TODO: assign pipelines to specific passes + for pipeline in self.pipelines.values_mut() { + render_pass.set_pipeline(pipeline.get_pipeline()); + pipeline.render(&mut self.data, &mut render_pass, &frame, world); + } + } + + let command_buffer = encoder.finish(); + self.data.queue.submit(&[command_buffer]); + } + + pub fn resize(&mut self, width: u32, height: u32, world: &mut World) { + self.data.swap_chain_descriptor.width = width; + self.data.swap_chain_descriptor.height = height; + self.swap_chain = self.data.device.create_swap_chain(&self.data.surface, &self.data.swap_chain_descriptor); + let mut encoder = + self.data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + + for render_resource_manager in self.render_resource_managers.iter_mut() { + render_resource_manager.resize(&mut self.data, &mut encoder, world); + } + + let command_buffer = encoder.finish(); + + for pass in self.passes.values_mut() { + pass.resize(&mut self.data); + } + + for pipeline in self.pipelines.values_mut() { + pipeline.resize(&mut self.data); + } + + self.data.queue.submit(&[command_buffer]); + + } + + pub fn add_render_resource_manager(&mut self, render_resource_manager: Box) { + self.render_resource_managers.push(render_resource_manager); + } + + pub fn set_pipeline(&mut self, name: &str, pipeline: Box) { + self.pipelines.insert(name.to_string(), pipeline); + } + + pub fn set_pass(&mut self, name: &str, pass: Box) { + self.passes.insert(name.to_string(), pass); + } } \ No newline at end of file diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs new file mode 100644 index 0000000000..26837e7869 --- /dev/null +++ b/src/render/pipeline.rs @@ -0,0 +1,17 @@ +use legion::world::World; +use wgpu::{Buffer, CommandEncoder, Device, SwapChainDescriptor, SwapChainOutput}; +use crate::render::{RenderResources, RenderGraphData}; + + +pub trait Pipeline { + fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, render_resources: &RenderResources); + fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor); + fn get_camera_uniform_buffer(&self) -> Option<&Buffer>; +} + +pub trait PipelineNew { + fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World); + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World); + fn resize(&mut self, render_graph: &RenderGraphData); + fn get_pipeline(&self) -> &wgpu::RenderPipeline; +} \ No newline at end of file diff --git a/src/render/render_resources.rs b/src/render/render_resources.rs index 4dc9d410f1..a23dc26dbb 100644 --- a/src/render/render_resources.rs +++ b/src/render/render_resources.rs @@ -1,4 +1,4 @@ -use crate::{render::*, LocalToWorld, Translation}; +use crate::{render::*, LocalToWorld, Translation, math}; use legion::prelude::*; use std::sync::Arc; @@ -8,6 +8,178 @@ use zerocopy::AsBytes; use wgpu::{BindGroupLayout, CommandEncoder, Device}; +pub const LIGHT_UNIFORM_BUFFER_NAME: &str = "lights"; +pub const FORWARD_UNIFORM_BUFFER_NAME: &str = "forward"; +pub struct LightResourceManager { + pub lights_are_dirty: bool, + pub max_lights: usize, +} + +impl LightResourceManager { + pub fn new(max_lights: usize) -> Self { + LightResourceManager { + lights_are_dirty: true, + max_lights: max_lights, + } + } +} + +impl RenderResourceManager for LightResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { + let light_uniform_size = + (self.max_lights * mem::size_of::()) as wgpu::BufferAddress; + + let light_uniform_buffer = UniformBuffer { + buffer: render_graph.device.create_buffer(&wgpu::BufferDescriptor { + size: light_uniform_size, + usage: wgpu::BufferUsage::UNIFORM + | wgpu::BufferUsage::COPY_SRC + | wgpu::BufferUsage::COPY_DST, + }), + size: light_uniform_size, + }; + + render_graph.set_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME, light_uniform_buffer); + } + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + if self.lights_are_dirty { + let mut light_query = <(Read, Read, Read)>::query(); + let light_count = light_query.iter(world).count(); + + self.lights_are_dirty = false; + let size = mem::size_of::(); + let total_size = size * light_count; + let temp_buf_data = + render_graph.device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); + for ((light, local_to_world, translation), slot) in light_query + .iter(world) + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + slot.copy_from_slice(LightRaw::from(&light, &local_to_world.0, &translation).as_bytes()); + } + + let light_uniform_buffer = render_graph.get_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME).unwrap(); + encoder.copy_buffer_to_buffer( + &temp_buf_data.finish(), + 0, + &light_uniform_buffer.buffer, + 0, + total_size as wgpu::BufferAddress, + ); + + } + } + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { } +} + +pub struct CameraResourceManager; + +impl RenderResourceManager for CameraResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { + let light_count = >::query().iter_immutable(world).count(); + let forward_uniforms = ForwardUniforms { + proj: math::Mat4::identity().to_cols_array_2d(), + num_lights: [light_count as u32, 0, 0, 0], + }; + + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let buffer = render_graph.device.create_buffer_with_data( + forward_uniforms.as_bytes(), + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ); + + let uniform_buffer = UniformBuffer { + buffer: buffer, + size: uniform_size, + }; + render_graph.set_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME, uniform_buffer); + } + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + + } + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + for (mut camera, local_to_world) in <(Write, Read)>::query().iter(world) { + camera.update(render_graph.swap_chain_descriptor.width, render_graph.swap_chain_descriptor.height); + let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); + let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64; + let temp_camera_buffer = + render_graph.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC); + let forward_uniform_buffer = render_graph.get_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME).unwrap(); + encoder.copy_buffer_to_buffer(&temp_camera_buffer, 0, &forward_uniform_buffer.buffer, 0, matrix_size); + } + } +} + +pub struct MaterialResourceManager; + +impl RenderResourceManager for MaterialResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { + + } + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + let mut entities = <(Write, Read)>::query() + .filter(!component::()); + let entities_count = entities.iter(world).count(); + let size = mem::size_of::(); + let temp_buf_data = render_graph.device + .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); + + for ((material, transform), slot) in entities.iter(world) + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + slot.copy_from_slice( + MaterialUniforms { + model: transform.0.to_cols_array_2d(), + color: material.color.into(), + } + .as_bytes(), + ); + } + + // TODO: dont use inline local + let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); + + for mut material in >::query().filter(!component::()).iter(world) { + if let None = material.bind_group { + let material_uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_buf = render_graph.device.create_buffer(&wgpu::BufferDescriptor { + size: material_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + let bind_group = render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: local_bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0 .. material_uniform_size, + }, + }], + }); + + material.bind_group = Some(bind_group); + material.uniform_buf = Some(uniform_buf); + } + } + + let temp_buf = temp_buf_data.finish(); + for (i, (material, _)) in entities.iter(world).enumerate() { + encoder.copy_buffer_to_buffer( + &temp_buf, + (i * size) as wgpu::BufferAddress, + material.uniform_buf.as_ref().unwrap(), + 0, + size as wgpu::BufferAddress, + ); + } + } + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + + } + +} + pub struct RenderResources { pub local_bind_group_layout: Rc, pub light_uniform_buffer: Arc, diff --git a/src/render/shadow/mod.rs b/src/render/shadow/mod.rs index d0f4f9f8d4..2755bdb8d4 100644 --- a/src/render/shadow/mod.rs +++ b/src/render/shadow/mod.rs @@ -18,7 +18,7 @@ pub struct ShadowUniforms { pub proj: [[f32; 4]; 4], } -impl Pass for ShadowPass { +impl Pipeline for ShadowPass { fn render(&mut self, device: &Device, _: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, render_resources: &RenderResources) { let mut light_query = <(Read, Read, Read)>::query(); let mut mesh_query =