Skip to content

Commit 87cc932

Browse files
james7132ItsDoot
authored andcommitted
Shrink ComputedVisibility (bevyengine#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 bevyengine#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 f01fa89 commit 87cc932

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)