diff --git a/examples/shader_material.rs b/examples/shader_material.rs index bbe0644e0c..ed8db284ec 100644 --- a/examples/shader_material.rs +++ b/examples/shader_material.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, asset, render::{Albedo, render_graph_2::{StandardMaterial, ShaderMaterials, ShaderMaterial, ShaderValue}}}; +use bevy::{prelude::*, asset, render::{Albedo, render_graph_2::{StandardMaterial, ShaderUniforms}}}; fn main() { AppBuilder::new().add_defaults_legacy().setup_world(setup).run(); @@ -11,53 +11,54 @@ fn setup(world: &mut World) { (texture_storage.add(texture)) }; - let mut color_shader_materials = ShaderMaterials::new(); + let mut color_shader_uniforms = ShaderUniforms::new(); let color_material = StandardMaterial { - albedo: Albedo::Color(math::vec4(1.0, 0.0, 0.0, 0.0)) + // albedo: Albedo::Color(math::vec4(1.0, 0.0, 0.0, 0.0)) + albedo: math::vec4(1.0, 0.0, 0.0, 0.0) }; - color_shader_materials.add(color_material.get_selector()); + // color_shader_materials.add(color_material.get_selector()); - world.insert( - (), - vec![( - color_shader_materials, - color_material, - )], - ); + // world.insert( + // (), + // vec![( + // color_shader_materials, + // color_material, + // )], + // ); - let mut texture_shader_materials = ShaderMaterials::new(); - let texture_material = StandardMaterial { - albedo: Albedo::Texture(texture_handle) - }; + // let mut texture_shader_materials = ShaderMaterials::new(); + // let texture_material = StandardMaterial { + // albedo: Albedo::Texture(texture_handle) + // }; - texture_shader_materials.add(texture_material.get_selector()); + // texture_shader_materials.add(texture_material.get_selector()); - world.insert( - (), - vec![( - texture_shader_materials, - texture_material, - )], - ); + // world.insert( + // (), + // vec![( + // texture_shader_materials, + // texture_material, + // )], + // ); - for (entity, materials) in >::query().iter_entities(world) { - println!("entity {}", entity); - for selector in materials.materials.iter() { - let shader_material = selector(entity, world).unwrap(); - print!(" "); - for property in shader_material.iter_properties() { - println!("property: {}", property); - print!(" "); - match shader_material.get_property(property) { - Some(a) => match a { - ShaderValue::Vec4(color) => println!("color {}", color), - ShaderValue::Texture(ref handle) => println!("tex {}", handle.id), - _ => println!("other"), - }, - None => println!("none"), - } - } - } - } + // for (entity, materials) in >::query().iter_entities(world) { + // println!("entity {}", entity); + // for selector in materials.materials.iter() { + // let shader_material = selector(entity, world).unwrap(); + // print!(" "); + // for property in shader_material.iter_properties() { + // println!("property: {}", property); + // print!(" "); + // match shader_material.get_property(property) { + // Some(a) => match a { + // ShaderValue::Vec4(color) => println!("color {}", color), + // ShaderValue::Texture(ref handle) => println!("tex {}", handle.id), + // _ => println!("other"), + // }, + // None => println!("none"), + // } + // } + // } + // } } diff --git a/src/render/passes/forward_flat/forward_flat.frag b/src/render/passes/forward_flat/forward_flat.frag deleted file mode 100644 index 07cb42f720..0000000000 --- a/src/render/passes/forward_flat/forward_flat.frag +++ /dev/null @@ -1,19 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 v_Normal; -layout(location = 1) in vec4 v_Position; - -layout(location = 0) out vec4 o_Target; - -layout(set = 0, binding = 0) uniform Camera { - mat4 ViewProj; -}; - -layout(set = 1, binding = 1) uniform Material { - vec4 Albedo; -}; - -void main() { - // multiply the light by material color - o_Target = Color; -} diff --git a/src/render/passes/forward_flat/forward_flat.vert b/src/render/passes/forward_flat/forward_flat.vert deleted file mode 100644 index 4da7ad5bb7..0000000000 --- a/src/render/passes/forward_flat/forward_flat.vert +++ /dev/null @@ -1,26 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 a_Pos; -layout(location = 1) in vec4 a_Normal; -layout(location = 2) in vec4 a_Uv; - -layout(location = 0) out vec3 v_Normal; -layout(location = 1) out vec4 v_Position; - -layout(set = 0, binding = 0) uniform Camera { - mat4 ViewProj; -}; - -layout(set = 1, binding = 0) uniform Object { - mat4 Model; -}; - -layout(set = 1, binding = 1) uniform Material { - vec4 Albedo; -}; - -void main() { - v_Normal = mat3(Model) * vec3(a_Normal.xyz); - v_Position = Model * vec4(a_Pos); - gl_Position = ViewProj * v_Position; -} diff --git a/src/render/passes/forward_flat/mod.rs b/src/render/passes/forward_flat/mod.rs deleted file mode 100644 index 54ea4c0144..0000000000 --- a/src/render/passes/forward_flat/mod.rs +++ /dev/null @@ -1,174 +0,0 @@ -use crate::{asset::*, render::*}; -use legion::prelude::*; -use wgpu::SwapChainOutput; - -pub struct ForwardFlatPipeline { - pub pipeline: Option, - pub depth_format: wgpu::TextureFormat, - pub bind_group: Option, - pub msaa_samples: usize, -} - -impl ForwardFlatPipeline { - pub fn new(msaa_samples: usize) -> Self { - ForwardFlatPipeline { - pipeline: None, - bind_group: None, - msaa_samples, - depth_format: wgpu::TextureFormat::Depth32Float, - } - } -} - -impl Pipeline for ForwardFlatPipeline { - fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) { - let vs_bytes = shader::glsl_to_spirv(include_str!("forward_flat.vert"), shader::ShaderStage::Vertex); - let fs_bytes = - shader::glsl_to_spirv(include_str!("forward_flat.frag"), shader::ShaderStage::Fragment); - - let bind_group_layout = - render_graph - .device - .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: &[ - wgpu::BindGroupLayoutBinding { - binding: 0, // global - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }, - wgpu::BindGroupLayoutBinding { - binding: 1, // lights - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }, - ], - }); - - self.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(), - }, - ], - }) - }); - - let material_bind_group_layout = render_graph - .get_bind_group_layout(render_resources::MATERIAL_BIND_GROUP_LAYOUT_NAME) - .unwrap(); - - let pipeline_layout = - render_graph - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout, material_bind_group_layout], - }); - - let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); - - let vs_module = render_graph.device.create_shader_module(&vs_bytes); - let fs_module = render_graph.device.create_shader_module(&fs_bytes); - - self.pipeline = Some(render_graph.device.create_render_pipeline( - &wgpu::RenderPipelineDescriptor { - layout: &pipeline_layout, - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", - }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", - }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { - front_face: wgpu::FrontFace::Ccw, - cull_mode: wgpu::CullMode::Back, - depth_bias: 0, - depth_bias_slope_scale: 0.0, - depth_bias_clamp: 0.0, - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - 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, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::Less, - stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_read_mask: 0, - stencil_write_mask: 0, - }), - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[vertex_buffer_descriptor], - sample_count: self.msaa_samples as u32, - sample_mask: !0, - alpha_to_coverage_enabled: false, - }, - )); - } - fn render( - &mut self, - render_graph: &RenderGraphData, - pass: &mut wgpu::RenderPass, - _: &SwapChainOutput, - world: &mut World, - ) { - pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]); - - let mut mesh_storage = world.resources.get_mut::>().unwrap(); - let mut last_mesh_id = None; - let mesh_query = - <(Read, Read>)>::query().filter(!component::()); - for (material, mesh) in mesh_query.iter(world) { - let current_mesh_id = mesh.id; - - 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) { - 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) { - pass.set_bind_group(1, material.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, _: &RenderGraphData) {} - - fn get_pipeline(&self) -> &wgpu::RenderPipeline { - self.pipeline.as_ref().unwrap() - } -} diff --git a/src/render/passes/mod.rs b/src/render/passes/mod.rs index a17484f918..f3266478d3 100644 --- a/src/render/passes/mod.rs +++ b/src/render/passes/mod.rs @@ -1,12 +1,10 @@ mod forward; -mod forward_flat; mod forward_instanced; mod forward_shadow; mod shadow; mod ui; pub use forward::{ForwardPass, ForwardPipeline, ForwardUniforms}; -pub use forward_flat::*; pub use forward_instanced::ForwardInstancedPipeline; pub use forward_shadow::ForwardShadowPassNew; pub use shadow::ShadowPass; diff --git a/src/render/render_graph_2/draw_target.rs b/src/render/render_graph_2/draw_target.rs index 888b185aa2..e9c05f926f 100644 --- a/src/render/render_graph_2/draw_target.rs +++ b/src/render/render_graph_2/draw_target.rs @@ -2,7 +2,7 @@ use crate::{ asset::{AssetStorage, Handle, Mesh}, legion::prelude::*, render::{ - render_graph_2::{ShaderMaterials, RenderPass}, + render_graph_2::{ShaderUniforms, RenderPass}, Instanced, }, }; @@ -14,7 +14,7 @@ pub fn mesh_draw_target(world: &World, _render_pass: &mut dyn RenderPass) { let mut mesh_storage = world.resources.get_mut::>().unwrap(); let mut last_mesh_id = None; let mesh_query = - <(Read, Read>)>::query().filter(!component::()); + <(Read, Read>)>::query().filter(!component::()); for (_material, mesh) in mesh_query.iter(world) { let current_mesh_id = mesh.id; diff --git a/src/render/render_graph_2/mod.rs b/src/render/render_graph_2/mod.rs index f8bc282afb..c225af28eb 100644 --- a/src/render/render_graph_2/mod.rs +++ b/src/render/render_graph_2/mod.rs @@ -1,6 +1,8 @@ pub mod pipelines; -pub mod resource; +pub mod resource_name; pub mod wgpu_renderer; +mod resource_provider; +mod resource; mod pipeline; mod pipeline_layout; mod pass; @@ -15,4 +17,6 @@ pub use pass::*; pub use renderer::*; pub use shader::*; pub use render_graph::*; -pub use draw_target::*; \ No newline at end of file +pub use draw_target::*; +pub use resource::*; +pub use resource_provider::*; \ No newline at end of file diff --git a/src/render/render_graph_2/pipeline_layout.rs b/src/render/render_graph_2/pipeline_layout.rs index 3c83556625..2456315470 100644 --- a/src/render/render_graph_2/pipeline_layout.rs +++ b/src/render/render_graph_2/pipeline_layout.rs @@ -22,7 +22,7 @@ pub struct Binding { pub enum BindType { Uniform { - // dynamic: bool, + dynamic: bool, properties: Vec }, Buffer { @@ -45,6 +45,7 @@ pub struct UniformProperty { } pub enum UniformPropertyType { + // TODO: Add all types here Int, Float, UVec4, @@ -55,6 +56,7 @@ pub enum UniformPropertyType { Array(Box, usize), } +#[derive(Copy, Clone)] pub enum TextureDimension { D1, D2, diff --git a/src/render/render_graph_2/pipelines/forward/forward.frag b/src/render/render_graph_2/pipelines/forward/forward.frag index 07cb42f720..6276a9a1b5 100644 --- a/src/render/render_graph_2/pipelines/forward/forward.frag +++ b/src/render/render_graph_2/pipelines/forward/forward.frag @@ -9,11 +9,11 @@ layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; }; -layout(set = 1, binding = 1) uniform Material { +layout(set = 1, binding = 1) uniform StandardMaterial { vec4 Albedo; }; void main() { // multiply the light by material color - o_Target = Color; + o_Target = Albedo; } diff --git a/src/render/render_graph_2/pipelines/forward/forward.vert b/src/render/render_graph_2/pipelines/forward/forward.vert index 4da7ad5bb7..95168e215d 100644 --- a/src/render/render_graph_2/pipelines/forward/forward.vert +++ b/src/render/render_graph_2/pipelines/forward/forward.vert @@ -15,7 +15,7 @@ layout(set = 1, binding = 0) uniform Object { mat4 Model; }; -layout(set = 1, binding = 1) uniform Material { +layout(set = 1, binding = 1) uniform StandardMaterial { vec4 Albedo; }; diff --git a/src/render/render_graph_2/pipelines/forward/mod.rs b/src/render/render_graph_2/pipelines/forward/mod.rs index b3115f3ca5..27310c77b3 100644 --- a/src/render/render_graph_2/pipelines/forward/mod.rs +++ b/src/render/render_graph_2/pipelines/forward/mod.rs @@ -2,7 +2,7 @@ use crate::render::{ Vertex, { render_graph_2::{ - mesh_draw_target, resource, pipeline_layout::*, PassDescriptor, PipelineDescriptor, + mesh_draw_target, resource_name, pipeline_layout::*, PassDescriptor, PipelineDescriptor, RenderGraphBuilder, RenderPassColorAttachmentDescriptor, }, shader::{Shader, ShaderStage}, @@ -27,54 +27,40 @@ impl ForwardPipelineBuilder for RenderGraphBuilder { .add_bind_group(BindGroup { bindings: vec![ Binding { - name: "Globals".to_string(), + name: "Camera".to_string(), bind_type: BindType::Uniform { + dynamic: false, properties: vec![ UniformProperty { name: "ViewProj".to_string(), property_type: UniformPropertyType::Mat4, }, - UniformProperty { - name: "NumLights".to_string(), - property_type: UniformPropertyType::UVec4, - }, ] } }, - Binding { - name: "Lights".to_string(), - bind_type: BindType::Uniform { - properties: vec![ - UniformProperty { - name: "SceneLights".to_string(), - property_type: UniformPropertyType::Array( - Box::new(UniformPropertyType::Struct( - vec![ - UniformPropertyType::Mat4, - UniformPropertyType::Vec4, - UniformPropertyType::Vec4, - ] - )), - 10 - ), - }, - ] - } - } ] }) .add_bind_group(BindGroup { bindings: vec![ Binding { - name: "Entity".to_string(), + name: "Object".to_string(), bind_type: BindType::Uniform { + dynamic: false, properties: vec![ UniformProperty { - name: "World".to_string(), + name: "Model".to_string(), property_type: UniformPropertyType::Mat4, }, + ] + } + }, + Binding { + name: "StandardMaterial".to_string(), + bind_type: BindType::Uniform { + dynamic: false, + properties: vec![ UniformProperty { - name: "Color".to_string(), + name: "Albedo".to_string(), property_type: UniformPropertyType::Vec4, }, ] @@ -121,7 +107,7 @@ impl ForwardPassBuilder for RenderGraphBuilder { "main", PassDescriptor { color_attachments: vec![RenderPassColorAttachmentDescriptor { - attachment: resource::texture::SWAP_CHAIN.to_string(), + attachment: resource_name::texture::SWAP_CHAIN.to_string(), resolve_target: None, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, diff --git a/src/render/render_graph_2/renderer.rs b/src/render/render_graph_2/renderer.rs index 538d09c0ca..7fd4ab8ae8 100644 --- a/src/render/render_graph_2/renderer.rs +++ b/src/render/render_graph_2/renderer.rs @@ -1,10 +1,12 @@ -use crate::{asset::Mesh, legion::prelude::*, render::render_graph_2::RenderGraph}; +use crate::{asset::Mesh, legion::prelude::*, render::render_graph_2::{RenderGraph, Buffer, ResourceId}}; pub trait Renderer { fn initialize(&mut self, world: &mut World); fn resize(&mut self, world: &mut World, width: u32, height: u32); fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World); - fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh); + // TODO: swap out wgpu::BufferUsage for custom type + fn create_buffer_with_data(&mut self, data: &[u8], buffer_usage: wgpu::BufferUsage) -> Buffer; + fn free_buffer(&mut self, id: ResourceId) -> Buffer; } pub trait RenderPass { diff --git a/src/render/render_graph_2/resource.rs b/src/render/render_graph_2/resource.rs new file mode 100644 index 0000000000..163cc2e144 --- /dev/null +++ b/src/render/render_graph_2/resource.rs @@ -0,0 +1,8 @@ +pub type ResourceId = u64; + +pub struct Buffer { + pub id: ResourceId, + pub size: u64, + pub buffer_usage: wgpu::BufferUsage, + // pub layout: Option< +} \ No newline at end of file diff --git a/src/render/render_graph_2/resource/mod.rs b/src/render/render_graph_2/resource/mod.rs deleted file mode 100644 index f41981d2ba..0000000000 --- a/src/render/render_graph_2/resource/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod texture; \ No newline at end of file diff --git a/src/render/render_graph_2/resource/texture.rs b/src/render/render_graph_2/resource/texture.rs deleted file mode 100644 index 9ec8fd3bdd..0000000000 --- a/src/render/render_graph_2/resource/texture.rs +++ /dev/null @@ -1 +0,0 @@ -pub const SWAP_CHAIN: &str = "swap_chain"; \ No newline at end of file diff --git a/src/render/render_graph_2/resource_name.rs b/src/render/render_graph_2/resource_name.rs new file mode 100644 index 0000000000..73e7fc6e43 --- /dev/null +++ b/src/render/render_graph_2/resource_name.rs @@ -0,0 +1,3 @@ +pub mod texture { + pub const SWAP_CHAIN: &str = "SwapChain"; +} \ 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 new file mode 100644 index 0000000000..95355d3b2d --- /dev/null +++ b/src/render/render_graph_2/resource_provider.rs @@ -0,0 +1,41 @@ +use crate::render::{render_graph_2::Renderer, ActiveCamera, Camera}; +use bevy_transform::prelude::LocalToWorld; +use legion::prelude::*; +use zerocopy::AsBytes; +use std::mem; + +trait ResourceProvider { + fn update(renderer: &mut dyn Renderer, world: &mut World); + fn resize(renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32); +} + +pub struct CameraResourceProvider; + +impl ResourceProvider for CameraResourceProvider { + fn update(renderer: &mut dyn Renderer, world: &mut World) {} + fn resize(renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) { + for (mut camera, local_to_world, _) in + <(Write, Read, Read)>::query().iter_mut(world) + { + camera.update(width, 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; + // TODO: use staging buffer? + let buffer = renderer.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::UNIFORM); + // 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, + // ); + } + } +} diff --git a/src/render/render_graph_2/shader.rs b/src/render/render_graph_2/shader.rs index 63e1da83e3..38c1e087a1 100644 --- a/src/render/render_graph_2/shader.rs +++ b/src/render/render_graph_2/shader.rs @@ -1,67 +1,134 @@ use crate::prelude::*; -use crate::{asset::Texture, legion::{prelude::{Entity, World}, borrow::{Ref, RefMap}}, render::Albedo}; +use crate::{ + asset::Texture, + legion::{ + borrow::{Ref, RefMap}, + prelude::{Entity, World}, + }, + render::render_graph_2::{UniformPropertyType, Binding, BindType}, + render::Albedo, + math::Vec4, +}; +use zerocopy::AsBytes; - -pub enum ShaderValue<'a> { - Int(u32), - Float(f32), - Vec4(Vec4), - Uniform(&'a [u8]), - Texture(&'a Handle), +pub type ShaderUniformSelector = fn(Entity, &World) -> Option>; +pub struct ShaderUniforms { + // used for distinguishing + pub uniform_selectors: Vec, } -pub type ShaderMaterialSelector = fn(Entity, &World) -> Option>; -pub struct ShaderMaterials { - // used for distinguishing - pub materials: Vec -} - -impl<'a> ShaderMaterials { - pub fn new() -> Self { - ShaderMaterials { - materials: Vec::new(), +impl<'a> ShaderUniforms { + pub fn new() -> Self { + ShaderUniforms { + uniform_selectors: Vec::new(), + } } - } - pub fn add(&mut self, selector: ShaderMaterialSelector) { - self.materials.push(selector); - } -} - -pub trait ShaderMaterial { - fn iter_properties(&self) -> std::slice::Iter<&'static str> ; - fn get_property(&self, name: &str) -> Option; - fn get_selector(&self) -> ShaderMaterialSelector; + pub fn add(&mut self, selector: ShaderUniformSelector) { + self.uniform_selectors.push(selector); + } } pub struct StandardMaterial { - pub albedo: Albedo + pub albedo: Vec4, } -// create this from a derive macro -const STANDARD_MATERIAL_PROPERTIES: &[&str] = &["albedo"]; -impl ShaderMaterial for StandardMaterial { - fn iter_properties(&self) -> std::slice::Iter<&'static str> { - STANDARD_MATERIAL_PROPERTIES.iter() +pub trait GetBytes { + fn get_bytes(&self) -> Vec; + fn get_bytes_ref(&self) -> Option<&[u8]>; +} + +impl GetBytes for dyn AsBytes { + fn get_bytes(&self) -> Vec { + self.as_bytes().into() } - fn get_property(&self, name: &str) -> Option { - match name { - "albedo" => Some(match self.albedo { - Albedo::Color(color) => ShaderValue::Vec4(color), - Albedo::Texture(ref texture) => ShaderValue::Texture(texture) - }), - _ => None, - } - } - fn get_selector(&self) -> ShaderMaterialSelector { - |entity, world| { - world.get_component::(entity).map( - |c: Ref| { - c.map_into(|s| { - s as &dyn ShaderMaterial - }) - } - ) - } + + fn get_bytes_ref(&self) -> Option<&[u8]> { + Some(self.as_bytes()) } } + +impl GetBytes for Vec4 { + fn get_bytes(&self) -> Vec { + let vec4_array: [f32; 4] = (*self).into(); + vec4_array.as_bytes().into() + } + + fn get_bytes_ref(&self) -> Option<&[u8]> { + None + } +} + +pub trait AsUniforms { + fn get_uniform_info(&self) -> &[UniformInfo]; + fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]]; + fn get_uniform_value(&self, index: usize) -> Vec; + // TODO: support zero-copy uniforms + // fn get_uniform_value_ref(&self, index: usize) -> &[u8]; +} + +// pub struct UniformInfo<'a> { +// pub name: &'a str, +// pub +// } + + +// create this from a derive macro +const STANDARD_MATERIAL_UNIFORM_INFO: &[UniformInfo] = &[ + UniformInfo { + name: "StandardMaterial", + bind_type: BindType::Uniform { + dynamic: false, + properties: Vec::new() + }, + } +]; + +// these are separate from BindType::Uniform{properties} because they need to be const +const STANDARD_MATERIAL_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]]; + +pub struct UniformInfo<'a> { + pub name: &'a str, + pub bind_type: BindType, +} + +// const ST +impl AsUniforms for StandardMaterial { + fn get_uniform_info(&self) -> &[UniformInfo] { + STANDARD_MATERIAL_UNIFORM_INFO + } + + fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] { + STANDARD_MATERIAL_UNIFORM_LAYOUTS + } + + fn get_uniform_value(&self, index: usize) -> Vec { + match index { + 0 => self.albedo.get_bytes(), + _ => panic!("index out of bounds"), + } + } + // fn iter_properties(&self) -> std::slice::Iter<&'static str> { + // STANDARD_MATERIAL_PROPERTIES.iter() + // } + // fn get_property(&self, name: &str) -> Option { + // match name { + // "albedo" => Some(match self.albedo { + // Albedo::Color(color) => ShaderValue::Vec4(color), + // Albedo::Texture(ref texture) => ShaderValue::Texture(texture) + // }), + // _ => None, + // } + // } + // fn get_selector(&self) -> ShaderMaterialSelector { + // |entity, world| { + // world.get_component::(entity).map( + // |c: Ref| { + // c.map_into(|s| { + // s as &dyn ShaderMaterial + // }) + // } + // ) + // } + // } +} diff --git a/src/render/render_graph_2/wgpu_renderer.rs b/src/render/render_graph_2/wgpu_renderer.rs index 63f41a1a43..71d8191aec 100644 --- a/src/render/render_graph_2/wgpu_renderer.rs +++ b/src/render/render_graph_2/wgpu_renderer.rs @@ -1,13 +1,12 @@ use crate::{ - asset::Mesh, legion::prelude::*, render::render_graph_2::{ - resource, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass, - RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, Renderer, + resource_name, BindType, Buffer, PassDescriptor, PipelineDescriptor, RenderGraph, + RenderPass, RenderPassColorAttachmentDescriptor, + RenderPassDepthStencilAttachmentDescriptor, Renderer, TextureDimension, }, }; use std::{collections::HashMap, ops::Deref}; -use zerocopy::AsBytes; pub struct WgpuRenderer { pub device: wgpu::Device, @@ -68,9 +67,34 @@ impl WgpuRenderer { None => None, }; + let bind_group_layouts = pipeline_descriptor + .pipeline_layout + .bind_groups + .iter() + .map(|bind_group| { + let bind_group_layout_binding = bind_group + .bindings + .iter() + .enumerate() + .map(|(i, binding)| wgpu::BindGroupLayoutBinding { + binding: i as u32, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: (&binding.bind_type).into() + }) + .collect::>(); + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: bind_group_layout_binding.as_slice(), + }) + }) + .collect::>(); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[], + bind_group_layouts: bind_group_layouts + .iter() + .collect::>() + .as_slice(), }); + let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { @@ -108,7 +132,6 @@ impl WgpuRenderer { encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPass<'a> { - // TODO: fill this in encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &pass_descriptor .color_attachments @@ -128,7 +151,7 @@ impl WgpuRenderer { frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPassColorAttachmentDescriptor<'a> { let attachment = match color_attachment_descriptor.attachment.as_str() { - resource::texture::SWAP_CHAIN => &frame.view, + resource_name::texture::SWAP_CHAIN => &frame.view, _ => self .textures .get(&color_attachment_descriptor.attachment) @@ -137,7 +160,7 @@ impl WgpuRenderer { let resolve_target = match color_attachment_descriptor.resolve_target { Some(ref target) => match target.as_str() { - resource::texture::SWAP_CHAIN => Some(&frame.view), + resource_name::texture::SWAP_CHAIN => Some(&frame.view), _ => Some(&frame.view), }, None => None, @@ -158,7 +181,7 @@ impl WgpuRenderer { frame: &'a wgpu::SwapChainOutput, ) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<&'a wgpu::TextureView> { let attachment = match depth_stencil_attachment_descriptor.attachment.as_str() { - resource::texture::SWAP_CHAIN => &frame.view, + resource_name::texture::SWAP_CHAIN => &frame.view, _ => self .textures .get(&depth_stencil_attachment_descriptor.attachment) @@ -197,7 +220,7 @@ impl Renderer for WgpuRenderer { .device .create_swap_chain(self.surface.as_ref().unwrap(), &self.swap_chain_descriptor); - // WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues + // WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World. world.resources.insert(swap_chain); } @@ -242,24 +265,36 @@ impl Renderer for WgpuRenderer { let command_buffer = encoder.finish(); self.queue.submit(&[command_buffer]); } - - fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh) { - if let None = mesh.vertex_buffer { - self.buffers.insert( - format!("meshv{}", asset_id), - self.device - .create_buffer_with_data(mesh.vertices.as_bytes(), wgpu::BufferUsage::VERTEX), - ); - } - - if let None = mesh.index_buffer { - self.buffers.insert( - format!("meshi{}", asset_id), - self.device - .create_buffer_with_data(mesh.indices.as_bytes(), wgpu::BufferUsage::INDEX), - ); + fn create_buffer_with_data(&mut self, data: &[u8], buffer_usage: wgpu::BufferUsage) -> Buffer { + let buffer = self.device.create_buffer_with_data(data, buffer_usage); + // TODO: FILL THIS IN + Buffer { + buffer_usage, + size: data.len() as u64, + id: 0, } } + fn free_buffer(&mut self, id: super::ResourceId) -> super::Buffer { + unimplemented!() + } + + // fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh) { + // if let None = mesh.vertex_buffer { + // self.buffers.insert( + // format!("meshv{}", asset_id), + // self.device + // .create_buffer_with_data(mesh.vertices.as_bytes(), wgpu::BufferUsage::VERTEX), + // ); + // } + + // if let None = mesh.index_buffer { + // self.buffers.insert( + // format!("meshi{}", asset_id), + // self.device + // .create_buffer_with_data(mesh.indices.as_bytes(), wgpu::BufferUsage::INDEX), + // ); + // } + // } } pub struct WgpuRenderPass<'a, 'b, 'c> { @@ -272,3 +307,41 @@ impl<'a, 'b, 'c> RenderPass for WgpuRenderPass<'a, 'b, 'c> { self.render_pass.set_index_buffer(buffer, offset); } } + +impl From for wgpu::TextureViewDimension { + fn from(dimension: TextureDimension) -> Self { + match dimension { + TextureDimension::D1 => wgpu::TextureViewDimension::D1, + TextureDimension::D2 => wgpu::TextureViewDimension::D2, + TextureDimension::D2Array => wgpu::TextureViewDimension::D2Array, + TextureDimension::Cube => wgpu::TextureViewDimension::Cube, + TextureDimension::CubeArray => wgpu::TextureViewDimension::CubeArray, + TextureDimension::D3 => wgpu::TextureViewDimension::D3, + } + } +} + +impl From<&BindType> for wgpu::BindingType { + fn from(bind_type: &BindType) -> Self { + match bind_type { + BindType::Uniform { dynamic, properties: _ } => { + wgpu::BindingType::UniformBuffer { dynamic: *dynamic } + } + BindType::Buffer { dynamic, readonly } => { + wgpu::BindingType::StorageBuffer { dynamic: *dynamic, readonly: *readonly } + } + BindType::SampledTexture { + dimension, + multisampled, + } => wgpu::BindingType::SampledTexture { + dimension: (*dimension).into(), + multisampled: *multisampled, + }, + BindType::Sampler => wgpu::BindingType::Sampler, + BindType::StorageTexture { dimension } => { + wgpu::BindingType::StorageTexture { dimension: (*dimension).into() } + }, + } + } + +} \ No newline at end of file