diff --git a/.vscode/launch.json b/.vscode/launch.json index 7437063d50..49a302f501 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -30,11 +30,11 @@ "cargo": { "args": [ "build", - "--example=simple_new_graph", + "--example=simple_new", "--package=bevy" ], "filter": { - "name": "simple_new_graph", + "name": "simple_new", "kind": "example" } }, @@ -48,12 +48,12 @@ "cargo": { "args": [ "run", - "--example=simple", + "--example=simple_new", "--package=bevy", "--release" ], "filter": { - "name": "simple", + "name": "simple_new", "kind": "example" } }, diff --git a/ROADMAP.md b/ROADMAP.md index 287fc8652d..8fe526de9d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,6 +14,9 @@ Here is the current list of planned features. All items are sorted in approximat * Add runtime type safety to uniform bindings (and maybe compile time) * Dynamic / user defined shaders * consider using shaderc-rs. but this introduces compile complexity and requires other C++ build systems +* Error Handling + * Custom error type? + * Remove as many panics / unwraps as possible * Input * Keyboard and mouse events * Gamepad events diff --git a/src/render/render_graph_2/pipeline.rs b/src/render/render_graph_2/pipeline.rs index 022d199ccc..24d9477533 100644 --- a/src/render/render_graph_2/pipeline.rs +++ b/src/render/render_graph_2/pipeline.rs @@ -20,10 +20,16 @@ impl<'a> Into> for &'a VertexBufferDescriptor { } } +#[derive(Clone, Debug)] +pub enum PipelineLayoutType { + Manual(PipelineLayout), + Reflected(Option), +} + #[derive(Clone, Debug)] pub struct PipelineDescriptor { pub draw_targets: Vec, - pub pipeline_layout: PipelineLayout, + pub layout: PipelineLayoutType, pub shader_stages: ShaderStages, pub rasterization_state: Option, @@ -59,7 +65,7 @@ pub struct PipelineDescriptor { impl PipelineDescriptor { fn new(vertex_shader: Handle) -> Self { PipelineDescriptor { - pipeline_layout: PipelineLayout::new(), + layout: PipelineLayoutType::Reflected(None), color_states: Vec::new(), depth_stencil_state: None, draw_targets: Vec::new(), @@ -79,6 +85,20 @@ impl PipelineDescriptor { alpha_to_coverage_enabled: false, } } + + pub fn get_layout(&self) -> Option<&PipelineLayout> { + match self.layout { + PipelineLayoutType::Reflected(ref layout) => layout.as_ref(), + PipelineLayoutType::Manual(ref layout) => Some(layout), + } + } + + pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> { + match self.layout { + PipelineLayoutType::Reflected(ref mut layout) => layout.as_mut(), + PipelineLayoutType::Manual(ref mut layout) => Some(layout), + } + } } impl PipelineDescriptor { @@ -128,7 +148,14 @@ impl<'a> PipelineBuilder<'a> { } pub fn add_bind_group(mut self, bind_group: BindGroup) -> Self { - self.pipeline.pipeline_layout.bind_groups.push(bind_group); + if let PipelineLayoutType::Reflected(_) = self.pipeline.layout { + self.pipeline.layout = PipelineLayoutType::Manual(PipelineLayout::new()); + } + + if let PipelineLayoutType::Manual(ref mut layout) = self.pipeline.layout { + layout.bind_groups.push(bind_group); + } + self } diff --git a/src/render/render_graph_2/pipeline_layout.rs b/src/render/render_graph_2/pipeline_layout.rs index 7a2ee6379f..3c5d2bf316 100644 --- a/src/render/render_graph_2/pipeline_layout.rs +++ b/src/render/render_graph_2/pipeline_layout.rs @@ -1,5 +1,6 @@ +use crate::render::shader_reflect::ShaderLayout; use std::{ - collections::hash_map::DefaultHasher, + collections::{HashMap, hash_map::DefaultHasher, BTreeSet}, hash::{Hash, Hasher}, }; @@ -14,23 +15,61 @@ impl PipelineLayout { bind_groups: Vec::new(), } } + + pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self { + let mut bind_groups = HashMap::::new(); + for shader_layout in shader_layouts { + for shader_bind_group in shader_layout.bind_groups.iter_mut() { + match bind_groups.get_mut(&shader_bind_group.index) { + Some(bind_group) => { + for shader_binding in shader_bind_group.bindings.iter() { + if let Some(binding) = bind_group.bindings.iter().find(|binding| binding.index == shader_binding.index) { + if binding != shader_binding { + panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding); + } + } else { + bind_group.bindings.insert(shader_binding.clone()); + } + } + }, + None => { + bind_groups.insert(shader_bind_group.index, shader_bind_group.clone()); + } + } + } + } + + PipelineLayout { + bind_groups: bind_groups.drain().map(|(_, value)| value).collect() + } + } } -#[derive(Hash, Clone, Debug)] +#[derive(Clone, Debug)] pub struct BindGroup { - pub bindings: Vec, + pub index: u32, + pub bindings: BTreeSet, hash: Option, } impl BindGroup { - pub fn new(bindings: Vec) -> Self { + pub fn new(index: u32, bindings: Vec) -> Self { BindGroup { - bindings, + index, + bindings: bindings.iter().cloned().collect(), hash: None, } } - pub fn get_hash(&self) -> u64 { + pub fn get_hash(&self) -> Option { + self.hash + } + + pub fn get_or_update_hash(&mut self) -> u64 { + if self.hash.is_none() { + self.update_hash(); + } + self.hash.unwrap() } @@ -41,14 +80,22 @@ impl BindGroup { } } -#[derive(Hash, Clone, Debug)] +impl Hash for BindGroup { + fn hash(&self, state: &mut H) { + self.index.hash(state); + self.bindings.hash(state); + } +} + +#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct Binding { pub name: String, + pub index: u32, pub bind_type: BindType, // TODO: ADD SHADER STAGE VISIBILITY } -#[derive(Hash, Clone, Debug)] +#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum BindType { Uniform { dynamic: bool, @@ -81,13 +128,13 @@ impl BindType { } } -#[derive(Hash, Clone, Debug)] +#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct UniformProperty { pub name: String, pub property_type: UniformPropertyType, } -#[derive(Hash, Clone, Debug)] +#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum UniformPropertyType { // TODO: Add all types here Int, @@ -95,6 +142,7 @@ pub enum UniformPropertyType { UVec4, Vec3, Vec4, + Mat3, Mat4, Struct(Vec), Array(Box, usize), @@ -108,6 +156,7 @@ impl UniformPropertyType { UniformPropertyType::UVec4 => 4 * 4, UniformPropertyType::Vec3 => 4 * 3, UniformPropertyType::Vec4 => 4 * 4, + UniformPropertyType::Mat3 => 4 * 4 * 3, UniformPropertyType::Mat4 => 4 * 4 * 4, UniformPropertyType::Struct(properties) => properties .iter() @@ -118,7 +167,7 @@ impl UniformPropertyType { } } -#[derive(Copy, Clone, Debug, Hash)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum TextureViewDimension { D1, D2, diff --git a/src/render/render_graph_2/pipelines/forward/mod.rs b/src/render/render_graph_2/pipelines/forward/mod.rs index c903a56e10..ebfa87240b 100644 --- a/src/render/render_graph_2/pipelines/forward/mod.rs +++ b/src/render/render_graph_2/pipelines/forward/mod.rs @@ -21,72 +21,76 @@ impl ForwardPipelineBuilder for RenderGraphBuilder { include_str!("forward.frag"), ShaderStage::Fragment, )) - .add_bind_group(BindGroup::new(vec![ - Binding { - name: "Camera".to_string(), - bind_type: BindType::Uniform { - dynamic: false, - properties: vec![UniformProperty { - name: "ViewProj".to_string(), - property_type: UniformPropertyType::Mat4, - }], - }, - }, - Binding { - name: "Lights".to_string(), - bind_type: BindType::Uniform { - dynamic: false, - properties: vec![ - UniformProperty { - name: "NumLights".to_string(), - property_type: UniformPropertyType::UVec4, - }, - UniformProperty { - name: "SceneLights".to_string(), - property_type: UniformPropertyType::Array( - Box::new(UniformPropertyType::Struct(vec![ - UniformProperty { - name: "proj".to_string(), - property_type: UniformPropertyType::Mat4, - }, - UniformProperty { - name: "pos".to_string(), - property_type: UniformPropertyType::Vec4, - }, - UniformProperty { - name: "color".to_string(), - property_type: UniformPropertyType::Vec4, - }, - ])), - 10, // max lights - ), - }, - ], - }, - }, - ])) - .add_bind_group(BindGroup::new(vec![ - Binding { - name: "Object".to_string(), - bind_type: BindType::Uniform { - dynamic: true, - properties: vec![UniformProperty { - name: "Model".to_string(), - property_type: UniformPropertyType::Mat4, - }], - }, - }, - Binding { - name: "StandardMaterial_albedo".to_string(), - bind_type: BindType::Uniform { - dynamic: true, - properties: vec![UniformProperty { - name: "Albedo".to_string(), - property_type: UniformPropertyType::Vec4, - }], - }, - }, - ])) + // .add_bind_group(BindGroup::new(0, vec![ + // Binding { + // index: 0, + // name: "Camera".to_string(), + // bind_type: BindType::Uniform { + // dynamic: false, + // properties: vec![UniformProperty { + // name: "ViewProj".to_string(), + // property_type: UniformPropertyType::Mat4, + // }], + // }, + // }, + // Binding { + // index: 1, + // name: "Lights".to_string(), + // bind_type: BindType::Uniform { + // dynamic: false, + // properties: vec![ + // UniformProperty { + // name: "NumLights".to_string(), + // property_type: UniformPropertyType::UVec4, + // }, + // UniformProperty { + // name: "SceneLights".to_string(), + // property_type: UniformPropertyType::Array( + // Box::new(UniformPropertyType::Struct(vec![ + // UniformProperty { + // name: "proj".to_string(), + // property_type: UniformPropertyType::Mat4, + // }, + // UniformProperty { + // name: "pos".to_string(), + // property_type: UniformPropertyType::Vec4, + // }, + // UniformProperty { + // name: "color".to_string(), + // property_type: UniformPropertyType::Vec4, + // }, + // ])), + // 10, // max lights + // ), + // }, + // ], + // }, + // }, + // ])) + // .add_bind_group(BindGroup::new(1, vec![ + // Binding { + // index: 0, + // name: "Object".to_string(), + // bind_type: BindType::Uniform { + // dynamic: true, + // properties: vec![UniformProperty { + // name: "Model".to_string(), + // property_type: UniformPropertyType::Mat4, + // }], + // }, + // }, + // Binding { + // index: 1, + // name: "StandardMaterial_albedo".to_string(), + // bind_type: BindType::Uniform { + // dynamic: true, + // properties: vec![UniformProperty { + // name: "Albedo".to_string(), + // property_type: UniformPropertyType::Vec4, + // }], + // }, + // }, + // ])) .with_rasterization_state(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, 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 f9e2ede830..dea02d2dc4 100644 --- a/src/render/render_graph_2/pipelines/forward_flat/mod.rs +++ b/src/render/render_graph_2/pipelines/forward_flat/mod.rs @@ -34,7 +34,8 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder { include_str!("forward_flat.frag"), ShaderStage::Fragment, )) - .add_bind_group(BindGroup::new(vec![Binding { + .add_bind_group(BindGroup::new(0, vec![Binding { + index: 0, name: "Camera".to_string(), bind_type: BindType::Uniform { dynamic: false, @@ -44,8 +45,9 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder { }], }, }])) - .add_bind_group(BindGroup::new(vec![ + .add_bind_group(BindGroup::new(1, vec![ Binding { + index: 0, name: "Object".to_string(), bind_type: BindType::Uniform { dynamic: true, @@ -56,6 +58,7 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder { }, }, Binding { + index: 1, name: "StandardMaterial_albedo".to_string(), bind_type: BindType::Uniform { dynamic: true, diff --git a/src/render/render_graph_2/pipelines/ui/mod.rs b/src/render/render_graph_2/pipelines/ui/mod.rs index b6ba37aa5c..36e68d3105 100644 --- a/src/render/render_graph_2/pipelines/ui/mod.rs +++ b/src/render/render_graph_2/pipelines/ui/mod.rs @@ -33,7 +33,8 @@ impl UiPipelineBuilder for RenderGraphBuilder { include_str!("ui.frag"), ShaderStage::Fragment, )) - .add_bind_group(BindGroup::new(vec![Binding { + .add_bind_group(BindGroup::new(0, vec![Binding { + index: 0, name: "Camera2d".to_string(), bind_type: BindType::Uniform { dynamic: false, diff --git a/src/render/render_graph_2/renderers/wgpu_renderer.rs b/src/render/render_graph_2/renderers/wgpu_renderer.rs index 7af520b632..62a342ae49 100644 --- a/src/render/render_graph_2/renderers/wgpu_renderer.rs +++ b/src/render/render_graph_2/renderers/wgpu_renderer.rs @@ -4,9 +4,9 @@ use crate::{ render::{ render_graph_2::{ resource_name, update_shader_assignments, BindGroup, BindType, - DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, RenderPass, - RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor, - Renderer, ResourceInfo, TextureDescriptor, + DynamicUniformBufferInfo, PassDescriptor, PipelineDescriptor, PipelineLayout, + PipelineLayoutType, RenderGraph, RenderPass, RenderPassColorAttachmentDescriptor, + RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDescriptor, }, Shader, }, @@ -76,25 +76,37 @@ impl WgpuRenderer { vertex_shader: &Shader, fragment_shader: Option<&Shader>, ) -> wgpu::RenderPipeline { - let vertex_shader_module = Self::create_shader_module(device, vertex_shader, None); + let vertex_spirv = vertex_shader.get_spirv_shader(None); + let fragment_spirv = fragment_shader.map(|f| f.get_spirv_shader(None)); + + let vertex_shader_module = Self::create_shader_module(device, &vertex_spirv, None); let fragment_shader_module = match fragment_shader { - Some(fragment_shader) => { - Some(Self::create_shader_module(device, fragment_shader, None)) - } + Some(fragment_spirv) => Some(Self::create_shader_module(device, fragment_spirv, None)), None => None, }; + if let PipelineLayoutType::Reflected(None) = pipeline_descriptor.layout { + let mut layouts = vec![vertex_spirv.reflect_layout().unwrap()]; + + if let Some(ref fragment_spirv) = fragment_spirv { + layouts.push(fragment_spirv.reflect_layout().unwrap()); + } + + pipeline_descriptor.layout = + PipelineLayoutType::Reflected(Some(PipelineLayout::from_shader_layouts(&mut layouts))); + } + + let layout = pipeline_descriptor.get_layout_mut().unwrap(); + // setup new bind group layouts - for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter_mut() { - bind_group.update_hash(); - let bind_group_id = bind_group.get_hash(); + for bind_group in layout.bind_groups.iter_mut() { + let bind_group_id = bind_group.get_or_update_hash(); if let None = bind_group_layouts.get(&bind_group_id) { let bind_group_layout_binding = bind_group .bindings .iter() - .enumerate() - .map(|(i, binding)| wgpu::BindGroupLayoutBinding { - binding: i as u32, + .map(|binding| wgpu::BindGroupLayoutBinding { + binding: binding.index, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: (&binding.bind_type).into(), }) @@ -109,12 +121,11 @@ impl WgpuRenderer { } // collect bind group layout references - let bind_group_layouts = pipeline_descriptor - .pipeline_layout + let bind_group_layouts = layout .bind_groups .iter() .map(|bind_group| { - let bind_group_id = bind_group.get_hash(); + let bind_group_id = bind_group.get_hash().unwrap(); bind_group_layouts.get(&bind_group_id).unwrap() }) .collect::>(); @@ -127,11 +138,11 @@ impl WgpuRenderer { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vertex_shader_module, - entry_point: &vertex_shader.entry_point, + entry_point: "main", }, fragment_stage: match fragment_shader { Some(fragment_shader) => Some(wgpu::ProgrammableStageDescriptor { - entry_point: &fragment_shader.entry_point, + entry_point: "main", module: fragment_shader_module.as_ref().unwrap(), }), None => None, @@ -233,7 +244,7 @@ impl WgpuRenderer { // TODO: consider moving this to a resource provider fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 { - let bind_group_id = bind_group.get_hash(); + let bind_group_id = bind_group.get_hash().unwrap(); if let None = self.bind_groups.get(&bind_group_id) { let mut unset_uniforms = Vec::new(); @@ -260,12 +271,11 @@ impl WgpuRenderer { let bindings = bind_group .bindings .iter() - .enumerate() - .map(|(i, b)| { - let resource_info = self.resource_info.get(&b.name).unwrap(); + .map(|binding| { + let resource_info = self.resource_info.get(&binding.name).unwrap(); wgpu::Binding { - binding: i as u32, - resource: match &b.bind_type { + binding: binding.index, + resource: match &binding.bind_type { BindType::Uniform { dynamic: _, properties: _, @@ -275,7 +285,7 @@ impl WgpuRenderer { buffer_usage: _, } = resource_info { - let buffer = self.buffers.get(&b.name).unwrap(); + let buffer = self.buffers.get(&binding.name).unwrap(); wgpu::BindingResource::Buffer { buffer, range: 0..*size, @@ -426,7 +436,8 @@ impl Renderer for WgpuRenderer { } // create bind groups - for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() { + let pipeline_layout = pipeline_descriptor.get_layout().unwrap(); + for bind_group in pipeline_layout.bind_groups.iter() { self.setup_bind_group(bind_group); } } @@ -641,14 +652,9 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { } fn setup_bind_groups(&mut self, entity: Option<&Entity>) { - for (i, bind_group) in self - .pipeline_descriptor - .pipeline_layout - .bind_groups - .iter() - .enumerate() - { - let bind_group_id = bind_group.get_hash(); + let pipeline_layout = self.pipeline_descriptor.get_layout().unwrap(); + for bind_group in pipeline_layout.bind_groups.iter() { + let bind_group_id = bind_group.get_hash().unwrap(); let bind_group_info = self.renderer.bind_groups.get(&bind_group_id).unwrap(); let mut dynamic_uniform_indices = Vec::new(); @@ -658,7 +664,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { continue; } - // PERF: This hashmap get is pretty expensive (10 fps per 10000 entities) + // PERF: This hashmap get is pretty expensive (10 fps for 10000 entities) if let Some(dynamic_uniform_buffer_info) = self.renderer.dynamic_uniform_buffer_info.get(&binding.name) { @@ -674,7 +680,7 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> { // TODO: check to see if bind group is already set self.render_pass.set_bind_group( - i as u32, + bind_group.index, &bind_group_info.bind_group, dynamic_uniform_indices.as_slice(), ); diff --git a/src/render/shader.rs b/src/render/shader.rs index 4c4b1d2be3..5c5ec54b82 100644 --- a/src/render/shader.rs +++ b/src/render/shader.rs @@ -1,4 +1,7 @@ -use crate::{asset::Handle, render::shader_reflect::get_shader_layout}; +use crate::{ + asset::Handle, + render::shader_reflect::{get_shader_layout, ShaderLayout}, +}; use std::marker::Copy; #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] @@ -50,11 +53,10 @@ pub enum ShaderSource { Glsl(String), } -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug)] pub struct Shader { pub source: ShaderSource, pub stage: ShaderStage, - pub entry_point: String, // TODO: add "precompile" flag? } @@ -62,29 +64,31 @@ impl Shader { pub fn from_glsl(glsl: &str, stage: ShaderStage) -> Shader { Shader { source: ShaderSource::Glsl(glsl.to_string()), - entry_point: "main".to_string(), stage, } } pub fn get_spirv(&self, macros: Option<&[String]>) -> Vec { - let result = match self.source { + match self.source { ShaderSource::Spirv(ref bytes) => bytes.clone(), ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, macros), - }; - - get_shader_layout(&result); - - result + } } pub fn get_spirv_shader(&self, macros: Option<&[String]>) -> Shader { Shader { source: ShaderSource::Spirv(self.get_spirv(macros)), - entry_point: self.entry_point.clone(), stage: self.stage, } } + + pub fn reflect_layout(&self) -> Option { + if let ShaderSource::Spirv(ref spirv) = self.source { + Some(get_shader_layout(spirv.as_slice())) + } else { + panic!("Cannot reflect layout of non-SpirV shader. Try compiling this shader to SpirV first using self.get_spirv_shader()"); + } + } } #[derive(Clone, Debug)] diff --git a/src/render/shader_reflect.rs b/src/render/shader_reflect.rs index 01a65ce3c5..fda0320457 100644 --- a/src/render/shader_reflect.rs +++ b/src/render/shader_reflect.rs @@ -1,12 +1,17 @@ -use crate::render::render_graph_2::{BindGroup, UniformPropertyType, Binding, BindType, UniformProperty}; +use crate::render::render_graph_2::{ + BindGroup, BindType, Binding, UniformProperty, UniformPropertyType, +}; use spirv_reflect::{ - types::{ReflectDescriptorSet, ReflectTypeDescription, ReflectDescriptorBinding, ReflectDescriptorType, ReflectTypeFlags}, + types::{ + ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, + ReflectTypeDescription, ReflectTypeFlags, + }, ShaderModule, }; use zerocopy::AsBytes; // use rspirv::{binary::Parser, dr::Loader, lift::LiftContext}; -// TODO: pick rspirv vs spirv-reflect +// TODO: use rspirv when structured representation is ready. this way we can remove spirv_reflect, which is a non-rust dependency // pub fn get_shader_layout(spirv_data: &[u32]) { // let mut loader = Loader::new(); // You can use your own consumer here. // { @@ -18,37 +23,39 @@ use zerocopy::AsBytes; // println!("{:?}", structured.types); // } -pub fn get_shader_layout(spirv_data: &[u32]) { +#[derive(Debug, Clone)] +pub struct ShaderLayout { + pub bind_groups: Vec, + pub entry_point: String, +} + +pub fn get_shader_layout(spirv_data: &[u32]) -> ShaderLayout { match ShaderModule::load_u8_data(spirv_data.as_bytes()) { Ok(ref mut module) => { let entry_point_name = module.get_entry_point_name(); - let shader_stage = module.get_shader_stage(); - println!("entry point: {}", entry_point_name); - println!("shader stage: {:?}", shader_stage); - let mut bind_groups = Vec::new(); for descriptor_set in module.enumerate_descriptor_sets(None).unwrap() { let bind_group = reflect_bind_group(&descriptor_set); bind_groups.push(bind_group); } - println!(" result {:?}", &bind_groups); - - println!(); + ShaderLayout { + bind_groups, + entry_point: entry_point_name, + } } - _ => {} + Err(err) => panic!("Failed to reflect shader layout: {:?}", err) } } fn reflect_bind_group(descriptor_set: &ReflectDescriptorSet) -> BindGroup { - println!(" set {}", descriptor_set.set); let mut bindings = Vec::new(); for descriptor_binding in descriptor_set.bindings.iter() { let binding = reflect_binding(descriptor_binding); bindings.push(binding); } - BindGroup::new(bindings) + BindGroup::new(descriptor_set.set, bindings) } fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding { @@ -61,10 +68,10 @@ fn reflect_binding(binding: &ReflectDescriptorBinding) -> Binding { _ => panic!("unsupported bind type {:?}", binding.descriptor_type), }; - // println!(" {:?}", binding); - Binding{ - bind_type: bind_type, - name: type_description.type_name.to_string() + Binding { + index: binding.binding, + bind_type, + name: type_description.type_name.to_string(), } } @@ -76,7 +83,10 @@ enum NumberType { } fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty { - let uniform_property_type = if type_description.type_flags.contains(ReflectTypeFlags::STRUCT) { + let uniform_property_type = if type_description + .type_flags + .contains(ReflectTypeFlags::STRUCT) + { reflect_uniform_struct(type_description) } else { reflect_uniform_numeric(type_description) @@ -89,8 +99,7 @@ fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty } fn reflect_uniform_struct(type_description: &ReflectTypeDescription) -> UniformPropertyType { - println!("reflecting struct"); - let mut properties = Vec::new(); + let mut properties = Vec::new(); for member in type_description.members.iter() { properties.push(reflect_uniform(member)); } @@ -104,9 +113,12 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform match traits.numeric.scalar.signedness { 0 => NumberType::UInt, 1 => NumberType::Int, - signedness => panic!("unexpected signedness {}", signedness) + signedness => panic!("unexpected signedness {}", signedness), } - } else if type_description.type_flags.contains(ReflectTypeFlags::FLOAT) { + } else if type_description + .type_flags + .contains(ReflectTypeFlags::FLOAT) + { NumberType::Float } else { panic!("unexpected type flag {:?}", type_description.type_flags); @@ -114,11 +126,28 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform // TODO: handle scalar width here - match (number_type, traits.numeric.vector.component_count) { - (NumberType::Int, 1) => UniformPropertyType::Int, - (NumberType::Float, 3) => UniformPropertyType::Vec3, - (NumberType::Float, 4) => UniformPropertyType::Vec4, - (NumberType::UInt, 4) => UniformPropertyType::UVec4, - (number_type, component_count) => panic!("unexpected uniform property format {:?} {}", number_type, component_count), + if type_description + .type_flags + .contains(ReflectTypeFlags::MATRIX) + { + match (number_type, traits.numeric.matrix.column_count, traits.numeric.matrix.row_count) { + (NumberType::Float, 3, 3) => UniformPropertyType::Mat3, + (NumberType::Float, 4, 4) => UniformPropertyType::Mat4, + (number_type, column_count, row_count) => panic!( + "unexpected uniform property matrix format {:?} {}x{}", + number_type, column_count, row_count + ), + } + } else { + match (number_type, traits.numeric.vector.component_count) { + (NumberType::Int, 1) => UniformPropertyType::Int, + (NumberType::Float, 3) => UniformPropertyType::Vec3, + (NumberType::Float, 4) => UniformPropertyType::Vec4, + (NumberType::UInt, 4) => UniformPropertyType::UVec4, + (number_type, component_count) => panic!( + "unexpected uniform property format {:?} {}", + number_type, component_count + ), + } } }