From 8bceb1c9fba8af8af1b09d13ca0cc196fee3ae48 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 20 Feb 2022 22:05:34 +0100 Subject: [PATCH 1/4] Quick and dirty ComputedVisiblity support for sprites, text2d This is needed for RenderLayers to work properly --- crates/bevy_sprite/src/bundle.rs | 3 +++ crates/bevy_sprite/src/render/mod.rs | 27 +++++++++++++++++++++------ crates/bevy_text/src/text2d.rs | 4 +++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index 82fdcd9db6292..4400f6c26de73 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -5,6 +5,7 @@ use crate::{ use bevy_asset::Handle; use bevy_ecs::bundle::Bundle; use bevy_render::{ + prelude::ComputedVisibility, texture::{Image, DEFAULT_IMAGE_HANDLE}, view::Visibility, }; @@ -18,6 +19,7 @@ pub struct SpriteBundle { pub texture: Handle, /// User indication of whether an entity is visible pub visibility: Visibility, + pub computed_visibility: ComputedVisibility, } impl Default for SpriteBundle { @@ -28,6 +30,7 @@ impl Default for SpriteBundle { global_transform: Default::default(), texture: DEFAULT_IMAGE_HANDLE.typed(), visibility: Default::default(), + computed_visibility: Default::default(), } } } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index c0066482014f7..b2e1ed15314bf 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -22,7 +22,7 @@ use bevy_render::{ render_resource::*, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, Image}, - view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, + view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities}, RenderWorld, }; use bevy_transform::components::GlobalTransform; @@ -173,6 +173,7 @@ impl SpecializedRenderPipeline for SpritePipeline { #[derive(Component, Clone, Copy)] pub struct ExtractedSprite { + pub entity: Entity, pub transform: GlobalTransform, pub color: Color, /// Select an area of the texture @@ -224,8 +225,15 @@ pub fn extract_sprite_events( pub fn extract_sprites( mut render_world: ResMut, texture_atlases: Res>, - sprite_query: Query<(&Visibility, &Sprite, &GlobalTransform, &Handle)>, + sprite_query: Query<( + Entity, + &Visibility, + &Sprite, + &GlobalTransform, + &Handle, + )>, atlas_query: Query<( + Entity, &Visibility, &TextureAtlasSprite, &GlobalTransform, @@ -234,12 +242,13 @@ pub fn extract_sprites( ) { let mut extracted_sprites = render_world.resource_mut::(); extracted_sprites.sprites.clear(); - for (visibility, sprite, transform, handle) in sprite_query.iter() { + for (entity, visibility, sprite, transform, handle) in sprite_query.iter() { if !visibility.is_visible { continue; } // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.alloc().init(ExtractedSprite { + entity, color: sprite.color, transform: *transform, // Use the full texture @@ -252,13 +261,14 @@ pub fn extract_sprites( anchor: sprite.anchor.as_vec(), }); } - for (visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { + for (entity, visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { if !visibility.is_visible { continue; } if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) { let rect = Some(texture_atlas.textures[atlas_sprite.index as usize]); extracted_sprites.sprites.alloc().init(ExtractedSprite { + entity, color: atlas_sprite.color, transform: *transform, // Select the area in the texture atlas @@ -347,7 +357,7 @@ pub fn queue_sprites( gpu_images: Res>, msaa: Res, mut extracted_sprites: ResMut, - mut views: Query<&mut RenderPhase>, + mut views: Query<(&VisibleEntities, &mut RenderPhase)>, events: Res, ) { // If an image has changed, the GpuImage has (probably) changed @@ -390,7 +400,7 @@ pub fn queue_sprites( let mut colored_index = 0; // FIXME: VisibleEntities is ignored - for mut transparent_phase in views.iter_mut() { + for (visible_entities, mut transparent_phase) in views.iter_mut() { let extracted_sprites = &mut extracted_sprites.sprites; let image_bind_groups = &mut *image_bind_groups; @@ -422,6 +432,11 @@ pub fn queue_sprites( // Batches are merged later (in `batch_phase_system()`), so that they can be interrupted // by any other phase item (and they can interrupt other items from batching). for extracted_sprite in extracted_sprites.iter() { + // TODO: this is probably super-inefficient + if !visible_entities.entities.contains(&extracted_sprite.entity) { + continue; + } + // &visible_entities.entities let new_batch = SpriteBatch { image_handle_id: extracted_sprite.image_handle_id, colored: extracted_sprite.color != Color::WHITE, diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index d0bebbad3609a..3106f002446eb 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ }; use bevy_math::{Vec2, Vec3}; use bevy_reflect::Reflect; -use bevy_render::{texture::Image, view::Visibility, RenderWorld}; +use bevy_render::{prelude::ComputedVisibility, texture::Image, view::Visibility, RenderWorld}; use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_utils::HashSet; @@ -58,6 +58,7 @@ pub struct Text2dBundle { pub text_2d_size: Text2dSize, pub text_2d_bounds: Text2dBounds, pub visibility: Visibility, + pub computed_visibility: ComputedVisibility, } pub fn extract_text2d_sprite( @@ -111,6 +112,7 @@ pub fn extract_text2d_sprite( let transform = text_transform.mul_transform(glyph_transform); extracted_sprites.sprites.push(ExtractedSprite { + entity, transform, color, rect, From 6377ee32aa5f06c0bd406edae5c372628c0b04b0 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 21 Feb 2022 14:00:04 +0100 Subject: [PATCH 2/4] Use a HashSet to speed up visibility checking --- crates/bevy_sprite/src/render/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index b2e1ed15314bf..d5d73f795d3f6 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -27,7 +27,7 @@ use bevy_render::{ }; use bevy_transform::components::GlobalTransform; use bevy_utils::FloatOrd; -use bevy_utils::HashMap; +use bevy_utils::{HashMap, HashSet}; use bytemuck::{Pod, Zeroable}; use copyless::VecHelper; @@ -404,6 +404,8 @@ pub fn queue_sprites( let extracted_sprites = &mut extracted_sprites.sprites; let image_bind_groups = &mut *image_bind_groups; + let visible_entities = HashSet::from_iter(visible_entities.iter().cloned()); + transparent_phase.items.reserve(extracted_sprites.len()); // Sort sprites by z for correct transparency and then by handle to improve batching @@ -432,11 +434,9 @@ pub fn queue_sprites( // Batches are merged later (in `batch_phase_system()`), so that they can be interrupted // by any other phase item (and they can interrupt other items from batching). for extracted_sprite in extracted_sprites.iter() { - // TODO: this is probably super-inefficient - if !visible_entities.entities.contains(&extracted_sprite.entity) { + if !visible_entities.contains(&extracted_sprite.entity) { continue; } - // &visible_entities.entities let new_batch = SpriteBatch { image_handle_id: extracted_sprite.image_handle_id, colored: extracted_sprite.color != Color::WHITE, From 1ddb82d12d5ebc83f59bc820564b0bda3b4a439c Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 22 Feb 2022 08:53:05 +0100 Subject: [PATCH 3/4] Remove resolved todo --- crates/bevy_sprite/src/render/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index d5d73f795d3f6..1a799999d4c3b 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -399,7 +399,6 @@ pub fn queue_sprites( let mut index = 0; let mut colored_index = 0; - // FIXME: VisibleEntities is ignored for (visible_entities, mut transparent_phase) in views.iter_mut() { let extracted_sprites = &mut extracted_sprites.sprites; let image_bind_groups = &mut *image_bind_groups; From 759c2926bbcbb044ba9b7b700fd310d83a6441f7 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 22 Feb 2022 09:07:43 +0100 Subject: [PATCH 4/4] Don't reallocate visible sprite entities map every frame --- crates/bevy_sprite/src/render/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 1a799999d4c3b..cc5c8d2a81f17 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -359,6 +359,7 @@ pub fn queue_sprites( mut extracted_sprites: ResMut, mut views: Query<(&VisibleEntities, &mut RenderPhase)>, events: Res, + mut visible_entities_map: Local>, ) { // If an image has changed, the GpuImage has (probably) changed for event in &events.images { @@ -403,7 +404,8 @@ pub fn queue_sprites( let extracted_sprites = &mut extracted_sprites.sprites; let image_bind_groups = &mut *image_bind_groups; - let visible_entities = HashSet::from_iter(visible_entities.iter().cloned()); + visible_entities_map.clear(); + visible_entities_map.extend(visible_entities.iter().copied()); transparent_phase.items.reserve(extracted_sprites.len()); @@ -433,7 +435,7 @@ pub fn queue_sprites( // Batches are merged later (in `batch_phase_system()`), so that they can be interrupted // by any other phase item (and they can interrupt other items from batching). for extracted_sprite in extracted_sprites.iter() { - if !visible_entities.contains(&extracted_sprite.entity) { + if !visible_entities_map.contains(&extracted_sprite.entity) { continue; } let new_batch = SpriteBatch {