Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Change check_visibility to use thread-local queues instead of a channel #4663

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions crates/bevy_pbr/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -21,8 +21,6 @@ pub struct MaterialMeshBundle<M: SpecializedMaterial> {
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<M: SpecializedMaterial> Default for MaterialMeshBundle<M> {
Expand All @@ -33,7 +31,6 @@ impl<M: SpecializedMaterial> Default for MaterialMeshBundle<M> {
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
computed_visibility: Default::default(),
}
}
}
Expand Down
30 changes: 9 additions & 21 deletions crates/bevy_pbr/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,7 @@ pub fn update_point_light_frusta(

pub fn check_light_mesh_visibility(
visible_point_lights: Query<&VisiblePointLights>,
mut computed_visibility: ResMut<ComputedVisibility>,
mut point_lights: Query<(
&PointLight,
&GlobalTransform,
Expand All @@ -1250,11 +1251,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>,
Expand All @@ -1275,14 +1275,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;
Expand All @@ -1300,7 +1294,7 @@ pub fn check_light_mesh_visibility(
}
}

computed_visibility.is_visible = true;
computed_visibility.mark_visible(entity);
visible_entities.entities.push(entity);
}

Expand Down Expand Up @@ -1334,14 +1328,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;
Expand All @@ -1364,12 +1352,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);
}
Expand Down
24 changes: 12 additions & 12 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bevy_render::{
texture::{
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
},
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility},
RenderApp, RenderStage,
};
use bevy_transform::components::GlobalTransform;
Expand Down Expand Up @@ -115,33 +115,32 @@ bitflags::bitflags! {
}

pub fn extract_meshes(
computed_visibility: Res<ComputedVisibility>,
mut commands: Commands,
mut previous_caster_len: Local<usize>,
mut previous_not_caster_len: Local<usize>,
caster_query: Query<
(
Entity,
&ComputedVisibility,
&GlobalTransform,
&Handle<Mesh>,
Option<&NotShadowReceiver>,
),
Without<NotShadowCaster>,
(With<Visibility>, Without<NotShadowCaster>),
>,
not_caster_query: Query<
(
Entity,
&ComputedVisibility,
&GlobalTransform,
&Handle<Mesh>,
Option<&NotShadowReceiver>,
),
With<NotShadowCaster>,
(With<Visibility>, With<NotShadowCaster>),
>,
) {
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();
Expand All @@ -165,8 +164,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();
Expand Down Expand Up @@ -238,7 +237,8 @@ impl SkinnedMeshJoints {
}

pub fn extract_skinned_meshes(
query: Query<(Entity, &ComputedVisibility, &SkinnedMesh)>,
computed_visibility: Res<ComputedVisibility>,
query: Query<(Entity, &SkinnedMesh)>,
inverse_bindposes: Res<Assets<SkinnedMeshInverseBindposes>>,
joint_query: Query<&GlobalTransform>,
mut commands: Commands,
Expand All @@ -249,8 +249,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?
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ bitflags = "1.2.1"
smallvec = { version = "1.6", features = ["union", "const_generics"] }
once_cell = "1.4.1" # TODO: replace once_cell with std equivalent if/when this lands: https://github.com/rust-lang/rfcs/pull/2788
downcast-rs = "1.2.0"
thread_local = "1.1"
thiserror = "1.0"
futures-lite = "1.4.0"
crossbeam-channel = "0.5.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only needed for the parallel system. We don't need it anymore, so it's been removed.

anyhow = "1.0"
hex = "0.4.2"
hexasphere = "7.0.0"
Expand All @@ -70,4 +70,5 @@ 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 }
encase = { version = "0.2", features = ["glam"] }
fixedbitset = "0.4"
encase = { version = "0.2", features = ["glam"] }
james7132 marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 3 additions & 1 deletion crates/bevy_render/src/camera/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
app.register_type::<Camera>()
.register_type::<Visibility>()
.register_type::<ComputedVisibility>()
.register_type::<OrthographicProjection>()
.register_type::<PerspectiveProjection>()
james7132 marked this conversation as resolved.
Show resolved Hide resolved
.register_type::<VisibleEntities>()
.register_type::<WindowOrigin>()
.register_type::<ScalingMode>()
.register_type::<DepthCalculation>()
.register_type::<Aabb>()
.init_resource::<ComputedVisibility>()
.register_type::<CameraRenderGraph>()
.add_plugin(CameraProjectionPlugin::<Projection>::default())
.add_plugin(CameraProjectionPlugin::<OrthographicProjection>::default())
Expand Down
7 changes: 4 additions & 3 deletions crates/bevy_render/src/extract_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,14 @@ fn extract_components<C: ExtractComponent>(

/// This system extracts all visible components of the corresponding [`ExtractComponent`] type.
fn extract_visible_components<C: ExtractComponent>(
computed_visibility: Res<ComputedVisibility>,
mut commands: Commands,
mut previous_len: Local<usize>,
mut query: StaticSystemParam<Query<(Entity, Read<ComputedVisibility>, C::Query), C::Filter>>,
mut query: StaticSystemParam<Query<(Entity, C::Query), C::Filter>>,
) {
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),)));
}
}
Expand Down
76 changes: 58 additions & 18 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ 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 std::cell::Cell;
use thread_local::ThreadLocal;

