From 74d52768e1b38ca30ea48ea9f1533844a95fcf86 Mon Sep 17 00:00:00 2001 From: james7132 Date: Wed, 4 May 2022 18:04:21 -0700 Subject: [PATCH 01/14] Make ComputedVisibility a bitset resource --- crates/bevy_pbr/src/bundle.rs | 5 +- crates/bevy_pbr/src/light.rs | 30 +++------- crates/bevy_pbr/src/render/mesh.rs | 24 ++++---- crates/bevy_render/Cargo.toml | 1 + crates/bevy_render/src/camera/mod.rs | 2 +- crates/bevy_render/src/render_component.rs | 7 ++- crates/bevy_render/src/view/visibility/mod.rs | 59 +++++++++++-------- crates/bevy_sprite/src/mesh2d/material.rs | 5 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 7 ++- examples/2d/mesh2d_manual.rs | 8 +-- examples/shader/animate_shader.rs | 3 +- examples/shader/shader_defs.rs | 2 - examples/shader/shader_instancing.rs | 3 +- examples/stress_tests/many_cubes.rs | 8 ++- 14 files changed, 81 insertions(+), 83 deletions(-) diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index c42ce981b95bd..c0755d5885f91 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -5,7 +5,7 @@ use bevy_reflect::Reflect; use bevy_render::{ mesh::Mesh, primitives::{CubemapFrusta, Frustum}, - view::{ComputedVisibility, Visibility, VisibleEntities}, + view::{Visibility, VisibleEntities}, }; use bevy_transform::components::{GlobalTransform, Transform}; @@ -21,8 +21,6 @@ pub struct MaterialMeshBundle { pub global_transform: GlobalTransform, /// User indication of whether an entity is visible pub visibility: Visibility, - /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub computed_visibility: ComputedVisibility, } impl Default for MaterialMeshBundle { @@ -33,7 +31,6 @@ impl Default for MaterialMeshBundle { transform: Default::default(), global_transform: Default::default(), visibility: Default::default(), - computed_visibility: Default::default(), } } } diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 5140eae18af18..af96c425e382a 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -1233,6 +1233,7 @@ pub fn update_point_light_frusta( pub fn check_light_mesh_visibility( visible_point_lights: Query<&VisiblePointLights>, + mut computed_visibility: ResMut, mut point_lights: Query<( &PointLight, &GlobalTransform, @@ -1247,11 +1248,10 @@ pub fn check_light_mesh_visibility( Option<&RenderLayers>, &Visibility, )>, - mut visible_entity_query: Query< + visible_entity_query: Query< ( Entity, &Visibility, - &mut ComputedVisibility, Option<&RenderLayers>, Option<&Aabb>, Option<&GlobalTransform>, @@ -1272,14 +1272,8 @@ pub fn check_light_mesh_visibility( let view_mask = maybe_view_mask.copied().unwrap_or_default(); - for ( - entity, - visibility, - mut computed_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_transform, - ) in visible_entity_query.iter_mut() + for (entity, visibility, maybe_entity_mask, maybe_aabb, maybe_transform) in + visible_entity_query.iter() { if !visibility.is_visible { continue; @@ -1297,7 +1291,7 @@ pub fn check_light_mesh_visibility( } } - computed_visibility.is_visible = true; + computed_visibility.mark_visible(entity); visible_entities.entities.push(entity); } @@ -1331,14 +1325,8 @@ pub fn check_light_mesh_visibility( radius: point_light.range, }; - for ( - entity, - visibility, - mut computed_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_transform, - ) in visible_entity_query.iter_mut() + for (entity, visibility, maybe_entity_mask, maybe_aabb, maybe_transform) in + visible_entity_query.iter() { if !visibility.is_visible { continue; @@ -1361,12 +1349,12 @@ pub fn check_light_mesh_visibility( .zip(cubemap_visible_entities.iter_mut()) { if frustum.intersects_obb(aabb, &model_to_world, true) { - computed_visibility.is_visible = true; + computed_visibility.mark_visible(entity); visible_entities.entities.push(entity); } } } else { - computed_visibility.is_visible = true; + computed_visibility.mark_visible(entity); for visible_entities in cubemap_visible_entities.iter_mut() { visible_entities.entities.push(entity); } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 2ccc6fde6c37d..158a35ea17047 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -22,7 +22,7 @@ use bevy_render::{ render_resource::{std140::AsStd140, *}, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, - view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, + view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, RenderApp, RenderStage, }; use bevy_transform::components::GlobalTransform; @@ -94,33 +94,32 @@ bitflags::bitflags! { } pub fn extract_meshes( + computed_visibility: Res, mut commands: Commands, mut previous_caster_len: Local, mut previous_not_caster_len: Local, caster_query: Query< ( Entity, - &ComputedVisibility, &GlobalTransform, &Handle, Option<&NotShadowReceiver>, ), - Without, + (With, Without), >, not_caster_query: Query< ( Entity, - &ComputedVisibility, &GlobalTransform, &Handle, Option<&NotShadowReceiver>, ), - With, + (With, With), >, ) { let mut caster_values = Vec::with_capacity(*previous_caster_len); - for (entity, computed_visibility, transform, handle, not_receiver) in caster_query.iter() { - if !computed_visibility.is_visible { + for (entity, transform, handle, not_receiver) in caster_query.iter() { + if !computed_visibility.is_visible(entity) { continue; } let transform = transform.compute_matrix(); @@ -144,8 +143,8 @@ pub fn extract_meshes( commands.insert_or_spawn_batch(caster_values); let mut not_caster_values = Vec::with_capacity(*previous_not_caster_len); - for (entity, computed_visibility, transform, mesh, not_receiver) in not_caster_query.iter() { - if !computed_visibility.is_visible { + for (entity, transform, mesh, not_receiver) in not_caster_query.iter() { + if !computed_visibility.is_visible(entity) { continue; } let transform = transform.compute_matrix(); @@ -217,7 +216,8 @@ impl SkinnedMeshJoints { } pub fn extract_skinned_meshes( - query: Query<(Entity, &ComputedVisibility, &SkinnedMesh)>, + computed_visibility: Res, + query: Query<(Entity, &SkinnedMesh)>, inverse_bindposes: Res>, joint_query: Query<&GlobalTransform>, mut commands: Commands, @@ -228,8 +228,8 @@ pub fn extract_skinned_meshes( let mut joints = Vec::with_capacity(*previous_joint_len); let mut last_start = 0; - for (entity, computed_visibility, skin) in query.iter() { - if !computed_visibility.is_visible { + for (entity, skin) in query.iter() { + if !computed_visibility.is_visible(entity) { continue; } // PERF: This can be expensive, can we move this to prepare? diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index df6230dca6d07..ba5c0b86fa64f 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -67,3 +67,4 @@ flate2 = { version = "1.0.22", optional = true } ruzstd = { version = "0.2.4", optional = true } # For transcoding of UASTC/ETC1S universal formats, and for .basis file support basis-universal = { version = "0.2.0", optional = true } +fixedbitset = "0.4" diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index bf1d1d5d8c101..ba368bf1adb12 100644 --- a/crates/bevy_render/src/camera/mod.rs +++ b/crates/bevy_render/src/camera/mod.rs @@ -22,7 +22,6 @@ impl Plugin for CameraPlugin { fn build(&self, app: &mut App) { app.register_type::() .register_type::() - .register_type::() .register_type::() .register_type::() .register_type::() @@ -32,6 +31,7 @@ impl Plugin for CameraPlugin { .register_type::() .register_type::() .register_type::() + .init_resource::() .add_system_to_stage( CoreStage::PostUpdate, crate::camera::camera_system::.after(ModifiesWindows), diff --git a/crates/bevy_render/src/render_component.rs b/crates/bevy_render/src/render_component.rs index 7cd3158cb94d7..3427ca985e0c3 100644 --- a/crates/bevy_render/src/render_component.rs +++ b/crates/bevy_render/src/render_component.rs @@ -194,13 +194,14 @@ fn extract_components( /// This system extracts all visible components of the corresponding [`ExtractComponent`] type. fn extract_visible_components( + computed_visibility: Res, mut commands: Commands, mut previous_len: Local, - mut query: StaticSystemParam, C::Query), C::Filter>>, + mut query: StaticSystemParam>, ) { let mut values = Vec::with_capacity(*previous_len); - for (entity, computed_visibility, query_item) in query.iter_mut() { - if computed_visibility.is_visible { + for (entity, query_item) in query.iter_mut() { + if computed_visibility.is_visible(entity) { values.push((entity, (C::extract_component(query_item),))); } } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 478c635572dc9..043ef36215ce4 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -5,11 +5,13 @@ pub use render_layers::*; use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; +use bevy_ecs::entity::Entities; use bevy_ecs::prelude::*; use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; use bevy_transform::TransformSystem; +use fixedbitset::FixedBitSet; use crate::{ camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection}, @@ -31,15 +33,30 @@ impl Default for Visibility { } /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering -#[derive(Component, Clone, Reflect, Debug)] -#[reflect(Component)] +#[derive(Default, Debug)] pub struct ComputedVisibility { - pub is_visible: bool, + entities: FixedBitSet, } -impl Default for ComputedVisibility { - fn default() -> Self { - Self { is_visible: true } +impl ComputedVisibility { + #[inline] + pub fn mark_visible(&mut self, entity: Entity) { + self.entities.insert(entity.id() as usize); + } + + #[inline] + pub fn is_visible(&self, entity: Entity) -> bool { + self.entities.contains(entity.id() as usize) + } + + #[inline] + pub fn reserve(&mut self, entities: &Entities) { + self.entities.grow(entities.len() as usize); + } + + #[inline] + pub fn clear(&mut self) { + self.entities.clear(); } } @@ -140,24 +157,21 @@ pub fn update_frusta( } pub fn check_visibility( + entities: &Entities, mut view_query: Query<(&mut VisibleEntities, &Frustum, Option<&RenderLayers>), With>, - mut visible_entity_query: ParamSet<( - Query<&mut ComputedVisibility>, - Query<( - Entity, - &Visibility, - &mut ComputedVisibility, - Option<&RenderLayers>, - Option<&Aabb>, - Option<&NoFrustumCulling>, - Option<&GlobalTransform>, - )>, + mut computed_visibility: ResMut, + visible_entity_query: Query<( + Entity, + &Visibility, + Option<&RenderLayers>, + Option<&Aabb>, + Option<&NoFrustumCulling>, + Option<&GlobalTransform>, )>, ) { // Reset the computed visibility to false - for mut computed_visibility in visible_entity_query.p0().iter_mut() { - computed_visibility.is_visible = false; - } + computed_visibility.clear(); + computed_visibility.reserve(entities); for (mut visible_entities, frustum, maybe_view_mask) in view_query.iter_mut() { visible_entities.entities.clear(); @@ -166,12 +180,11 @@ pub fn check_visibility( for ( entity, visibility, - mut computed_visibility, maybe_entity_mask, maybe_aabb, maybe_no_frustum_culling, maybe_transform, - ) in visible_entity_query.p1().iter_mut() + ) in visible_entity_query.iter() { if !visibility.is_visible { continue; @@ -201,7 +214,7 @@ pub fn check_visibility( } } - computed_visibility.is_visible = true; + computed_visibility.mark_visible(entity); visible_entities.entities.push(entity); } diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 77cb3c4ebe92f..3e2fb6a69ae4e 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -24,7 +24,7 @@ use bevy_render::{ SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines, }, renderer::RenderDevice, - view::{ComputedVisibility, Msaa, Visibility, VisibleEntities}, + view::{Msaa, Visibility, VisibleEntities}, RenderApp, RenderStage, }; use bevy_transform::components::{GlobalTransform, Transform}; @@ -375,8 +375,6 @@ pub struct MaterialMesh2dBundle { pub global_transform: GlobalTransform, /// User indication of whether an entity is visible pub visibility: Visibility, - /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub computed_visibility: ComputedVisibility, } impl Default for MaterialMesh2dBundle { @@ -387,7 +385,6 @@ impl Default for MaterialMesh2dBundle { transform: Default::default(), global_transform: Default::default(), visibility: Default::default(), - computed_visibility: Default::default(), } } } diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 47c4efbbb2c1c..7504990ca6a4c 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -88,13 +88,14 @@ bitflags::bitflags! { } pub fn extract_mesh2d( + computed_visibility: Res, mut commands: Commands, mut previous_len: Local, - query: Query<(Entity, &ComputedVisibility, &GlobalTransform, &Mesh2dHandle)>, + query: Query<(Entity, &GlobalTransform, &Mesh2dHandle)>, ) { let mut values = Vec::with_capacity(*previous_len); - for (entity, computed_visibility, transform, handle) in query.iter() { - if !computed_visibility.is_visible { + for (entity, transform, handle) in query.iter() { + if !computed_visibility.is_visible(entity) { continue; } let transform = transform.compute_matrix(); diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index 201e32571f561..d38247d8f7081 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -99,7 +99,6 @@ fn star( Transform::default(), GlobalTransform::default(), Visibility::default(), - ComputedVisibility::default(), )); commands // And use an orthographic projection @@ -277,13 +276,14 @@ impl Plugin for ColoredMesh2dPlugin { /// Extract the [`ColoredMesh2d`] marker component into the render app pub fn extract_colored_mesh2d( + computed_visibility: Res, mut commands: Commands, mut previous_len: Local, - query: Query<(Entity, &ComputedVisibility), With>, + query: Query, With)>, ) { let mut values = Vec::with_capacity(*previous_len); - for (entity, computed_visibility) in query.iter() { - if !computed_visibility.is_visible { + for entity in query.iter() { + if !computed_visibility.is_visible(entity) { continue; } values.push((entity, (ColoredMesh2d,))); diff --git a/examples/shader/animate_shader.rs b/examples/shader/animate_shader.rs index 2af1d34b85bf8..12dd1067c4096 100644 --- a/examples/shader/animate_shader.rs +++ b/examples/shader/animate_shader.rs @@ -15,7 +15,7 @@ use bevy::{ }, render_resource::*, renderer::{RenderDevice, RenderQueue}, - view::{ComputedVisibility, ExtractedView, Msaa, Visibility}, + view::{ExtractedView, Msaa, Visibility}, RenderApp, RenderStage, }, }; @@ -36,7 +36,6 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { GlobalTransform::default(), CustomMaterial, Visibility::default(), - ComputedVisibility::default(), )); // camera diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 5be3ad6267822..eb214a3055e57 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -62,7 +62,6 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { Transform::from_xyz(-1.0, 0.5, 0.0), GlobalTransform::default(), Visibility::default(), - ComputedVisibility::default(), )); // blue cube @@ -72,7 +71,6 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { Transform::from_xyz(1.0, 0.5, 0.0), GlobalTransform::default(), Visibility::default(), - ComputedVisibility::default(), )); // camera diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 5698c3325b829..53391a317cd62 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -14,7 +14,7 @@ use bevy::{ }, render_resource::*, renderer::RenderDevice, - view::{ComputedVisibility, ExtractedView, Msaa, NoFrustumCulling, Visibility}, + view::{ExtractedView, Msaa, NoFrustumCulling, Visibility}, RenderApp, RenderStage, }, }; @@ -44,7 +44,6 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { .collect(), ), Visibility::default(), - ComputedVisibility::default(), // NOTE: Frustum culling is done based on the Aabb of the Mesh and the GlobalTransform. // As the cube is at the origin, if its Aabb moves outside the view frustum, all the // instanced cubes will be culled. diff --git a/examples/stress_tests/many_cubes.rs b/examples/stress_tests/many_cubes.rs index 82f9519e20a09..9d8b398a43cf4 100644 --- a/examples/stress_tests/many_cubes.rs +++ b/examples/stress_tests/many_cubes.rs @@ -141,9 +141,10 @@ fn move_camera(time: Res