diff --git a/src/render/render_graph_2/draw_target.rs b/src/render/render_graph_2/draw_target.rs index f2d08a7a0b..6c877c90ab 100644 --- a/src/render/render_graph_2/draw_target.rs +++ b/src/render/render_graph_2/draw_target.rs @@ -40,7 +40,7 @@ pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) { } if let Some(mesh_asset) = mesh_storage.get(mesh.id) { - // pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]); + render_pass.setup_bind_groups(); render_pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1); }; diff --git a/src/render/render_graph_2/pipeline_layout.rs b/src/render/render_graph_2/pipeline_layout.rs index 2456315470..31e07c9135 100644 --- a/src/render/render_graph_2/pipeline_layout.rs +++ b/src/render/render_graph_2/pipeline_layout.rs @@ -10,16 +10,19 @@ impl PipelineLayout { } } +#[derive(Hash)] pub struct BindGroup { pub bindings: Vec } +#[derive(Hash)] pub struct Binding { pub name: String, pub bind_type: BindType, // TODO: ADD SHADER STAGE VISIBILITY } +#[derive(Hash)] pub enum BindType { Uniform { dynamic: bool, @@ -39,11 +42,13 @@ pub enum BindType { }, } +#[derive(Hash)] pub struct UniformProperty { pub name: String, pub property_type: UniformPropertyType, } +#[derive(Hash)] pub enum UniformPropertyType { // TODO: Add all types here Int, @@ -56,7 +61,7 @@ pub enum UniformPropertyType { Array(Box, usize), } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Hash)] pub enum TextureDimension { D1, D2, diff --git a/src/render/render_graph_2/renderer.rs b/src/render/render_graph_2/renderer.rs index ddd8cbb421..c30bba7932 100644 --- a/src/render/render_graph_2/renderer.rs +++ b/src/render/render_graph_2/renderer.rs @@ -1,4 +1,4 @@ -use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, BufferInfo, PipelineDescriptor}}; +use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor, BindGroup}}; use std::ops::Range; pub trait Renderer { @@ -7,8 +7,9 @@ pub trait Renderer { fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World); // TODO: swap out wgpu::BufferUsage for custom type fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage); + fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64; fn remove_buffer(&mut self, name: &str); - fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo>; + fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>; } pub trait RenderPass { @@ -17,4 +18,5 @@ pub trait RenderPass { fn set_index_buffer(&mut self, name: &str, offset: u64); fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64); fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range); + fn setup_bind_groups(&mut self); } \ No newline at end of file diff --git a/src/render/render_graph_2/resource.rs b/src/render/render_graph_2/resource.rs index 0ac029f17d..171abdb7c2 100644 --- a/src/render/render_graph_2/resource.rs +++ b/src/render/render_graph_2/resource.rs @@ -1,7 +1,7 @@ -// pub type ResourceId = u64; - -pub struct BufferInfo { - pub size: u64, - pub buffer_usage: wgpu::BufferUsage, - // pub layout: Option< +pub enum ResourceInfo { + Buffer { + size: u64, + buffer_usage: wgpu::BufferUsage, + // pub layout: Option< + }, } \ No newline at end of file diff --git a/src/render/render_graph_2/resource_provider.rs b/src/render/render_graph_2/resource_provider.rs index 09fc8839db..995f9d65fd 100644 --- a/src/render/render_graph_2/resource_provider.rs +++ b/src/render/render_graph_2/resource_provider.rs @@ -7,6 +7,7 @@ use legion::prelude::*; use zerocopy::AsBytes; pub trait ResourceProvider { + fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World); fn update(&self, renderer: &mut dyn Renderer, world: &mut World); fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32); } @@ -14,6 +15,10 @@ pub trait ResourceProvider { pub struct CameraResourceProvider; impl ResourceProvider for CameraResourceProvider { + fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World) { + // TODO: create real buffer here + } + fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {} fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) { for (mut camera, local_to_world, _) in @@ -22,7 +27,7 @@ impl ResourceProvider for CameraResourceProvider { camera.update(width, height); let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); - // TODO: use staging buffer? + // TODO: use staging buffer here renderer.create_buffer_with_data( resource_name::uniform::CAMERA, camera_matrix.as_bytes(), diff --git a/src/render/render_graph_2/wgpu_renderer.rs b/src/render/render_graph_2/wgpu_renderer.rs index 794fc5c80d..23429d7a0f 100644 --- a/src/render/render_graph_2/wgpu_renderer.rs +++ b/src/render/render_graph_2/wgpu_renderer.rs @@ -1,12 +1,16 @@ use crate::{ legion::prelude::*, render::render_graph_2::{ - resource_name, BindType, BufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, + resource_name, BindGroup, BindType, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor, - RenderPassDepthStencilAttachmentDescriptor, Renderer, TextureDimension, + RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDimension, }, }; -use std::{collections::HashMap, ops::Deref}; +use std::{ + collections::{hash_map::DefaultHasher, HashMap}, + hash::{Hash, Hasher}, + ops::Deref, +}; pub struct WgpuRenderer { pub device: wgpu::Device, @@ -14,8 +18,11 @@ pub struct WgpuRenderer { pub surface: Option, pub swap_chain_descriptor: wgpu::SwapChainDescriptor, pub render_pipelines: HashMap, - pub buffers: HashMap>, + pub buffers: HashMap, pub textures: HashMap, + pub resource_info: HashMap, + pub bind_groups: HashMap, + pub bind_group_layouts: HashMap, } impl WgpuRenderer { @@ -51,11 +58,15 @@ impl WgpuRenderer { render_pipelines: HashMap::new(), buffers: HashMap::new(), textures: HashMap::new(), + resource_info: HashMap::new(), + bind_groups: HashMap::new(), + bind_group_layouts: HashMap::new(), } } pub fn create_render_pipeline( pipeline_descriptor: &PipelineDescriptor, + bind_group_layouts: &mut HashMap, device: &wgpu::Device, ) -> wgpu::RenderPipeline { let vertex_shader_module = pipeline_descriptor @@ -67,11 +78,12 @@ impl WgpuRenderer { None => None, }; - let bind_group_layouts = pipeline_descriptor - .pipeline_layout - .bind_groups - .iter() - .map(|bind_group| { + // setup new bind group layouts + for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() { + let mut hasher = DefaultHasher::new(); + bind_group.hash(&mut hasher); + let bind_group_id = hasher.finish(); + if let None = bind_group_layouts.get(&bind_group_id) { let bind_group_layout_binding = bind_group .bindings .iter() @@ -82,17 +94,32 @@ impl WgpuRenderer { ty: (&binding.bind_type).into(), }) .collect::>(); - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: bind_group_layout_binding.as_slice(), - }) + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: bind_group_layout_binding.as_slice(), + }); + + bind_group_layouts.insert(bind_group_id, bind_group_layout); + } + } + + // collect bind group layout references + let bind_group_layouts = pipeline_descriptor + .pipeline_layout + .bind_groups + .iter() + .map(|bind_group| { + let mut hasher = DefaultHasher::new(); + bind_group.hash(&mut hasher); + let bind_group_id = hasher.finish(); + + bind_group_layouts.get(&bind_group_id).unwrap() }) - .collect::>(); + .collect::>(); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: bind_group_layouts - .iter() - .collect::>() - .as_slice(), + bind_group_layouts: bind_group_layouts.as_slice() }); let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { @@ -198,6 +225,10 @@ impl WgpuRenderer { stencil_store_op: depth_stencil_attachment_descriptor.stencil_store_op, } } + + fn add_resource_info(&mut self, name: &str, resource_info: ResourceInfo) { + self.resource_info.insert(name.to_string(), resource_info); + } } impl Renderer for WgpuRenderer { @@ -244,6 +275,7 @@ impl Renderer for WgpuRenderer { if let None = self.render_pipelines.get(pass_pipeline) { let render_pipeline = WgpuRenderer::create_render_pipeline( pipeline_descriptor, + &mut self.bind_group_layouts, &self.device, ); self.render_pipelines @@ -275,25 +307,74 @@ impl Renderer for WgpuRenderer { buffer_usage: wgpu::BufferUsage, ) { let buffer = self.device.create_buffer_with_data(data, buffer_usage); - self.buffers.insert( - name.to_string(), - Buffer { - buffer, - buffer_info: BufferInfo { - buffer_usage, - size: data.len() as u64, - }, + self.add_resource_info( + name, + ResourceInfo::Buffer { + buffer_usage, + size: data.len() as u64, }, ); + + self.buffers.insert(name.to_string(), buffer); } - fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo> { - self.buffers.get(name).map(|b| &b.buffer_info) + fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo> { + self.resource_info.get(name) } fn remove_buffer(&mut self, name: &str) { self.buffers.remove(name); } + + fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 { + // TODO: cache hash result in bind_group? + let mut hasher = DefaultHasher::new(); + bind_group.hash(&mut hasher); + let bind_group_id = hasher.finish(); + + + // TODO: setup bind group layout + if let None = self.bind_groups.get(&bind_group_id) { + let bindings = bind_group + .bindings + .iter() + .enumerate() + .map(|(i, b)| wgpu::Binding { + binding: i as u32, + resource: match &b.bind_type { + BindType::Uniform { + dynamic, + properties, + } => { + let resource_info = self.resource_info.get(&b.name).unwrap(); + if let ResourceInfo::Buffer { size, buffer_usage } = resource_info { + let buffer = self.buffers.get(&b.name).unwrap(); + wgpu::BindingResource::Buffer { + buffer: buffer, + range: 0..*size, + } + } else { + panic!("expected a Buffer resource"); + } + } + _ => panic!("unsupported bind type"), + }, + }) + .collect::>(); + + let bind_group_layout = self.bind_group_layouts.get(&bind_group_id).unwrap(); + let bind_group_descriptor = wgpu::BindGroupDescriptor { + layout: bind_group_layout, + bindings: bindings.as_slice(), + }; + + let bind_group = self.device.create_bind_group(&bind_group_descriptor); + // let bind + self.bind_groups.insert(bind_group_id, bind_group); + } + + bind_group_id + } } pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { @@ -302,7 +383,7 @@ pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { pub renderer: &'d mut WgpuRenderer, } -impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> { +impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { fn get_renderer(&mut self) -> &mut dyn Renderer { self.renderer } @@ -313,16 +394,41 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> { fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) { let buffer = self.renderer.buffers.get(name).unwrap(); - self.render_pass.set_vertex_buffers(start_slot, &[(&buffer.buffer, offset)]); + self.render_pass + .set_vertex_buffers(start_slot, &[(&buffer, offset)]); } fn set_index_buffer(&mut self, name: &str, offset: u64) { let buffer = self.renderer.buffers.get(name).unwrap(); - self.render_pass.set_index_buffer(&buffer.buffer, offset); + self.render_pass.set_index_buffer(&buffer, offset); } - fn draw_indexed(&mut self, indices: core::ops::Range, base_vertex: i32, instances: core::ops::Range) { - self.render_pass.draw_indexed(indices, base_vertex, instances); + fn draw_indexed( + &mut self, + indices: core::ops::Range, + base_vertex: i32, + instances: core::ops::Range, + ) { + self.render_pass + .draw_indexed(indices, base_vertex, instances); + } + + // TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc); + fn setup_bind_groups(&mut self) { + for (i, bind_group) in self + .pipeline_descriptor + .pipeline_layout + .bind_groups + .iter() + .enumerate() + { + let id = self.renderer.setup_bind_group(bind_group); + self.render_pass.set_bind_group( + i as u32, + self.renderer.bind_groups.get(&id).unwrap(), + &[], + ); + } } } @@ -364,8 +470,3 @@ impl From<&BindType> for wgpu::BindingType { } } } - -pub struct Buffer { - pub buffer: T, - pub buffer_info: BufferInfo, -}