From 796d9e063b38f979bb872ef537594edce0739aa8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Feb 2024 14:44:21 -0800 Subject: [PATCH 1/7] Intern mesh vertex buffer layouts so that we don't have to compare them over and over. Although we cached hashes of `MeshVertexBufferLayout`, we were paying the cost of `PartialEq` on `InnerMeshVertexBufferLayout` for every entity, every frame. This patch changes that logic to place `MeshVertexBufferLayout`s in `Arc`s so that they can be compared and hashed by pointer. This results in a 28% speedup in the `queue_material_meshes` phase of `many_cubes`, with frustum culling disabled. Additionally, this patch contains two minor changes: 1. This commit flattens the specialized mesh pipeline cache to one level of hash tables instead of two. This saves a hash lookup. 2. The example `many_cubes` has been given a `--no-frustum-culling` flag, to aid in benchmarking. --- crates/bevy_pbr/src/extended_material.rs | 6 +-- crates/bevy_pbr/src/lightmap/mod.rs | 2 +- crates/bevy_pbr/src/material.rs | 7 +-- crates/bevy_pbr/src/pbr_material.rs | 6 ++- crates/bevy_pbr/src/prepass/mod.rs | 16 +++--- crates/bevy_pbr/src/render/mesh.rs | 25 ++++----- crates/bevy_pbr/src/wireframe.rs | 5 +- crates/bevy_render/src/mesh/mesh/mod.rs | 40 +++++++++----- crates/bevy_render/src/mesh/mod.rs | 52 ++++++++++++++++++- .../render_resource/pipeline_specializer.rs | 20 +++---- crates/bevy_sprite/src/mesh2d/material.rs | 6 +-- crates/bevy_sprite/src/mesh2d/mesh.rs | 17 +++--- examples/2d/custom_gltf_vertex_attribute.rs | 6 +-- examples/3d/lines.rs | 4 +- examples/shader/custom_vertex_attribute.rs | 6 +-- examples/shader/shader_defs.rs | 4 +- examples/shader/shader_instancing.rs | 4 +- examples/stress_tests/many_cubes.rs | 12 ++++- 18 files changed, 154 insertions(+), 84 deletions(-) diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_pbr/src/extended_material.rs index a80a6d5af5503..f9e3049683340 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, @@ -75,7 +75,7 @@ pub trait MaterialExtension: Asset + AsBindGroup + Clone + Sized { 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..20f8f0a1384dd 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::*, @@ -177,7 +177,7 @@ pub trait Material: Asset + AsBindGroup + Clone + Sized { 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 135e720ce1735..ee4aea85c8745 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..5969a114c7d73 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -3,13 +3,19 @@ mod mesh; pub mod morph; pub mod primitives; +use bevy_utils::HashSet; pub use mesh::*; pub use primitives::*; +use std::{ + borrow::Borrow, + 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 +33,47 @@ 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::(); + } +} + +#[derive(Clone, Debug)] +pub struct MeshVertexBufferLayoutRef(pub Arc); + +#[derive(Clone, Default, Resource)] +pub struct MeshVertexBufferLayouts(HashSet); + +impl MeshVertexBufferLayouts { + pub fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef { + self.0 + .get_or_insert_with(&layout, |layout| { + MeshVertexBufferLayoutRef(Arc::new(layout.clone())) + }) + .clone() + } +} + +impl Borrow for MeshVertexBufferLayoutRef { + fn borrow(&self) -> &MeshVertexBufferLayout { + &self.0 + } +} + +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 &MeshVertexBufferLayout 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..1d95b241c3bde 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, MeshVertexBufferLayout, 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..d37b17bbbcaa0 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::{MeshVertexBufferLayout, 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..e7ab7d8580c97 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, MeshVertexBufferLayout, 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..21fdc3d1109a6 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::{MeshVertexBufferLayout, 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..b63ce3386c4d1 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, MeshVertexBufferLayout, 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/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 From 7973535f7a68bac55059e8911dea03ba313c150b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 00:48:41 -0800 Subject: [PATCH 2/7] Address review comments --- crates/bevy_render/src/mesh/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index 5969a114c7d73..f4b166b893b9c 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -42,14 +42,26 @@ impl Plugin for MeshPlugin { } } +/// 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. #[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 { - pub fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef { + /// 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 we're using `get_or_insert_with` on the layout itself, not + // the `MeshVertexBufferLayoutRef`, this compares the mesh vertex buffer + // layout structurally, not by pointer. self.0 .get_or_insert_with(&layout, |layout| { MeshVertexBufferLayoutRef(Arc::new(layout.clone())) From 9a240ae06cbc7ed53bbb32235f4af79adc569f7e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 00:52:12 -0800 Subject: [PATCH 3/7] Fix broken doc links --- crates/bevy_pbr/src/extended_material.rs | 2 +- crates/bevy_pbr/src/material.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_pbr/src/extended_material.rs index f9e3049683340..5ad2e1a8eb42b 100644 --- a/crates/bevy_pbr/src/extended_material.rs +++ b/crates/bevy_pbr/src/extended_material.rs @@ -68,7 +68,7 @@ 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] diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 20f8f0a1384dd..6939153c7fcb4 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -171,7 +171,7 @@ 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( From 8a3c3de844c636547edb29f71fde63a05e39680c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 01:36:35 -0800 Subject: [PATCH 4/7] Warning police --- examples/2d/custom_gltf_vertex_attribute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/2d/custom_gltf_vertex_attribute.rs b/examples/2d/custom_gltf_vertex_attribute.rs index 1d95b241c3bde..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, MeshVertexBufferLayoutRef}, + mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef}, render_resource::*, }, sprite::{Material2d, Material2dKey, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle}, From 1cb7abf981a2e38160a546ff17465df3f0d3b9bb Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 07:02:02 -0800 Subject: [PATCH 5/7] Address review comment --- crates/bevy_render/src/mesh/mod.rs | 6 +++++- examples/shader/shader_instancing.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index f4b166b893b9c..22a75b221866b 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -46,7 +46,11 @@ impl Plugin for MeshPlugin { /// /// 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. +/// 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); diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index b63ce3386c4d1..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, MeshVertexBufferLayoutRef}, + mesh::{GpuBufferInfo, MeshVertexBufferLayoutRef}, render_asset::RenderAssets, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, From cae189c6f1598beda9d0bd0f544b0b53dc4c5dd6 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 11:46:38 -0800 Subject: [PATCH 6/7] Clippy police --- examples/3d/lines.rs | 2 +- examples/shader/custom_vertex_attribute.rs | 2 +- examples/shader/shader_defs.rs | 2 +- examples/shader/shader_material_glsl.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/3d/lines.rs b/examples/3d/lines.rs index d37b17bbbcaa0..ad2a516b2c50a 100644 --- a/examples/3d/lines.rs +++ b/examples/3d/lines.rs @@ -5,7 +5,7 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - mesh::{MeshVertexBufferLayout, MeshVertexBufferLayoutRef, PrimitiveTopology}, + mesh::{MeshVertexBufferLayoutRef, PrimitiveTopology}, render_asset::RenderAssetUsages, render_resource::{ AsBindGroup, PolygonMode, RenderPipelineDescriptor, ShaderRef, diff --git a/examples/shader/custom_vertex_attribute.rs b/examples/shader/custom_vertex_attribute.rs index e7ab7d8580c97..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, MeshVertexBufferLayoutRef}, + mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef}, render_resource::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, VertexFormat, diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 21fdc3d1109a6..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, MeshVertexBufferLayoutRef}, + mesh::MeshVertexBufferLayoutRef, render_resource::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, }, 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(); From fa07eee95fb9df71c3886ec1e85b3791ec6b0e1d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Mar 2024 12:44:51 -0800 Subject: [PATCH 7/7] Don't hash the pointer when inserting into the `MeshVertexBufferLayouts` table. The trick with `Borrow` was too clever and ended up actually hashing the pointer, causing lookups to sometimes spuriously fail. This manifested itself as a crash in `alien_cake_addict`. Removing the `MeshVertexBufferLayoutRef` wrapper from the entries in the store prevents its implementation of `Hash` from being called, solving the problem. --- crates/bevy_render/src/mesh/mod.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index 22a75b221866b..a6d67e960fe4d 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -7,7 +7,6 @@ use bevy_utils::HashSet; pub use mesh::*; pub use primitives::*; use std::{ - borrow::Borrow, hash::{Hash, Hasher}, sync::Arc, }; @@ -56,27 +55,22 @@ pub struct MeshVertexBufferLayoutRef(pub Arc); /// Stores the single copy of each mesh vertex buffer layout. #[derive(Clone, Default, Resource)] -pub struct MeshVertexBufferLayouts(HashSet); +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 we're using `get_or_insert_with` on the layout itself, not - // the `MeshVertexBufferLayoutRef`, this compares the mesh vertex buffer - // layout structurally, not by pointer. - self.0 - .get_or_insert_with(&layout, |layout| { - MeshVertexBufferLayoutRef(Arc::new(layout.clone())) - }) - .clone() - } -} - -impl Borrow for MeshVertexBufferLayoutRef { - fn borrow(&self) -> &MeshVertexBufferLayout { - &self.0 + // 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(), + ) } } @@ -90,6 +84,6 @@ impl Eq for MeshVertexBufferLayoutRef {} impl Hash for MeshVertexBufferLayoutRef { fn hash(&self, state: &mut H) { - (&*self.0 as &MeshVertexBufferLayout as *const MeshVertexBufferLayout as usize).hash(state); + (&*self.0 as *const MeshVertexBufferLayout as usize).hash(state); } }