diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index fb86f411d438f..0b86cd95e1a8a 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1300,8 +1300,11 @@ pub struct MaterialProperties { pub reads_view_transmission_texture: bool, pub render_phase_type: RenderPhaseType, pub material_layout: Option, - pub draw_functions: HashMap, - pub shaders: HashMap>, + /// Backing array is a size of 4 because the `StandardMaterial` needs 4 draw functions by default + pub draw_functions: SmallVec<[(InternedDrawFunctionLabel, DrawFunctionId); 4]>, + /// Backing array is a size of 3 because the `StandardMaterial` has 3 custom shaders (`frag`, `prepass_frag`, `deferred_frag`) which is the + /// most common use case + pub shaders: SmallVec<[(InternedShaderLabel, Handle); 3]>, /// Whether this material *actually* uses bindless resources, taking the /// platform support (or lack thereof) of bindless resources into account. pub bindless: bool, @@ -1320,27 +1323,31 @@ pub struct MaterialProperties { impl MaterialProperties { pub fn get_shader(&self, label: impl ShaderLabel) -> Option> { - self.shaders.get(&label.intern()).cloned() + self.shaders + .iter() + .find(|(inner_label, _)| inner_label == &label.intern()) + .map(|(_, shader)| shader) + .cloned() } - pub fn add_shader( - &mut self, - label: impl ShaderLabel, - shader: Handle, - ) -> Option> { - self.shaders.insert(label.intern(), shader) + pub fn add_shader(&mut self, label: impl ShaderLabel, shader: Handle) { + self.shaders.push((label.intern(), shader)); } pub fn get_draw_function(&self, label: impl DrawFunctionLabel) -> Option { - self.draw_functions.get(&label.intern()).copied() + self.draw_functions + .iter() + .find(|(inner_label, _)| inner_label == &label.intern()) + .map(|(_, shader)| shader) + .cloned() } pub fn add_draw_function( &mut self, label: impl DrawFunctionLabel, draw_function: DrawFunctionId, - ) -> Option { - self.draw_functions.insert(label.intern(), draw_function) + ) { + self.draw_functions.push((label.intern(), draw_function)); } } @@ -1472,19 +1479,19 @@ where _ => None, }; - let mut draw_functions = HashMap::new(); - draw_functions.insert(MaterialDrawFunction.intern(), draw_function_id); + let mut draw_functions = SmallVec::new(); + draw_functions.push((MaterialDrawFunction.intern(), draw_function_id)); if let Some(prepass_draw_function_id) = prepass_draw_function_id { - draw_functions.insert(PrepassDrawFunction.intern(), prepass_draw_function_id); + draw_functions.push((PrepassDrawFunction.intern(), prepass_draw_function_id)); } if let Some(deferred_draw_function_id) = deferred_draw_function_id { - draw_functions.insert(DeferredDrawFunction.intern(), deferred_draw_function_id); + draw_functions.push((DeferredDrawFunction.intern(), deferred_draw_function_id)); } if let Some(shadow_draw_function_id) = shadow_draw_function_id { - draw_functions.insert(ShadowsDrawFunction.intern(), shadow_draw_function_id); + draw_functions.push((ShadowsDrawFunction.intern(), shadow_draw_function_id)); } - let mut shaders = HashMap::new(); + let mut shaders = SmallVec::new(); let mut add_shader = |label: InternedShaderLabel, shader_ref: ShaderRef| { let mayber_shader = match shader_ref { ShaderRef::Default => None, @@ -1492,7 +1499,7 @@ where ShaderRef::Path(path) => Some(asset_server.load(path)), }; if let Some(shader) = mayber_shader { - shaders.insert(label, shader); + shaders.push((label, shader)); } }; add_shader(MaterialVertexShader.intern(), M::vertex_shader()); diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 13b44edbdd56c..42b2c28c1510f 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -553,27 +553,18 @@ impl PrepassPipelineInternal { || emulate_unclipped_depth || (mesh_key.contains(MeshPipelineKey::MAY_DISCARD) && material_properties - .shaders - .get(&PrepassFragmentShader.intern()) + .get_shader(PrepassFragmentShader) .is_some()); let fragment = fragment_required.then(|| { // Use the fragment shader from the material let frag_shader_handle = if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) { - match material_properties - .shaders - .get(&DeferredFragmentShader.intern()) - .cloned() - { + match material_properties.get_shader(DeferredFragmentShader) { Some(frag_shader_handle) => frag_shader_handle, None => self.default_prepass_shader.clone(), } } else { - match material_properties - .shaders - .get(&PrepassFragmentShader.intern()) - .cloned() - { + match material_properties.get_shader(PrepassFragmentShader) { Some(frag_shader_handle) => frag_shader_handle, None => self.default_prepass_shader.clone(), }