Skip to content

Commit 342f69e

Browse files
committed
Shrink ComputedVisibility (#6305)
# Objective `ComputedVisibility` could afford to be smaller/faster. Optimizing the size and performance of operations on the component will positively benefit almost all extraction systems. This was listed as one of the potential pieces of future work for #5310. ## Solution Merge both internal booleans into a single `u8` bitflag field. Rely on bitmasks to evaluate local, hierarchical, and general visibility. Pros: - `ComputedVisibility::is_visible` should be a single bitmask test instead of two. - `ComputedVisibility` is now only 1 byte. Should be able to fit 100% more per cache line when using dense iteration. Cons: - Harder to read. - Setting individual values inside `ComputedVisiblity` require bitmask mutations. This should be a non-breaking change. No public API was changed. The only publicly visible effect is that `ComputedVisibility` is now 1 byte instead of 2.
1 parent 8ebd4d9 commit 342f69e

File tree

1 file changed

+33
-17
lines changed
  • crates/bevy_render/src/view/visibility

1 file changed

+33
-17
lines changed

crates/bevy_render/src/view/visibility/mod.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,19 @@ impl Visibility {
5454
}
5555
}
5656

57+
bitflags::bitflags! {
58+
#[derive(Reflect)]
59+
struct ComputedVisibilityFlags: u8 {
60+
const VISIBLE_IN_VIEW = 1 << 0;
61+
const VISIBLE_IN_HIERARCHY = 1 << 1;
62+
}
63+
}
64+
5765
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
5866
#[derive(Component, Clone, Reflect, Debug, Eq, PartialEq)]
5967
#[reflect(Component, Default)]
6068
pub struct ComputedVisibility {
61-
is_visible_in_hierarchy: bool,
62-
is_visible_in_view: bool,
69+
flags: ComputedVisibilityFlags,
6370
}
6471

6572
impl Default for ComputedVisibility {
@@ -71,8 +78,7 @@ impl Default for ComputedVisibility {
7178
impl ComputedVisibility {
7279
/// A [`ComputedVisibility`], set as invisible.
7380
pub const INVISIBLE: Self = ComputedVisibility {
74-
is_visible_in_hierarchy: false,
75-
is_visible_in_view: false,
81+
flags: ComputedVisibilityFlags::empty(),
7682
};
7783

7884
/// Whether this entity is visible to something this frame. This is true if and only if [`Self::is_visible_in_hierarchy`] and [`Self::is_visible_in_view`]
@@ -81,7 +87,7 @@ impl ComputedVisibility {
8187
/// [`CoreStage::Update`] stage will yield the value from the previous frame.
8288
#[inline]
8389
pub fn is_visible(&self) -> bool {
84-
self.is_visible_in_hierarchy && self.is_visible_in_view
90+
self.flags.bits == ComputedVisibilityFlags::all().bits
8591
}
8692

8793
/// Whether this entity is visible in the entity hierarchy, which is determined by the [`Visibility`] component.
@@ -90,7 +96,8 @@ impl ComputedVisibility {
9096
/// [`VisibilitySystems::VisibilityPropagate`] system label.
9197
#[inline]
9298
pub fn is_visible_in_hierarchy(&self) -> bool {
93-
self.is_visible_in_hierarchy
99+
self.flags
100+
.contains(ComputedVisibilityFlags::VISIBLE_IN_HIERARCHY)
94101
}
95102

96103
/// Whether this entity is visible in _any_ view (Cameras, Lights, etc). Each entity type (and view type) should choose how to set this
@@ -102,7 +109,8 @@ impl ComputedVisibility {
102109
/// Other entities might just set this to `true` every frame.
103110
#[inline]
104111
pub fn is_visible_in_view(&self) -> bool {
105-
self.is_visible_in_view
112+
self.flags
113+
.contains(ComputedVisibilityFlags::VISIBLE_IN_VIEW)
106114
}
107115

108116
/// Sets `is_visible_in_view` to `true`. This is not reversible for a given frame, as it encodes whether or not this is visible in
@@ -111,7 +119,16 @@ impl ComputedVisibility {
111119
/// label. Don't call this unless you are defining a custom visibility system. For normal user-defined entity visibility, see [`Visibility`].
112120
#[inline]
113121
pub fn set_visible_in_view(&mut self) {
114-
self.is_visible_in_view = true;
122+
self.flags.insert(ComputedVisibilityFlags::VISIBLE_IN_VIEW);
123+
}
124+
125+
#[inline]
126+
fn reset(&mut self, visible_in_hierarchy: bool) {
127+
self.flags = if visible_in_hierarchy {
128+
ComputedVisibilityFlags::VISIBLE_IN_HIERARCHY
129+
} else {
130+
ComputedVisibilityFlags::empty()
131+
};
115132
}
116133
}
117134

@@ -280,13 +297,12 @@ fn visibility_propagate_system(
280297
children_query: Query<&Children, (With<Parent>, With<Visibility>, With<ComputedVisibility>)>,
281298
) {
282299
for (children, visibility, mut computed_visibility, entity) in root_query.iter_mut() {
283-
computed_visibility.is_visible_in_hierarchy = visibility.is_visible;
284300
// reset "view" visibility here ... if this entity should be drawn a future system should set this to true
285-
computed_visibility.is_visible_in_view = false;
301+
computed_visibility.reset(visibility.is_visible);
286302
if let Some(children) = children {
287303
for child in children.iter() {
288304
let _ = propagate_recursive(
289-
computed_visibility.is_visible_in_hierarchy,
305+
computed_visibility.is_visible_in_hierarchy(),
290306
&mut visibility_query,
291307
&children_query,
292308
*child,
@@ -313,10 +329,10 @@ fn propagate_recursive(
313329
child_parent.get(), expected_parent,
314330
"Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
315331
);
316-
computed_visibility.is_visible_in_hierarchy = visibility.is_visible && parent_visible;
332+
let visible_in_hierarchy = visibility.is_visible && parent_visible;
317333
// reset "view" visibility here ... if this entity should be drawn a future system should set this to true
318-
computed_visibility.is_visible_in_view = false;
319-
computed_visibility.is_visible_in_hierarchy
334+
computed_visibility.reset(visible_in_hierarchy);
335+
visible_in_hierarchy
320336
};
321337

322338
for child in children_query.get(entity).map_err(drop)?.iter() {
@@ -390,7 +406,7 @@ pub fn check_visibility(
390406
}
391407
}
392408

393-
computed_visibility.is_visible_in_view = true;
409+
computed_visibility.set_visible_in_view();
394410
let cell = thread_queues.get_or_default();
395411
let mut queue = cell.take();
396412
queue.push(entity);
@@ -412,7 +428,7 @@ pub fn check_visibility(
412428
return;
413429
}
414430

415-
computed_visibility.is_visible_in_view = true;
431+
computed_visibility.set_visible_in_view();
416432
let cell = thread_queues.get_or_default();
417433
let mut queue = cell.take();
418434
queue.push(entity);
@@ -518,7 +534,7 @@ mod test {
518534
.entity(e)
519535
.get::<ComputedVisibility>()
520536
.unwrap()
521-
.is_visible_in_hierarchy
537+
.is_visible_in_hierarchy()
522538
};
523539
assert!(
524540
!is_visible(root1),

0 commit comments

Comments
 (0)