diff --git a/crates/bevy_sprite/Cargo.toml b/crates/bevy_sprite/Cargo.toml index 53b70abeb8d9f..6b81e4cff2f9e 100644 --- a/crates/bevy_sprite/Cargo.toml +++ b/crates/bevy_sprite/Cargo.toml @@ -30,3 +30,4 @@ guillotiere = "0.6.0" thiserror = "1.0" rectangle-pack = "0.4" serde = { version = "1", features = ["derive"] } +copyless = "0.1.5" diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 3e5477f4b9f11..68cd750516525 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -1,5 +1,7 @@ use std::{cmp::Ordering, ops::Range}; +use copyless::VecHelper; + use crate::{ texture_atlas::{TextureAtlas, TextureAtlasSprite}, Rect, Sprite, SPRITE_SHADER_HANDLE, @@ -218,14 +220,25 @@ pub fn extract_sprites( ) { let mut extracted_sprites = render_world.get_resource_mut::().unwrap(); extracted_sprites.sprites.clear(); - for (computed_visibility, sprite, transform, handle) in sprite_query.iter() { + + // `get` is not cheap. Cache the previous image and handle and bypass `get` when requesting the + // same handle multiple times in a row. + let mut current_image_handle = None; + let mut current_image = None; + for (computed_visibility, sprite, transform, image_handle) in sprite_query.iter() { if !computed_visibility.is_visible { continue; } - if let Some(image) = images.get(handle) { + + if current_image_handle != Some(image_handle) { + current_image = images.get(image_handle); + current_image_handle = Some(image_handle); + }; + + if let Some(image) = current_image { let size = image.texture_descriptor.size; - extracted_sprites.sprites.push(ExtractedSprite { + extracted_sprites.sprites.alloc().init(ExtractedSprite { atlas_size: None, color: sprite.color, transform: transform.compute_matrix(), @@ -237,18 +250,27 @@ pub fn extract_sprites( }, flip_x: sprite.flip_x, flip_y: sprite.flip_y, - handle: handle.clone_weak(), + handle: image_handle.clone_weak(), }); }; } + + let mut current_atlas_handle = None; + let mut current_atlas = None; for (computed_visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { if !computed_visibility.is_visible { continue; } - if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) { + + if current_atlas_handle != Some(texture_atlas_handle) { + current_atlas = texture_atlases.get(texture_atlas_handle); + current_atlas_handle = Some(texture_atlas_handle); + }; + + if let Some(texture_atlas) = current_atlas { if images.contains(&texture_atlas.texture) { let rect = texture_atlas.textures[atlas_sprite.index as usize]; - extracted_sprites.sprites.push(ExtractedSprite { + extracted_sprites.sprites.alloc().init(ExtractedSprite { atlas_size: Some(texture_atlas.size), color: atlas_sprite.color, transform: transform.compute_matrix(),