bevy/crates/bevy_render/src
charlotte dd812b3e49
Type safe retained render world (#15756)
# Objective

In the Render World, there are a number of collections that are derived
from Main World entities and are used to drive rendering. The most
notable are:
- `VisibleEntities`, which is generated in the `check_visibility` system
and contains visible entities for a view.
- `ExtractedInstances`, which maps entity ids to asset ids.

In the old model, these collections were trivially kept in sync -- any
extracted phase item could look itself up because the render entity id
was guaranteed to always match the corresponding main world id.

After #15320, this became much more complicated, and was leading to a
number of subtle bugs in the Render World. The main rendering systems,
i.e. `queue_material_meshes` and `queue_material2d_meshes`, follow a
similar pattern:

```rust
for visible_entity in visible_entities.iter::<With<Mesh2d>>() {
    let Some(mesh_instance) = render_mesh_instances.get_mut(visible_entity) else {
        continue;
    };
            
    // Look some more stuff up and specialize the pipeline...
            
    let bin_key = Opaque2dBinKey {
        pipeline: pipeline_id,
        draw_function: draw_opaque_2d,
        asset_id: mesh_instance.mesh_asset_id.into(),
        material_bind_group_id: material_2d.get_bind_group_id().0,
    };
    opaque_phase.add(
        bin_key,
        *visible_entity,
        BinnedRenderPhaseType::mesh(mesh_instance.automatic_batching),
    );
}
```

In this case, `visible_entities` and `render_mesh_instances` are both
collections that are created and keyed by Main World entity ids, and so
this lookup happens to work by coincidence. However, there is a major
unintentional bug here: namely, because `visible_entities` is a
collection of Main World ids, the phase item being queued is created
with a Main World id rather than its correct Render World id.

This happens to not break mesh rendering because the render commands
used for drawing meshes do not access the `ItemQuery` parameter, but
demonstrates the confusion that is now possible: our UI phase items are
correctly being queued with Render World ids while our meshes aren't.

Additionally, this makes it very easy and error prone to use the wrong
entity id to look up things like assets. For example, if instead we
ignored visibility checks and queued our meshes via a query, we'd have
to be extra careful to use `&MainEntity` instead of the natural
`Entity`.

## Solution

Make all collections that are derived from Main World data use
`MainEntity` as their key, to ensure type safety and avoid accidentally
looking up data with the wrong entity id:

```rust
pub type MainEntityHashMap<V> = hashbrown::HashMap<MainEntity, V, EntityHash>;
```

Additionally, we make all `PhaseItem` be able to provide both their Main
and Render World ids, to allow render phase implementors maximum
flexibility as to what id should be used to look up data.

You can think of this like tracking at the type level whether something
in the Render World should use it's "primary key", i.e. entity id, or
needs to use a foreign key, i.e. `MainEntity`.

## Testing

##### TODO:

This will require extensive testing to make sure things didn't break!
Additionally, some extraction logic has become more complicated and
needs to be checked for regressions.

## Migration Guide

With the advent of the retained render world, collections that contain
references to `Entity` that are extracted into the render world have
been changed to contain `MainEntity` in order to prevent errors where a
render world entity id is used to look up an item by accident. Custom
rendering code may need to be changed to query for `&MainEntity` in
order to look up the correct item from such a collection. Additionally,
users who implement their own extraction logic for collections of main
world entity should strongly consider extracting into a different
collection that uses `MainEntity` as a key.

Additionally, render phases now require specifying both the `Entity` and
`MainEntity` for a given `PhaseItem`. Custom render phases should ensure
`MainEntity` is available when queuing a phase item.
2024-10-10 18:47:04 +00:00
..
batching Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00
camera Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00
diagnostic Ensure Bevy's rendering byte usage is little-endian (#15750) 2024-10-08 22:43:35 +00:00
mesh Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
primitives Migrate cameras to required components (#15641) 2024-10-05 01:59:52 +00:00
render_graph Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
render_phase Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00
render_resource Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
renderer Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
texture Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
view Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00
alpha.rs Simpler lint fixes: makes ci lints work but disables a lint for now (#15376) 2024-09-24 11:42:59 +00:00
color_operations.wgsl move wgsl color operations from bevy_pbr to bevy_render (#13209) 2024-05-04 10:30:23 +00:00
extract_component.rs Remove Handle<T> trait implementations that are dependent on Component (#15749) 2024-10-09 17:12:27 +00:00
extract_instances.rs Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00
extract_param.rs Synchronize removed components with the render world (#15582) 2024-10-08 22:23:17 +00:00
extract_resource.rs Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
globals.rs Refactor App and SubApp internals for better separation (#9202) 2024-03-31 03:16:10 +00:00
globals.wgsl Refactor Globals and View structs into separate shaders (#7512) 2023-02-11 17:55:18 +00:00
gpu_component_array_buffer.rs Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
gpu_readback.rs Synchronize removed components with the render world (#15582) 2024-10-08 22:23:17 +00:00
lib.rs Synchronize removed components with the render world (#15582) 2024-10-08 22:23:17 +00:00
maths.wgsl add tonemapping LUT bindings for sprite and mesh2d pipelines (#13262) 2024-05-28 12:09:26 +00:00
pipelined_rendering.rs Synchronize removed components with the render world (#15582) 2024-10-08 22:23:17 +00:00
render_asset.rs Remove thiserror from bevy_render (#15765) 2024-10-09 14:26:28 +00:00
settings.rs Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
spatial_bundle.rs Clearer spatial bundle pub const docs (#14293) 2024-07-15 16:03:09 +00:00
storage.rs Simpler lint fixes: makes ci lints work but disables a lint for now (#15376) 2024-09-24 11:42:59 +00:00
sync_component.rs Synchronize removed components with the render world (#15582) 2024-10-08 22:23:17 +00:00
sync_world.rs Type safe retained render world (#15756) 2024-10-10 18:47:04 +00:00