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

Remove the type parameter from check_visibility, and only invoke it once. #16812

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

pcwalton
Copy link
Contributor

Currently, check_visibility is parameterized over a query filter that specifies the type of potentially-visible object. This has the unfortunate side effect that we need a separate system, mark_view_visibility_as_changed_if_necessary, to trigger view visibility change detection. That system is quite slow because it must iterate sequentially over all entities in the scene.

This PR moves the query filter from check_visibility to a new component, VisibilityClass. VisibilityClass stores a list of type IDs, each corresponding to one of the query filters we used to use. Because check_visibility is no longer specialized to the query filter at the type level, Bevy now only needs to invoke it once, leading to better performance as check_visibility can do change detection on the fly rather than delegating it to a separate system.

This commit also has ergonomic improvements, as there's no need for applications that want to add their own custom renderable components to add specializations of the check_visibility system to the schedule. Instead, they only need to ensure that the ViewVisibility component is properly kept up to date. The recommended way to do this, and the way that's demonstrated in the custom_phase_item and specialized_mesh_pipeline examples, is to make ViewVisibility a required component and to add the type ID to it in a component add hook. This patch does this for Mesh3d, Mesh2d, Sprite, Light, and Node, which means that most app code doesn't need to change at all.

Note that, although this patch has a large impact on the performance of visibility determination, it doesn't actually improve the end-to-end frame time of many_cubes. That's because the render world was already effectively hiding the latency from
mark_view_visibility_as_changed_if_necessary. This patch is, however, necessary for further improvements to many_cubes performance.

many_cubes trace before:
Screenshot 2024-12-13 015318

many_cubes trace after:
Screenshot 2024-12-13 145735

Migration Guide

  • check_visibility no longer takes a QueryFilter, and there's no need to add it manually to your app schedule anymore for custom rendering items. Instead, entities with custom renderable components should add the appropriate type IDs to VisibilityClass. See custom_phase_item for an example.

once.

Currently, `check_visibility` is parameterized over a query filter that
specifies the type of potentially-visible object. This has the
unfortunate side effect that we need a separate system,
`mark_view_visibility_as_changed_if_necessary`, to trigger view
visibility change detection. That system is quite slow because it must
iterate sequentially over all entities in the scene.

This PR moves the query filter from `check_visibility` to a new
component, `VisibilityClass`. `VisibilityClass` stores a list of type
IDs, each corresponding to one of the query filters we used to use.
Because `check_visibility` is no longer specialized to the query filter
at the type level, Bevy now only needs to invoke it once, leading to
better performance as `check_visibility` can do change detection on the
fly rather than delegating it to a separate system.

This commit also has ergonomic improvements, as there's no need for
applications that want to add their own custom renderable components to
add specializations of the `check_visibility` system to the schedule.
Instead, they only need to ensure that the `ViewVisibility` component is
properly kept up to date. The recommended way to do this, and the way
that's demonstrated in the `custom_phase_item` and
`specialized_mesh_pipeline` examples, is to make `ViewVisibility` a
required component and to add the type ID to it in a component add hook.
This patch does this for `Mesh3d`, `Mesh2d`, `Sprite`, `Light`, and
`Node`, which means that most app code doesn't need to change at all.

Note that, although this patch has a large impact on the performance of
visibility determination, it doesn't actually improve the end-to-end
frame time of `many_cubes`. That's because the render world was already
effectively hiding the latency from
`mark_view_visibility_as_changed_if_necessary`. This patch is, however,
necessary for *further* improvements to `many_cubes` performance.
@pcwalton pcwalton added the A-Rendering Drawing game state to the screen label Dec 14, 2024
@pcwalton pcwalton added this to the 0.16 milestone Dec 14, 2024
@pcwalton pcwalton added C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 14, 2024
/// add-component hook that adds the type ID of that component to the
/// [`VisibilityClass`] array. See `custom_phase_item` for an example.
#[derive(Clone, Component, Default, Reflect, Deref, DerefMut)]
pub struct VisibilityClass(pub SmallVec<[TypeId; 1]>);
Copy link
Contributor

Choose a reason for hiding this comment

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

How much more work would it be to store ComponentId instead of TypeId? The former would be more introspect-able.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ItsDoot I just tried it, and unfortunately it's not really possible because those IDs get fed into the render world, and component IDs are per-world.

@JMS55
Copy link
Contributor

JMS55 commented Dec 14, 2024

@pcwalton need to do the same for MeshletMesh3d, conditionally when the MeshletPlugin is loaded.

@pcwalton
Copy link
Contributor Author

@JMS55 Good point, added meshlet support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants