From 6a818c5acbb230427d0e3331148a1d3ac78e72af Mon Sep 17 00:00:00 2001 From: Luo Zhiaho Date: Sun, 31 May 2026 23:01:38 +0800 Subject: [PATCH 1/2] Reduce `LayoutCache::get` and `BindGroupLayoutCache::get` heap allocation --- .../src/render_resource/pipeline_cache.rs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 197782336dd79..a746ae80ed3a8 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -2,6 +2,7 @@ use bevy_material::descriptor::{ BindGroupLayoutDescriptor, CachedComputePipelineId, CachedRenderPipelineId, ComputePipelineDescriptor, PipelineDescriptor, RenderPipelineDescriptor, }; +use smallvec::SmallVec; use crate::{ render_resource::*, @@ -16,7 +17,7 @@ use bevy_ecs::{ system::{Res, ResMut}, }; use bevy_log::error; -use bevy_platform::collections::{HashMap, HashSet}; +use bevy_platform::collections::{hash_map::RawEntryMut, HashMap, HashSet}; use bevy_shader::{ CachedPipelineId, Shader, ShaderCache, ShaderCacheError, ShaderCacheSource, ShaderDefVal, ValidateShader, @@ -79,8 +80,15 @@ impl CachedPipelineState { } } +// The default webgpu `max_bind_groups` is 4. Most desktop GPUs support 8. +// Since the element size we used below is small, we inline 8 on the stack. +const BIND_GROUP_LAYOUTS_INLINE_CAPACITY: usize = 8; + type ImmediateSize = u32; -type LayoutCacheKey = (Vec, ImmediateSize); +type LayoutCacheKey = ( + SmallVec<[BindGroupLayoutId; BIND_GROUP_LAYOUTS_INLINE_CAPACITY]>, + ImmediateSize, +); #[derive(Default)] struct LayoutCache { layouts: HashMap>>, @@ -101,7 +109,7 @@ impl LayoutCache { .iter() .map(BindGroupLayout::value) .map(Some) - .collect::>(); + .collect::>(); Arc::new(WgpuWrapper::new(render_device.create_pipeline_layout( &PipelineLayoutDescriptor { bind_group_layouts: &bind_group_layouts, @@ -175,15 +183,17 @@ impl BindGroupLayoutCache { fn get( &mut self, render_device: &RenderDevice, - descriptor: BindGroupLayoutDescriptor, + descriptor: &BindGroupLayoutDescriptor, ) -> BindGroupLayout { - self.bgls - .entry(descriptor) - .or_insert_with_key(|descriptor| { - render_device - .create_bind_group_layout(descriptor.label.as_ref(), &descriptor.entries) - }) - .clone() + match self.bgls.raw_entry_mut().from_key(descriptor) { + RawEntryMut::Occupied(entry) => entry.into_mut(), + RawEntryMut::Vacant(slot) => { + let created = render_device + .create_bind_group_layout(descriptor.label.as_ref(), &descriptor.entries); + slot.insert(descriptor.clone(), created).1 + } + } + .clone() } } @@ -442,7 +452,7 @@ impl PipelineCache { self.bindgroup_layout_cache .lock() .unwrap() - .get(&self.device, bind_group_layout_descriptor.clone()) + .get(&self.device, bind_group_layout_descriptor) } /// Inserts a [`Shader`] into this cache with the provided [`AssetId`]. @@ -478,7 +488,7 @@ impl PipelineCache { .layout .iter() .map(|bind_group_layout_descriptor| { - bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor.clone()) + bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor) }) .collect::>(); @@ -586,7 +596,7 @@ impl PipelineCache { .layout .iter() .map(|bind_group_layout_descriptor| { - bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor.clone()) + bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor) }) .collect::>(); From f96ef399ce74525b65bcf77f712c92e153dc4ba0 Mon Sep 17 00:00:00 2001 From: Luo Zhiaho Date: Mon, 1 Jun 2026 00:58:36 +0800 Subject: [PATCH 2/2] Collect SmallVec --- crates/bevy_render/src/render_resource/pipeline_cache.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index a746ae80ed3a8..9841ed594f480 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -490,7 +490,7 @@ impl PipelineCache { .map(|bind_group_layout_descriptor| { bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor) }) - .collect::>(); + .collect::>(); create_pipeline_task( async move { @@ -598,7 +598,7 @@ impl PipelineCache { .map(|bind_group_layout_descriptor| { bindgroup_layout_cache.get(&self.device, bind_group_layout_descriptor) }) - .collect::>(); + .collect::>(); create_pipeline_task( async move {