diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_pbr/src/extended_material.rs index a80a6d5af5503..5ad2e1a8eb42b 100644 --- a/crates/bevy_pbr/src/extended_material.rs +++ b/crates/bevy_pbr/src/extended_material.rs @@ -1,7 +1,7 @@ use bevy_asset::{Asset, Handle}; use bevy_reflect::{impl_type_path, Reflect}; use bevy_render::{ - mesh::MeshVertexBufferLayout, + mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, render_resource::{ AsBindGroup, AsBindGroupError, BindGroupLayout, RenderPipelineDescriptor, Shader, @@ -68,14 +68,14 @@ pub trait MaterialExtension: Asset + AsBindGroup + Clone + Sized { } /// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's - /// [`MaterialPipelineKey`] and [`MeshVertexBufferLayout`] as input. + /// [`MaterialPipelineKey`] and [`MeshVertexBufferLayoutRef`] as input. /// Specialization for the base material is applied before this function is called. #[allow(unused_variables)] #[inline] fn specialize( pipeline: &MaterialExtensionPipeline, descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, key: MaterialExtensionKey, ) -> Result<(), SpecializedMeshPipelineError> { Ok(()) @@ -214,7 +214,7 @@ impl Material for ExtendedMaterial { fn specialize( pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { // Call the base material's specialize function diff --git a/crates/bevy_pbr/src/lightmap/mod.rs b/crates/bevy_pbr/src/lightmap/mod.rs index c34ac4885707e..30c4bc631fb21 100644 --- a/crates/bevy_pbr/src/lightmap/mod.rs +++ b/crates/bevy_pbr/src/lightmap/mod.rs @@ -159,7 +159,7 @@ fn extract_lightmaps( || !render_mesh_instances .get(&entity) .and_then(|mesh_instance| meshes.get(mesh_instance.mesh_asset_id)) - .is_some_and(|mesh| mesh.layout.contains(Mesh::ATTRIBUTE_UV_1.id)) + .is_some_and(|mesh| mesh.layout.0.contains(Mesh::ATTRIBUTE_UV_1.id)) { continue; } diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index aab0ea7a1e26e..6939153c7fcb4 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -18,7 +18,7 @@ use bevy_render::{ camera::TemporalJitter, extract_instances::{ExtractInstancesPlugin, ExtractedInstances}, extract_resource::ExtractResource, - mesh::{Mesh, MeshVertexBufferLayout}, + mesh::{Mesh, MeshVertexBufferLayoutRef}, render_asset::RenderAssets, render_phase::*, render_resource::*, @@ -171,13 +171,13 @@ pub trait Material: Asset + AsBindGroup + Clone + Sized { } /// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's - /// [`MaterialPipelineKey`] and [`MeshVertexBufferLayout`] as input. + /// [`MaterialPipelineKey`] and [`MeshVertexBufferLayoutRef`] as input. #[allow(unused_variables)] #[inline] fn specialize( pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { Ok(()) @@ -326,7 +326,7 @@ where fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?; if let Some(vertex_shader) = &self.vertex_shader { @@ -585,6 +585,7 @@ pub fn queue_material_meshes( camera_3d.screen_space_specular_transmission_quality, ); } + let rangefinder = view.rangefinder3d(); for visible_entity in &visible_entities.entities { let Some(material_asset_id) = render_material_instances.get(visible_entity) else { diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 816d88a02f045..a83509267d2ec 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -2,7 +2,9 @@ use bevy_asset::Asset; use bevy_color::Alpha; use bevy_math::{Affine2, Mat3, Vec4}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_render::{mesh::MeshVertexBufferLayout, render_asset::RenderAssets, render_resource::*}; +use bevy_render::{ + mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, render_resource::*, +}; use crate::deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID; use crate::*; @@ -813,7 +815,7 @@ impl Material for StandardMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _layout: &MeshVertexBufferLayout, + _layout: &MeshVertexBufferLayoutRef, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { if let Some(fragment) = descriptor.fragment.as_mut() { diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index b0b17b4a0301a..818022b5a7cc9 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,5 +1,6 @@ mod prepass_bindings; +use bevy_render::mesh::MeshVertexBufferLayoutRef; use bevy_render::render_resource::binding_types::uniform_buffer; pub use prepass_bindings::*; @@ -17,7 +18,6 @@ use bevy_math::{Affine3A, Mat4}; use bevy_render::{ batching::batch_and_prepare_render_phase, globals::{GlobalsBuffer, GlobalsUniform}, - mesh::MeshVertexBufferLayout, prelude::{Camera, Mesh}, render_asset::RenderAssets, render_phase::*, @@ -302,7 +302,7 @@ where fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut bind_group_layouts = vec![if key .mesh_key @@ -347,7 +347,7 @@ where shader_defs.push("BLEND_ALPHA".into()); } - if layout.contains(Mesh::ATTRIBUTE_POSITION) { + if layout.0.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } @@ -363,12 +363,12 @@ where shader_defs.push("PREPASS_FRAGMENT".into()); } - if layout.contains(Mesh::ATTRIBUTE_UV_0) { + if layout.0.contains(Mesh::ATTRIBUTE_UV_0) { shader_defs.push("VERTEX_UVS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1)); } - if layout.contains(Mesh::ATTRIBUTE_UV_1) { + if layout.0.contains(Mesh::ATTRIBUTE_UV_1) { shader_defs.push("VERTEX_UVS_B".into()); vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(2)); } @@ -383,7 +383,7 @@ where { vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(3)); shader_defs.push("NORMAL_PREPASS_OR_DEFERRED_PREPASS".into()); - if layout.contains(Mesh::ATTRIBUTE_TANGENT) { + if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) { shader_defs.push("VERTEX_TANGENTS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4)); } @@ -400,7 +400,7 @@ where shader_defs.push("DEFERRED_PREPASS".into()); } - if layout.contains(Mesh::ATTRIBUTE_COLOR) { + if layout.0.contains(Mesh::ATTRIBUTE_COLOR) { shader_defs.push("VERTEX_COLORS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(7)); } @@ -430,7 +430,7 @@ where ); bind_group_layouts.insert(1, bind_group); - let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?; + let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; // Setup prepass fragment targets - normals in slot 0 (or None if not needed), motion vectors in slot 1 let mut targets = vec![ diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 4cd5f8d7ec699..31f3a29352a28 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -26,7 +26,7 @@ use bevy_render::{ Extract, }; use bevy_transform::components::GlobalTransform; -use bevy_utils::{tracing::error, Entry, HashMap, Hashed, Parallel}; +use bevy_utils::{tracing::error, Entry, HashMap, Parallel}; #[cfg(debug_assertions)] use bevy_utils::warn_once; @@ -595,12 +595,13 @@ impl MeshPipelineKey { } } -fn is_skinned(layout: &Hashed) -> bool { - layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX) && layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT) +fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool { + layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX) + && layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT) } pub fn setup_morph_and_skinning_defs( mesh_layouts: &MeshLayouts, - layout: &Hashed, + layout: &MeshVertexBufferLayoutRef, offset: u32, key: &MeshPipelineKey, shader_defs: &mut Vec, @@ -638,7 +639,7 @@ impl SpecializedMeshPipeline for MeshPipeline { fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); @@ -648,32 +649,32 @@ impl SpecializedMeshPipeline for MeshPipeline { shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into()); - if layout.contains(Mesh::ATTRIBUTE_POSITION) { + if layout.0.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } - if layout.contains(Mesh::ATTRIBUTE_NORMAL) { + if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) { shader_defs.push("VERTEX_NORMALS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1)); } - if layout.contains(Mesh::ATTRIBUTE_UV_0) { + if layout.0.contains(Mesh::ATTRIBUTE_UV_0) { shader_defs.push("VERTEX_UVS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2)); } - if layout.contains(Mesh::ATTRIBUTE_UV_1) { + if layout.0.contains(Mesh::ATTRIBUTE_UV_1) { shader_defs.push("VERTEX_UVS_B".into()); vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3)); } - if layout.contains(Mesh::ATTRIBUTE_TANGENT) { + if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) { shader_defs.push("VERTEX_TANGENTS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4)); } - if layout.contains(Mesh::ATTRIBUTE_COLOR) { + if layout.0.contains(Mesh::ATTRIBUTE_COLOR) { shader_defs.push("VERTEX_COLORS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5)); } @@ -701,7 +702,7 @@ impl SpecializedMeshPipeline for MeshPipeline { shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into()); } - let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?; + let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; let (label, blend, depth_write_enabled); let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS); diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 10bf0571002a9..5a7564e048798 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -5,7 +5,8 @@ use bevy_color::{Color, LinearRgba}; use bevy_ecs::prelude::*; use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath}; use bevy_render::{ - extract_resource::ExtractResource, mesh::MeshVertexBufferLayout, prelude::*, render_resource::*, + extract_resource::ExtractResource, mesh::MeshVertexBufferLayoutRef, prelude::*, + render_resource::*, }; pub const WIREFRAME_SHADER_HANDLE: Handle = Handle::weak_from_u128(192598014480025766); @@ -208,7 +209,7 @@ impl Material for WireframeMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _layout: &MeshVertexBufferLayout, + _layout: &MeshVertexBufferLayoutRef, _key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { descriptor.primitive.polygon_mode = PolygonMode::Line; diff --git a/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index aee822155fadc..33a21e62d6b58 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -13,11 +13,14 @@ use crate::{ use bevy_asset::{Asset, Handle}; use bevy_core::cast_slice; use bevy_derive::EnumVariantMeta; -use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; +use bevy_ecs::system::{ + lifetimeless::{SRes, SResMut}, + SystemParamItem, +}; use bevy_log::warn; use bevy_math::*; use bevy_reflect::Reflect; -use bevy_utils::{tracing::error, Hashed}; +use bevy_utils::tracing::error; use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator}; use thiserror::Error; use wgpu::{ @@ -25,6 +28,8 @@ use wgpu::{ VertexStepMode, }; +use super::{MeshVertexBufferLayoutRef, MeshVertexBufferLayouts}; + pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0; pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10; @@ -377,7 +382,10 @@ impl Mesh { /// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in [`SpecializedMeshPipeline`]. /// /// [`SpecializedMeshPipeline`]: crate::render_resource::SpecializedMeshPipeline - pub fn get_mesh_vertex_buffer_layout(&self) -> MeshVertexBufferLayout { + pub fn get_mesh_vertex_buffer_layout( + &self, + mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts, + ) -> MeshVertexBufferLayoutRef { let mut attributes = Vec::with_capacity(self.attributes.len()); let mut attribute_ids = Vec::with_capacity(self.attributes.len()); let mut accumulated_offset = 0; @@ -391,14 +399,15 @@ impl Mesh { accumulated_offset += data.attribute.format.get_size(); } - MeshVertexBufferLayout::new(InnerMeshVertexBufferLayout { + let layout = MeshVertexBufferLayout { layout: VertexBufferLayout { array_stride: accumulated_offset, step_mode: VertexStepMode::Vertex, attributes, }, attribute_ids, - }) + }; + mesh_vertex_buffer_layouts.insert(layout) } /// Counts all vertices of the mesh. @@ -967,15 +976,13 @@ impl From for MeshVertexAttributeId { } } -pub type MeshVertexBufferLayout = Hashed; - #[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct InnerMeshVertexBufferLayout { +pub struct MeshVertexBufferLayout { attribute_ids: Vec, layout: VertexBufferLayout, } -impl InnerMeshVertexBufferLayout { +impl MeshVertexBufferLayout { pub fn new(attribute_ids: Vec, layout: VertexBufferLayout) -> Self { Self { attribute_ids, @@ -1350,7 +1357,7 @@ pub struct GpuMesh { pub morph_targets: Option, pub buffer_info: GpuBufferInfo, pub primitive_topology: PrimitiveTopology, - pub layout: MeshVertexBufferLayout, + pub layout: MeshVertexBufferLayoutRef, } /// The index/vertex buffer info of a [`GpuMesh`]. @@ -1367,7 +1374,11 @@ pub enum GpuBufferInfo { impl RenderAsset for Mesh { type PreparedAsset = GpuMesh; - type Param = (SRes, SRes>); + type Param = ( + SRes, + SRes>, + SResMut, + ); fn asset_usage(&self) -> RenderAssetUsages { self.asset_usage @@ -1376,7 +1387,9 @@ impl RenderAsset for Mesh { /// Converts the extracted mesh a into [`GpuMesh`]. fn prepare_asset( self, - (render_device, images): &mut SystemParamItem, + (render_device, images, ref mut mesh_vertex_buffer_layouts): &mut SystemParamItem< + Self::Param, + >, ) -> Result> { let vertex_buffer_data = self.get_vertex_buffer_data(); let vertex_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { @@ -1399,7 +1412,8 @@ impl RenderAsset for Mesh { GpuBufferInfo::NonIndexed }; - let mesh_vertex_buffer_layout = self.get_mesh_vertex_buffer_layout(); + let mesh_vertex_buffer_layout = + self.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts); Ok(GpuMesh { vertex_buffer, diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index 172565ef1db5b..a6d67e960fe4d 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -3,13 +3,18 @@ mod mesh; pub mod morph; pub mod primitives; +use bevy_utils::HashSet; pub use mesh::*; pub use primitives::*; +use std::{ + hash::{Hash, Hasher}, + sync::Arc, +}; -use crate::{prelude::Image, render_asset::RenderAssetPlugin}; +use crate::{prelude::Image, render_asset::RenderAssetPlugin, RenderApp}; use bevy_app::{App, Plugin}; use bevy_asset::{AssetApp, Handle}; -use bevy_ecs::entity::Entity; +use bevy_ecs::{entity::Entity, system::Resource}; /// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU. pub struct MeshPlugin; @@ -27,5 +32,58 @@ impl Plugin for MeshPlugin { .register_type::>() // 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready .add_plugins(RenderAssetPlugin::::default()); + + let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app.init_resource::(); + } +} + +/// Describes the layout of the mesh vertices in GPU memory. +/// +/// At most one copy of a mesh vertex buffer layout ever exists in GPU memory at +/// once. Therefore, comparing these for equality requires only a single pointer +/// comparison, and this type's [`PartialEq`] and [`Hash`] implementations take +/// advantage of this. To that end, this type doesn't implement +/// [`bevy_derive::Deref`] or [`bevy_derive::DerefMut`] in order to reduce the +/// possibility of accidental deep comparisons, which would be needlessly +/// expensive. +#[derive(Clone, Debug)] +pub struct MeshVertexBufferLayoutRef(pub Arc); + +/// Stores the single copy of each mesh vertex buffer layout. +#[derive(Clone, Default, Resource)] +pub struct MeshVertexBufferLayouts(HashSet>); + +impl MeshVertexBufferLayouts { + /// Inserts a new mesh vertex buffer layout in the store and returns a + /// reference to it, reusing the existing reference if this mesh vertex + /// buffer layout was already in the store. + pub(crate) fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef { + // Because the special `PartialEq` and `Hash` implementations that + // compare by pointer are on `MeshVertexBufferLayoutRef`, not on + // `Arc`, this compares the mesh vertex buffer + // structurally, not by pointer. + MeshVertexBufferLayoutRef( + self.0 + .get_or_insert_with(&layout, |layout| Arc::new(layout.clone())) + .clone(), + ) + } +} + +impl PartialEq for MeshVertexBufferLayoutRef { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} + +impl Eq for MeshVertexBufferLayoutRef {} + +impl Hash for MeshVertexBufferLayoutRef { + fn hash(&self, state: &mut H) { + (&*self.0 as *const MeshVertexBufferLayout as usize).hash(state); } } diff --git a/crates/bevy_render/src/render_resource/pipeline_specializer.rs b/crates/bevy_render/src/render_resource/pipeline_specializer.rs index 7fc8533830ff5..746f7bee7afff 100644 --- a/crates/bevy_render/src/render_resource/pipeline_specializer.rs +++ b/crates/bevy_render/src/render_resource/pipeline_specializer.rs @@ -1,16 +1,14 @@ +use crate::mesh::MeshVertexBufferLayoutRef; use crate::render_resource::CachedComputePipelineId; use crate::{ - mesh::{InnerMeshVertexBufferLayout, MeshVertexBufferLayout, MissingVertexAttributeError}, + mesh::MissingVertexAttributeError, render_resource::{ CachedRenderPipelineId, ComputePipelineDescriptor, PipelineCache, RenderPipelineDescriptor, VertexBufferLayout, }, }; use bevy_ecs::system::Resource; -use bevy_utils::{ - default, hashbrown::hash_map::RawEntryMut, tracing::error, Entry, HashMap, PreHashMap, - PreHashMapExt, -}; +use bevy_utils::{default, hashbrown::hash_map::RawEntryMut, tracing::error, Entry, HashMap}; use std::{fmt::Debug, hash::Hash}; use thiserror::Error; @@ -79,14 +77,13 @@ pub trait SpecializedMeshPipeline { fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result; } #[derive(Resource)] pub struct SpecializedMeshPipelines { - mesh_layout_cache: - PreHashMap>, + mesh_layout_cache: HashMap<(MeshVertexBufferLayoutRef, S::Key), CachedRenderPipelineId>, vertex_layout_cache: HashMap>, } @@ -106,12 +103,9 @@ impl SpecializedMeshPipelines { cache: &PipelineCache, specialize_pipeline: &S, key: S::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { - let map = self - .mesh_layout_cache - .get_or_insert_with(layout, Default::default); - match map.entry(key.clone()) { + match self.mesh_layout_cache.entry((layout.clone(), key.clone())) { Entry::Occupied(entry) => Ok(*entry.into_mut()), Entry::Vacant(entry) => { let descriptor = specialize_pipeline diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 8e0dc38d42421..a8588c73f80e3 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -12,7 +12,7 @@ use bevy_ecs::{ }; use bevy_log::error; use bevy_render::{ - mesh::{Mesh, MeshVertexBufferLayout}, + mesh::{Mesh, MeshVertexBufferLayoutRef}, prelude::Image, render_asset::{prepare_assets, RenderAssets}, render_phase::{ @@ -125,7 +125,7 @@ pub trait Material2d: AsBindGroup + Asset + Clone + Sized { #[inline] fn specialize( descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, key: Material2dKey, ) -> Result<(), SpecializedMeshPipelineError> { Ok(()) @@ -271,7 +271,7 @@ where fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut descriptor = self.mesh2d_pipeline.specialize(key.mesh_key, layout)?; if let Some(vertex_shader) = &self.vertex_shader { diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 8908ac096d890..045c1e2ca2594 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -11,13 +11,14 @@ use bevy_ecs::{ }; use bevy_math::{Affine3, Vec4}; use bevy_reflect::Reflect; +use bevy_render::mesh::MeshVertexBufferLayoutRef; use bevy_render::{ batching::{ batch_and_prepare_render_phase, write_batched_instance_buffer, GetBatchData, NoAutomaticBatching, }, globals::{GlobalsBuffer, GlobalsUniform}, - mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout}, + mesh::{GpuBufferInfo, Mesh}, render_asset::RenderAssets, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::{binding_types::uniform_buffer, *}, @@ -436,32 +437,32 @@ impl SpecializedMeshPipeline for Mesh2dPipeline { fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); - if layout.contains(Mesh::ATTRIBUTE_POSITION) { + if layout.0.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } - if layout.contains(Mesh::ATTRIBUTE_NORMAL) { + if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) { shader_defs.push("VERTEX_NORMALS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1)); } - if layout.contains(Mesh::ATTRIBUTE_UV_0) { + if layout.0.contains(Mesh::ATTRIBUTE_UV_0) { shader_defs.push("VERTEX_UVS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2)); } - if layout.contains(Mesh::ATTRIBUTE_TANGENT) { + if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) { shader_defs.push("VERTEX_TANGENTS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3)); } - if layout.contains(Mesh::ATTRIBUTE_COLOR) { + if layout.0.contains(Mesh::ATTRIBUTE_COLOR) { shader_defs.push("VERTEX_COLORS".into()); vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4)); } @@ -504,7 +505,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline { } } - let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?; + let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; let format = match key.contains(Mesh2dPipelineKey::HDR) { true => ViewTarget::TEXTURE_FORMAT_HDR, diff --git a/examples/2d/custom_gltf_vertex_attribute.rs b/examples/2d/custom_gltf_vertex_attribute.rs index 2f84665c31b6e..59c36e754050e 100644 --- a/examples/2d/custom_gltf_vertex_attribute.rs +++ b/examples/2d/custom_gltf_vertex_attribute.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::{MeshVertexAttribute, MeshVertexBufferLayout}, + mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef}, render_resource::*, }, sprite::{Material2d, Material2dKey, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle}, @@ -70,10 +70,10 @@ impl Material2d for CustomMaterial { fn specialize( descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, _key: Material2dKey, ) -> Result<(), SpecializedMeshPipelineError> { - let vertex_layout = layout.get_layout(&[ + let vertex_layout = layout.0.get_layout(&[ Mesh::ATTRIBUTE_POSITION.at_shader_location(0), Mesh::ATTRIBUTE_COLOR.at_shader_location(1), ATTRIBUTE_BARYCENTRIC.at_shader_location(2), diff --git a/examples/3d/lines.rs b/examples/3d/lines.rs index 8342f134918ec..ad2a516b2c50a 100644 --- a/examples/3d/lines.rs +++ b/examples/3d/lines.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::{MeshVertexBufferLayout, PrimitiveTopology}, + mesh::{MeshVertexBufferLayoutRef, PrimitiveTopology}, render_asset::RenderAssetUsages, render_resource::{ AsBindGroup, PolygonMode, RenderPipelineDescriptor, ShaderRef, @@ -78,7 +78,7 @@ impl Material for LineMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _layout: &MeshVertexBufferLayout, + _layout: &MeshVertexBufferLayoutRef, _key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { // This is the important part to tell bevy to render this material as a line between vertices diff --git a/examples/shader/custom_vertex_attribute.rs b/examples/shader/custom_vertex_attribute.rs index c3abf4d09a8e6..72a816c17cd93 100644 --- a/examples/shader/custom_vertex_attribute.rs +++ b/examples/shader/custom_vertex_attribute.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::{MeshVertexAttribute, MeshVertexBufferLayout}, + mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef}, render_resource::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, VertexFormat, @@ -74,10 +74,10 @@ impl Material for CustomMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, _key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { - let vertex_layout = layout.get_layout(&[ + let vertex_layout = layout.0.get_layout(&[ Mesh::ATTRIBUTE_POSITION.at_shader_location(0), ATTRIBUTE_BLEND_COLOR.at_shader_location(1), ])?; diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index a7da28ff0eedb..8edbd3b957593 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::MeshVertexBufferLayout, + mesh::MeshVertexBufferLayoutRef, render_resource::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, }, @@ -62,7 +62,7 @@ impl Material for CustomMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _layout: &MeshVertexBufferLayout, + _layout: &MeshVertexBufferLayoutRef, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { if key.bind_group_data.is_red { diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 27dc6f9455d5a..47c7b6e4bac0d 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -12,7 +12,7 @@ use bevy::{ prelude::*, render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, - mesh::{GpuBufferInfo, MeshVertexBufferLayout}, + mesh::{GpuBufferInfo, MeshVertexBufferLayoutRef}, render_asset::RenderAssets, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, @@ -197,7 +197,7 @@ impl SpecializedMeshPipeline for CustomPipeline { fn specialize( &self, key: Self::Key, - layout: &MeshVertexBufferLayout, + layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut descriptor = self.mesh_pipeline.specialize(key, layout)?; diff --git a/examples/shader/shader_material_glsl.rs b/examples/shader/shader_material_glsl.rs index 27a5e7f31a289..ee780065e5cc1 100644 --- a/examples/shader/shader_material_glsl.rs +++ b/examples/shader/shader_material_glsl.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::MeshVertexBufferLayout, + mesh::MeshVertexBufferLayoutRef, render_resource::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, }, @@ -78,7 +78,7 @@ impl Material for CustomMaterial { fn specialize( _pipeline: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _layout: &MeshVertexBufferLayout, + _layout: &MeshVertexBufferLayoutRef, _key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { descriptor.vertex.entry_point = "main".into(); diff --git a/examples/stress_tests/many_cubes.rs b/examples/stress_tests/many_cubes.rs index cb808e936881f..88755973c6863 100644 --- a/examples/stress_tests/many_cubes.rs +++ b/examples/stress_tests/many_cubes.rs @@ -18,8 +18,9 @@ use bevy::{ render::{ render_asset::RenderAssetUsages, render_resource::{Extent3d, TextureDimension, TextureFormat}, + view::NoFrustumCulling, }, - window::{PresentMode, WindowPlugin, WindowResolution}, + window::{PresentMode, WindowResolution}, winit::{UpdateMode, WinitSettings}, }; use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng}; @@ -42,6 +43,10 @@ struct Args { /// the number of different textures from which to randomly select the material base color. 0 means no textures. #[argh(option, default = "0")] material_texture_count: usize, + + /// whether to disable frustum culling, for stress testing purposes + #[argh(switch)] + no_frustum_culling: bool, } #[derive(Default, Clone)] @@ -131,12 +136,15 @@ fn setup( let spherical_polar_theta_phi = fibonacci_spiral_on_sphere(golden_ratio, i, N_POINTS); let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi); - commands.spawn(PbrBundle { + let mut cube = commands.spawn(PbrBundle { mesh: mesh.clone(), material: materials.choose(&mut material_rng).unwrap().clone(), transform: Transform::from_translation((radius * unit_sphere_p).as_vec3()), ..default() }); + if args.no_frustum_culling { + cube.insert(NoFrustumCulling); + } } // camera