use crate::{
camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection, Projection},
Expand All @@ -31,15 +35,36 @@ 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) {
james7132 marked this conversation as resolved.
Show resolved Hide resolved
self.entities.grow(entities.meta_len() as usize);
}

#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.entities.count_ones(..)
}

#[inline]
pub fn clear(&mut self) {
self.entities.clear();
}
}

Expand Down Expand Up @@ -148,38 +173,44 @@ pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(
}

pub fn check_visibility(
entities: &Entities,
mut thread_queues: Local<ThreadLocal<Cell<Vec<Entity>>>>,
mut view_query: Query<(&mut VisibleEntities, &Frustum, Option<&RenderLayers>), With<Camera>>,
mut visible_entity_query: Query<(
mut computed_visibility: ResMut<ComputedVisibility>,
visible_entity_query: Query<(
Entity,
&Visibility,
&mut ComputedVisibility,
Option<&RenderLayers>,
Option<&Aabb>,
Option<&NoFrustumCulling>,
Option<&GlobalTransform>,
)>,
) {
// Reset the computed visibility to false
computed_visibility.clear();
computed_visibility.reserve(entities);

for queue in thread_queues.iter_mut() {
queue.get_mut().clear();
james7132 marked this conversation as resolved.
Show resolved Hide resolved
}

for (mut visible_entities, frustum, maybe_view_mask) in view_query.iter_mut() {
let view_mask = maybe_view_mask.copied().unwrap_or_default();
let (visible_entity_sender, visible_entity_receiver) = crossbeam_channel::unbounded();

visible_entity_query.par_for_each_mut(
visible_entities.entities.clear();
visible_entity_query.par_for_each(
1024,
|(
entity,
visibility,
mut computed_visibility,
maybe_entity_mask,
maybe_aabb,
maybe_no_frustum_culling,
maybe_transform,
)| {
// Reset visibility
computed_visibility.is_visible = false;

if !visibility.is_visible {
return;
}

let entity_mask = maybe_entity_mask.copied().unwrap_or_default();
if !view_mask.intersects(&entity_mask) {
return;
Expand All @@ -204,10 +235,19 @@ pub fn check_visibility(
}
}

computed_visibility.is_visible = true;
visible_entity_sender.send(entity).ok();
let cell = thread_queues.get_or_default();
let mut queue = cell.take();
queue.push(entity);
cell.set(queue);
},
);
visible_entities.entities = visible_entity_receiver.try_iter().collect();

for cell in thread_queues.iter_mut() {
let queue = cell.get_mut();
for entity in queue.iter().copied() {
computed_visibility.mark_visible(entity);
}
visible_entities.entities.append(queue);
}
}
}
5 changes: 1 addition & 4 deletions crates/bevy_sprite/src/mesh2d/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -375,8 +375,6 @@ pub struct MaterialMesh2dBundle<M: SpecializedMaterial2d> {
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<M: SpecializedMaterial2d> Default for MaterialMesh2dBundle<M> {
Expand All @@ -387,7 +385,6 @@ impl<M: SpecializedMaterial2d> Default for MaterialMesh2dBundle<M> {
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
computed_visibility: Default::default(),
}
}
}
Loading