From 3bc0a5648a00297e4cb1bbb8b81722816cc74c89 Mon Sep 17 00:00:00 2001 From: Tiernan DeFranco <126631791+TiernanDeFranco@users.noreply.github.com> Date: Wed, 6 May 2026 23:15:43 -0700 Subject: [PATCH] perf(runtime): cut drain reallocs in dirty+render command paths --- .../perro_graphics/src/three_d/particles/gpu.rs | 15 ++++++++++++--- .../perro_runtime/src/runtime/render_bridge.rs | 1 - .../perro_runtime/src/runtime/state.rs | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/perro_source/render_stack/perro_graphics/src/three_d/particles/gpu.rs b/perro_source/render_stack/perro_graphics/src/three_d/particles/gpu.rs index 458091798..fd8c77366 100644 --- a/perro_source/render_stack/perro_graphics/src/three_d/particles/gpu.rs +++ b/perro_source/render_stack/perro_graphics/src/three_d/particles/gpu.rs @@ -174,6 +174,7 @@ pub struct GpuPointParticles3D { compute_spawn_rings: AHashMap, compute_spawn_origin_dirty_slots: Vec, compute_spawn_rotation_dirty_slots: Vec, + emitter_order: Vec, spawn_origin_cache: AHashMap>, spawn_origin_generation: u64, hybrid_map_fingerprint: u64, @@ -987,6 +988,7 @@ impl GpuPointParticles3D { compute_spawn_rings: AHashMap::new(), compute_spawn_origin_dirty_slots: Vec::new(), compute_spawn_rotation_dirty_slots: Vec::new(), + emitter_order: Vec::new(), spawn_origin_cache: AHashMap::new(), spawn_origin_generation: 0, hybrid_map_fingerprint: 0, @@ -1041,9 +1043,16 @@ impl GpuPointParticles3D { if self.spawn_origin_generation == 0 { self.spawn_origin_generation = 1; } - let mut emitter_order = (0..frame.emitters.len()).collect::>(); - emitter_order.sort_unstable_by_key(|&i| frame.emitters[i].0.as_u64()); - for idx in emitter_order { + self.emitter_order.clear(); + if self.emitter_order.capacity() < frame.emitters.len() { + self.emitter_order + .reserve(frame.emitters.len() - self.emitter_order.capacity()); + } + self.emitter_order.extend(0..frame.emitters.len()); + self.emitter_order + .sort_unstable_by_key(|&i| frame.emitters[i].0.as_u64()); + for pos in 0..self.emitter_order.len() { + let idx = self.emitter_order[pos]; let (node, emitter) = &frame.emitters[idx]; match emitter.sim_mode { ParticleSimulationMode3D::Cpu => self.push_emitter_particles(*node, emitter), diff --git a/perro_source/runtime_project/perro_runtime/src/runtime/render_bridge.rs b/perro_source/runtime_project/perro_runtime/src/runtime/render_bridge.rs index 13259c474..4fe306850 100644 --- a/perro_source/runtime_project/perro_runtime/src/runtime/render_bridge.rs +++ b/perro_source/runtime_project/perro_runtime/src/runtime/render_bridge.rs @@ -18,7 +18,6 @@ impl Runtime { pub fn drain_render_commands(&mut self, out: &mut Vec) { let mut queued_resource_commands = self.render.take_resource_queue_scratch(); - queued_resource_commands.clear(); self.resource_api .drain_commands(&mut queued_resource_commands); if !queued_resource_commands.is_empty() { diff --git a/perro_source/runtime_project/perro_runtime/src/runtime/state.rs b/perro_source/runtime_project/perro_runtime/src/runtime/state.rs index 520287473..5a07bc500 100644 --- a/perro_source/runtime_project/perro_runtime/src/runtime/state.rs +++ b/perro_source/runtime_project/perro_runtime/src/runtime/state.rs @@ -229,6 +229,9 @@ impl RenderState { } pub(crate) fn drain_commands(&mut self, out: &mut Vec) { + if out.capacity() - out.len() < self.pending_commands.len() { + out.reserve(self.pending_commands.len() - (out.capacity() - out.len())); + } out.append(&mut self.pending_commands); } @@ -587,6 +590,9 @@ impl DirtyState { pub(crate) fn take_pending_transform_roots(&mut self, out: &mut Vec) { out.clear(); + if out.capacity() < self.pending_transform_roots.len() { + out.reserve(self.pending_transform_roots.len() - out.capacity()); + } out.append(&mut self.pending_transform_roots); for id in out.iter().copied() { let index = id.index() as usize;