Commit Graph

2 Commits

Author SHA1 Message Date
DavidCrossman 7c77ecd576 Fix documentation typos (#24446)
# Objective

Fix typos and other small issues in the documentation. I can drop the
changes to `bevy_reflect`'s and `bevy_anti_alias`'s crate descriptions
if it's a problem.
2026-06-02 00:52:42 +00:00
Jenya705 b842bcb923 Contiguous access (#21984)
# Objective

Enables accessing slices from tables directly via Queries.

Fixes: #21861 

## Solution

One new trait:
- `ContiguousQueryData` allows to fetch all values from tables all at
once (an implementation for `&T` returns a slice of components in the
set table, for `&mut T` returns a mutable slice of components in the set
table as well as a struct with methods to set update ticks (to match the
`fetch` implementation))

Methods `contiguous_iter`, `contiguous_iter_mut` and similar in `Query`
and `QueryState` making possible to iterate using these traits.

Macro `QueryData` was updated to support contiguous items when
`contiguous(target)` attribute is added (a target can be `all`,
`mutable` and `immutable`, refer to the `custom_query_param` example)

## Testing

- `sparse_set_contiguous_query` test verifies that you can't use
`next_contiguous` with sparse set components
- `test_contiguous_query_data` test verifies that returned values are
valid
- `base_contiguous` benchmark (file is named
`iter_simple_contiguous.rs`)
- `base_no_detection` benchmark (file is named
`iter_simple_no_detection.rs`)
- `base_no_detection_contiguous` benchmark (file is named
`iter_simple_no_detection_contiguous.rs`)
- `base_contiguous_avx2` benchmark (file is named
`iter_simple_contiguous_avx2.rs`)

---

## Showcase

Examples `contiguous_query`, `custom_query_param`

### Example
```rust
// - self.0 is a World
// - self.1 is a QueryState
// - velocity is a slice of components with Vec3 inside.
// - position is a data structure which implements Deref/DerefMut and IntoIterator methods to access the slice
// as well as mechanism to update update ticks (which it does automatically on dereference), 
// which may be bypassed via `bypass_change_detection` methods.
for (velocity, mut position) in self.1.contiguous_iter_mut(&mut self.0).unwrap() {
    assert!(velocity.len() == position.len());
    for (v, p) in velocity.iter().zip(position.iter_mut()) {
        p.0 += v.0;
    }
}
```

### Benchmarks
Code for `base` benchmark:
```rust
#[derive(Component, Copy, Clone)]
struct Transform(Mat4);

#[derive(Component, Copy, Clone)]
struct Position(Vec3);

#[derive(Component, Copy, Clone)]
struct Rotation(Vec3);

#[derive(Component, Copy, Clone)]
struct Velocity(Vec3);

pub struct Benchmark<'w>(World, QueryState<(&'w Velocity, &'w mut Position)>);

impl<'w> Benchmark<'w> {
    pub fn new() -> Self {
        let mut world = World::new();

        world.spawn_batch(core::iter::repeat_n(
            (
                Transform(Mat4::from_scale(Vec3::ONE)),
                Position(Vec3::X),
                Rotation(Vec3::X),
                Velocity(Vec3::X),
            ),
            10_000,
        ));

        let query = world.query::<(&Velocity, &mut Position)>();
        Self(world, query)
    }

    #[inline(never)]
    pub fn run(&mut self) {
        for (velocity, mut position) in self.1.iter_mut(&mut self.0) {
            position.0 += velocity.0;
        }
    }
}
```
Iterating over 10000 entities from **a single** table and increasing a
3-dimensional vector from component `Position` by a 3-dimensional vector
from component `Velocity`

| Name | Time | Time (AVX2) | Description |

|------------------------------|-----------|-------------|--------------------------------------------------------------------|
| base | 5.5828 µs | 5.5122 µs | Iteration over components |
| base_contiguous | 4.8825 µs | 1.8665 µs | Iteration over contiguous
chunks |
| base_contiguous_avx2 | 2.0740 µs | 1.8665 µs | Iteration over
contiguous chunks with enforced avx2 optimizations |
| base_no_detection | 4.8065 µs | 4.7723 µs | Iteration over components
while bypassing change detection through `bypass_change_detection()`
method |
| base_no_detection_contiguous | 4.3979 µs | 1.5797 µs | Iteration over
components without registering update ticks |

Using contiguous 'iterator' makes the program a little bit faster and it
can be further vectorized to make it even faster
2026-02-03 00:02:26 +00:00