Commit Graph

373 Commits

Author SHA1 Message Date
Visse 6f270d4776 Expose pipeline constants to materials (#24502)
# Objective

Allow materials to use pipeline constants ([pipeline-overridable
constants](https://www.w3.org/TR/WGSL/#override-decls)).
They are already available in wgpu, but bevy didn't expose them.

## Solution

Expose constants in `RenderPipelineDescriptor` &
`ComputePipelineDescriptor`, allowing materials to specify them in their
specilize function.

**Note:** I had to remove the `Eq` derive from
`ComputePipelineDescriptor`, `VertexState` and `FragmentState`, due to
the new f64 field. It was already a bit inconsistent with
`RenderPipelineDescriptor` not having it.

## Testing
- Ran `cargo check`
- Created an example & ran it
- Couldn't run `cargo test` due to it taking looots of disk space to
run, but I have a hard time seeing it break something at runtime

## Showcase

See the added example, where pipeline constants are used to change the
`LEVELS` override in WGSL.
<img width="760" height="289" alt="Screenshot from 2026-05-31 09-46-05"
src="https://github.com/user-attachments/assets/6902757c-aea4-4b91-9ff0-e653ce4c3448"
/>
2026-06-09 00:06:01 +00:00
charlotte 🌸 d1b1980733 Add ReadbackOnce component to help one-shot readbacks. (#23845)
Users are sometimes confused about the fact that the `Readback`
component will fire multiple observers (once per every frame it exists
in the main world). This new `ReadbackOnce` component helps a bit with
the ux of spawning a readback that only fires once.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2026-05-22 13:41:31 +00:00
Luo Zhihao d5a0cf4f1e Change ShaderDefVal to use Cow<'static, str> (#24209)
# Objective

Fixes #24036

## Solution

Replace String with Cow<'static, str> in ShaderDefVal.

## Testing

CI
2026-05-21 14:34:41 +00:00
andriyDev 61127f6d01 Replace all different load variants in AssetServer with a builder. (#23663)
# Objective

- In 0.18, we had 10 different functions that load assets (I'm not even
counting `load_folder`).
- In 0.19, we've even added `load_erased` - but it unfortunately doesn't
support all the features that the other variants support.
- We apparently needed `load_acquire_with_settings_override` which 1)
loads the asset, 2) uses the settings provided, 3) allows reading
unapproved asset paths, and 4) drops a guard once the load completes.
- That's fine if that's necessary. But we needed to create an explicit
variant for that.
- We need fewer load paths!

## Solution

- Create a builder.
- Store all these options dynamically instead of statically handling
each case.
- Have the caller choose a particular "kind" of load when they are
ready: `load`, `load_erased`, `load_untyped`, or `load_untyped_async`.
- I intentionally didn't provide a `load_async` or `load_erased_async`,
since those can be replicated using `load`/`load_erased` +
`AssetServer::wait_for_asset_id` to get the exact same effect.

I am also intentionally leaving `NestedLoader` untouched in this PR, but
a followup will duplicate this API for `NestedLoader`, which should make
it easier to understand.

Unlike the `NestedLoader` API, we aren't doing any type-state craziness,
so the docs are much more clear: users don't need to understand how
type-state stuff works, they just call the handful of methods on the
type. The "cost" here is we now need to be careful about including the
cross product of loads between static asset type, runtime asset type, or
dynamic asset type, crossed with deferred or async. In theory, if we
added more kinds on either side, we would need to expand this cross
product a lot. In practice though, it seems unlikely there will be any
more variants there. (maybe there could be a blocking variant? I don't
think this is a popular opinion though).

A big con here is some somewhat common calls are now more verbose.
Specifically, `asset_server.load_with_settings()` has become
`asset_server.load_builder().with_settings().load()`. I am not really
concerned about this though, since it really isn't that painful.

## Testing

- Tests all pass!

---

## Showcase

Now instead of:

```rust
asset_server.load_acquire_with_settings_override("some_path", |settings: &mut GltfLoaderSettings| { ... }, my_lock_guard);
```

You can instead do:

```rust
asset_server.load_builder()
    .with_guard(my_lock_guard)
    .with_settings(|settings: &mut GltfLoaderSettings| { ... })
    .override_unapproved()
    .load("some_path");
```

We also now cover more variants! For example, you can now load an asset
untyped with a guard, or with override_unapproved, etc.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-15 18:32:25 +00:00
Jordan Halase 5e1630bfd8 Fix 16 byte alignment typo (WebGL 2: 16 bit -> 16 byte) (#23124)
# Objective

WebGL 2 requires 16 **byte** UBO alignment. Some comments incorrectly
state 16 **bits**.

## Solution

Fix comment typos.

## Testing

N/A

---

## Showcase

N/A
2026-02-24 00:51:54 +00:00
Rostyslav Lesovyi 9fd2637846 Add tools to avoid unnecessary AssetEvent::Modified events that lead to rendering performance costs (#16751) (#22460)
# Objective

- Fixes #16751

## Solution

- `Assets::get_mut` now returns a wrapper `AssetMut` type instead of
`&mut impl Asset`.
- `AssetMut` implements `Deref` and `DerefMut`.
- `DerefMut` marks assets as changed.
- when dropped `AssetMut` will add `AssetEvent::Modified` event to a
queue only in case asset was marked as changed.

## Testing

- Did you test these changes? If so, how?
  - No unit tests were added, change is pretty straightforward.
  - Test project: https://github.com/MatrixDev/bevy-feature-16751-test.
    - With change: ~100 fps.
    - Without change: ~15 fps.
- Are there any parts that need more testing?
- I don't really see how this can break anything or add a measurable
overhead.
- `AssetEvent::Modified` will now be sent after the asset was modified
instead of before. It should not affect anything but still worth noting.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Have a big amount of entities that constantly update their materials.
- Properties of those materials should be animated in a stepped maned
(like changing color every 0.1 seconds).
  - Update material only if value has actually changed:
```rust
if material.base_color != new_color {
    material.base_color = new_color;
}
```
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - tested on macos (Mackbook M1)
  - not a platform-specific issue

PS: This is my first PR, so please don’t judge.
2026-02-10 18:39:37 +00:00
charlotte 🌸 f1f41547fc Replace RenderGraph with systems (#22144)
# render-graph-as-systems

> [!NOTE]
> Remember to check hide whitespace in diff view options when reviewing
this PR

This PR removes the `RenderGraph` in favor of using systems.

## Motivation

The `RenderGraph` API was originally created when the ECS was
significantly more immature. It was also created with the intention of
supporting an input/output based slot system for managing resources that
has never been used. While resource management is an important potential
use of a render graph, current rendering code doesn't make use of any
patterns relating to it.

Since the ECS has improved, the functionality of `Schedule` has
basically become co-extensive with what the `RenderGraph` API is doing,
i.e. ordering bits of system-like logic relative to one another and
executing them in a big chunk. Additionally, while there's still desire
for more advanced techniques like resource management in the graph, it's
desirable to implement those in ECS terms rather than creating more
`RenderGraph` specific abstraction.

In short, this sets us up to iterate on a more ECS based approach, while
deleting ~3k lines of mostly unused code.

## Implementation

At a high level: We use `Schedule` as our "sub-graph." Rather than
running the graph, we run a schedule. Systems can be ordered relative to
one another.

The render system uses a `RenderGraph` schedule to define the "root" of
the graph. `core_pipeline` adds a `camera_driver` system that runs the
per-camera schedules. This top level schedule provides an extension
point for apps that may want to do custom rendering, or non-camera
rendering.

### `CurrentView` / `ViewQuery`

When running schedules per-camera in the `camera_driver` system, we
insert a `CurrentView` resource that's used to mark the currently
iterating view. We also add a new param `ViewQuery` that internally uses
this resource to execute the query and skip the system if it doesn't
match as a convenience.

### `RenderContext`

The `RenderContext` is now a system param that wraps a `Deferred` for
tracking the state of the current command encoder and queued buffers.

### `SystemBuffer`

We use an system buffer impl to track command encoders in the render
context and rely on apply deferred in order to encode them all.
Currently, this encodes them in series. There are likely opportunities
here to make this more efficient.

## Benchmarks

### Bistro

<img width="1635" height="825" alt="Screenshot 2026-01-15 at 7 57 40 PM"
src="https://github.com/user-attachments/assets/8e55a959-89a3-4947-bfc5-c04780f82e7b"
/>

### Caldera

<img width="1631" height="828" alt="Screenshot 2026-01-15 at 8 13 06 PM"
src="https://github.com/user-attachments/assets/e7e8ae0d-41c3-430f-8b4d-9099b3d922a0"
/>

## Future steps

There are a number of exciting potential changes that could follow here:

- We can explore adding something like a read-only schedule to pick up
some more potential parallelism in graph execution.
- We can use more things like run conditions in order to prevent systems
from running at all in the first place.
- We can explore things like automating resource creation via system
params.

## TODO:
- [x] Make sure 100% of everything still works.
- [x] Benchmark to make sure we don't regress performance
- [x] Re-add docs

---------

Co-authored-by: atlas dostal <rodol@rivalrebels.com>
2026-01-28 21:09:59 +00:00
charlotte 🌸 b8d756d4de Rename ShaderStorageBuffer -> ShaderBuffer. (#22558)
The original name is inaccurate since you can provide whatever usages
you want. As we make the renderer more modular and flexible, especially
if we develop a compute abstraction, having an easy way to bind things
like vertex buffers could be desirable.

I'd *really* like to just call this `Buffer` to keep it short and sweet,
but I know that proved controversial in the original PR.
2026-01-17 00:36:51 +00:00
Aevyrie a88af65738 Contact Shadows (#22382)
# Objective

- Implement contact shadows to add fine shadow detail where shadow
cascades cannot.

## Solution

- Extend our existing pbr implementation using our existing raymarching
functions.

---

## Showcase

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/e93b79c5-c596-4a9e-b94d-20bdde1d863b"
/>

<img width="1824" height="1180" alt="image"
src="https://github.com/user-attachments/assets/0fd7dffa-60b8-4b92-8fad-7f993d4d89dd"
/>


https://github.com/user-attachments/assets/e74b190d-9ae3-4aaf-97f0-b520930a0667


https://github.com/user-attachments/assets/e80ccb26-bbaa-4d25-a823-8ea12354c5b9


https://github.com/user-attachments/assets/b04f4b00-92bd-4a2f-b7dd-5157d8fbe0ab

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/b7629908-dd32-48db-8ee7-a4d2dd8f66c2"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3de0258e-9191-4180-ac57-41b32e1205bd"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/951477f9-e9a9-426f-ae8d-18ae50cc7b85"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/2291453c-da57-4fcc-a6b0-f60f6eac6cbb"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/5820cdff-ea54-4294-b520-2a8d8dc24996"
/>

<img width="1073" height="685" alt="image"
src="https://github.com/user-attachments/assets/3ea16481-7689-4e99-87e2-1589f1532e4c"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
2026-01-13 21:51:39 +00:00
atlv ff376dea7c bevy_material (#22426)
# Objective

- extract material infrastructure to be usable for scene description
without a renderer
- rework of #21543 on top of #22408, you can view a clean diff here:
https://github.com/tychedelia/bevy/compare/type-erase-more-materials...atlv24:ad/material2?expand=1
- this is the culmination of numerous crate splits and refactors leading
up to this point, and the another step towards shared 2d and 3d
rendering infrastructure deduplication.

## Solution

- new crate bevy_material with MaterialProperties struct that lets one
define when a material draws, how it behaves, what shaders it uses,
specialization functions, and bind group layouts expected.

## Testing

---------

Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
Co-authored-by: Daniel Skates <zeophlite@gmail.com>
2026-01-13 21:41:06 +00:00
atlv e64f04f824 clean up shader cache errors (#22362)
# Objective

- Name error type more accurately, its about the shader cache not
pipeline cache.
- Put naga error in Box to make type smaller and clippy happy

## Solution

- do it

## Testing

- examples run
2026-01-13 17:36:43 +00:00
Jan Hohenheim 9737c3076c Fix copy-pasting mistake in extended material bindless example (#22373)
# Objective

- The docs are a bit weird, which is probably due to someone at some
point accidentally copy-pasting the wgsl correspondence code

## Solution

- Write the actual code
- Also use our fancy `#{MATERIAL_BIND_GROUP}` in the docs, given that
it's used in the shader :)
- Split the line a liiiiittle bit differently

## Testing

- None, just docs. Well, I did make sure that the stuff in the docs is
the same as in the shader!

---------

Co-authored-by: Nico Zweifel <34443492+NicoZweifel@users.noreply.github.com>
2026-01-05 02:06:01 +00:00
Luo Zhihao 2e9ef6988c Fix non-srgb RenderTarget::Image (#22090)
# Objective

Fixes
https://github.com/bevyengine/bevy/pull/22031#issuecomment-3640036590.
Fixes #15201.
#22031 makes `ViewTarget::out_texture_format` to return the underlying
texture’s format, which causes some issues:
1. `ExtractedWindow::swap_chain_texture_view` always uses srgb view. But
the underlying swap chain texture in WebGPU can be Bgra8unorm, leading
to format mismatch between the render pipeline and the render pass.
2. We can no longer use srgb view for non-srgb target texture, it will
panic due to incompatible pipeline:
```rs
    let mut image = Image::new_target_texture(512, 512, TextureFormat::Rgba8Unorm);
    image.texture_view_descriptor = Some(bevy_render::render_resource::TextureViewDescriptor {
        format: Some(TextureFormat::Rgba8UnormSrgb),
        ..Default::default()
    });
    image.texture_descriptor.view_formats = &[TextureFormat::Rgba8UnormSrgb];
```

## Solution

Reverts #22031.
Renames some `format` to `view_format` explicitly.
Adds `view_format` to `GpuImage` and `Image::new_target_texture` so we
can make render pipeline match render pass texture view.

## Testing
Tested `render_to_texture` and `screenshot` examples on linux and
webgpu.
<details>
<summary>The rendered Rgba8Unorm texture with or without srgb view in
MeshMaterial3d looks the same, but the underlaying data is
different:</summary>

With srgb view:
<img width="912" height="640" alt="屏幕截图_20251212_223355"
src="https://github.com/user-attachments/assets/d320bad9-d11a-4d3d-93a9-879af6413658"
/>

Without srgb view:
<img width="912" height="640" alt="屏幕截图_20251212_223313"
src="https://github.com/user-attachments/assets/522abf23-9c85-468d-8d17-a94495ee4452"
/>

</details>
2025-12-14 21:39:02 +00:00
mgi388 d60a1b8166 Add MeshTag to array_texture example to demonstrate layer selection in shader (#21989)
## Objective

- When looking at the `array_texture` example, it wasn't clear to me how
I could send the "layer" to the GPU, but it turns out that [MeshTag is
one recommended
way](https://discord.com/channels/691052431525675048/866787577687310356/1444495450999754823)
to pass this.
- The example previously extracted a fake "layer" from the world
position, but IIUC this isn't the most realistic way to demonstrate
layer selection.

## Solution

- Update the `array_texture` example by using `MeshTag`.
- Add a system to the example that periodically changes the `MeshTag` on
entities to show that the mesh tag can also change dynamically at
runtime (and show how easy it is).

## Testing and showcase

Before, you can see each cube's texture is fixed.

<img width="1280" height="747" alt="image"
src="https://github.com/user-attachments/assets/1ffde7db-8110-4431-b4e8-3a5a4ba5c5db"
/>

After, you can see each cube's texture changes as time passes.


https://github.com/user-attachments/assets/b1227659-5886-4d2c-a401-84b80423c798

----

I'm hoping for a rendering dev to validate this approach is correct, and
useful. I think it is, but [I'm only just starting to
understand](https://discord.com/channels/691052431525675048/866787577687310356/1444888786478829668)
how to use this stuff and it's [possibly not the only
way](https://discord.com/channels/691052431525675048/866787577687310356/1444888304020488365)
so I don't want to submit this if it's the wrong approach to teach
future me's.
2025-12-09 23:38:23 +00:00
Rob Grindeland 0451082bc3 Add a setting to ImageLoader that calls Image::reinterpret_stacked_2d_as_array (#21628)
# Objective

If you want to use a `TilemapChunk` (or more generally use a
`texture2DArray` in a shader), you have to implement a mechanism that
waits for your texture to load, then calls
`Image::reinterpret_stacked_2d_as_array`.

## Solution

Have the loader do it instead.

Closes #20799, which does very similar things and should be remade if
more functionality is needed.

## Testing

- Ran the updated examples

---

## Showcase

```rs
let array_texture = asset_server.load_with_settings(
    "textures/array_texture.png",
    |settings: &mut ImageLoaderSettings| {
        settings.array_layout = Some(ImageArrayLayout::RowCount(4));
    },
);
```
2025-10-29 20:39:08 +00:00
Daniel Skates adf8211f79 Add BindGroupLayout caching via descriptors (#21205)
# Objective

- Defer creating `BindGroupLayout` by using a
`BindGroupLayoutDescriptor` and cache the results
- Unblocks `bevy_material` (render-less material definitions)
- Blocked by https://github.com/bevyengine/bevy/pull/21533

## Solution

- Reviewers, look at first commit for mechanism, and following for usage

## Testing

- CI

---------

Co-authored-by: atlas <email@atlasdostal.com>
2025-10-17 00:53:35 +00:00
Bude 15de74cc10 Image::reinterpret_size and Image::reinterpret_stacked_2d_as_array now return a Result (#20797)
# Objective

Remove panics from image reinterpretation methods.

## Solution

Introduce new errors and emit those instead of panicking.

## Testing

- Did you test these changes? If so, how?
  - CI + changed examples
- Are there any parts that need more testing?
  - No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - examples, no
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  - linux, amd cpu, amd gpu

---

Moved out of #20536

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-10-06 18:56:03 +00:00
Emerson Coskey 560ffd7bcb make Prepass/ShadowsEnabled methods on Material (#20999)
# Objective

- enabling prepass/shadows should be done like the rest of a material's
properties

## Solution

- remove `Prepass/ShadowsEnabled` resources and associated fields on
`MaterialPlugin`
- add `Material::enable_prepass` and `Material::enable_shadows`
2025-10-01 19:24:46 +00:00
TheBlckbird 13877fa84d Add a new trait to accept more types in the Val-helper functions (#20551)
# Objective

- Allow the `Val`-helper functions to accept more types besides just
`f32`

Fixes #20549

## Solution

- Adds a new trait that can be implemented for numbers
- That trait has a method that converts `self` to `f32`

## Testing

- I tested it using Rust's testing framework (although I didn't leave
the tests in, as I don't deem them important enough)

<details>
  <summary>Rust test</summary>

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_val_helpers_work() {
        let p = px(10_u8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_u128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i8);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i16);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i32);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i64);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10_i128);
        assert_eq!(p, Val::Px(10.0));

        let p = px(10.3_f32);
        assert_eq!(p, Val::Px(10.3));

        let p = px(10.6_f64);
        assert_eq!(p, Val::Px(10.6));
    }
}
```
</details>

---

## Showcase

```rust
// Same as Val::Px(10.)
px(10);
px(10_u8);
px(10.0);
```
2025-08-29 20:18:57 +00:00
Carter Anderson 5058f8a9e6 Improve On Terminology (#20648)
# Objective

Fixes #19263 (and expands on it)

Within `Observers`, we have started to distance ourselves from the
"trigger" terminology. Specifically, we have renamed `Trigger` to `On`.
I think this was a very good move, but we're currently in an awkward
middle ground state. Users interact with `On` as if it were an event:
`On<E>` exposes the event and derefs directly to it. I think we should
embrace this mindset fully, in the interest of clarity.

## Solution

- Rename all `trigger: On<SomeEvent>` cases to `event: On<SomeEvent>`.
- Rename `On::target` to `On::entity`. This reads _much_ better when
writing `query.get(event.entity())` and pairs more effectively with the
`EntityEvent` terminology.
- Rename `On::original_target` to `On::original_entity`, for the same
reasons.
- Take advantage of the `Deref` behavior where appropriate

```rust
// Before
entity.observe(|trigger: On<Explode>| {
  println!("{} exploded!", trigger.target());
})

// After
entity.observe(|event: On<Explode>| {
  println!("{} exploded!", event.entity());
})
```
2025-08-21 08:54:28 +00:00
BigWingBeat 121981b016 Remove redundant number conversion in window resolution (#20582)
# Objective

`WindowResolution` stores the width and height as `u32`, but the
constructors take `f32` and just convert straight to `u32`.
Additionally, everywhere in Bevy where a `WindowResolution` is
constructed specifies whole numbers, making the use of a float entirely
pointless.

## Solution

Replace the `f32` constructors with `u32` constructors.

I also decided to change the generic `I: Into<f32>` tuple and array
constructors to only take u32 instead of `I: Into<u32>` for UX reasons.
It allows formatting those constructors as `(1920, 1080).into()`, as the
compiler can infer that the numbers are u32. Keeping those impls generic
prevents that inference, and because the default number type (i32)
doesn't impl `Into<u32>`, that would require formatting it explicitly as
`(1920u32, 1080u32).into()` to compile.

In practice, these generic constructors were only used with whole-number
f32 values anyway, like everything else, so them being generic wasn't
actually leveraged anywhere.

## Testing

Chased type errors until they were all gone
2025-08-20 18:02:41 +00:00
charlotte 🌸 7cd2270ce8 Use boxed storage for material erasure. (#20614)
# Objective

#19667 added a `bytemuck::Pod` type constraint on `AsBindGroup::Data`
which, while technically a reasonable constraint to expect from material
keys, imposed a breaking change on our users which may be confusing /
difficult for them to work around. It's not technically invalid to store
arbitrary types in a material key, just probably bad practice.

Additionally, the performance concerns here were probably overstated: 1.
cold specialization makes re-specialization less likely. 2. we can
mitigate going through the vtable unnecessarily by pre-computing our
hash which should still make the boxed storage fast in almost all cases
where we don't get a collision.

## Solution

Use `Box<dyn Any>` for erasure.
2025-08-17 16:37:33 +00:00
Daniel Skates 9ee0aaafc5 Split out sprite rendering (#20587)
# Objective

- Split out `bevy_sprite_render` from `bevy_sprite` .

## Solution

- Do the thing

## Testing

- CI
- `cargo run --example sprite`
2025-08-15 22:41:05 +00:00
dontgetfoundout 5bc5a1325a Update Game of Life compute example to include a uniform buffer variable (#20466)
# Objective
It is currently a little unclear how to use uniform buffers in compute
shaders. The other examples of uniform buffers in the Bevy examples and
codebase either are built on Materials or use `DynamicUniformBuffer`s
created from a `ViewNode`. Neither of these are a great fit for use in a
compute shader.

## Solution
Update the compute shader example to pass a uniform buffer to the shader
that determines the color for alive cells.

## Discussion Topics
- Is this the right way to pass this data to the shader?
- Should we be encouraging use of uniform buffers in compute shaders at
all? Some in the community prefer the ergonomics of storage buffers in
most (all?) compute shader cases. Do we want to push users to use
storage buffers instead?
- I took the idea to use color as the input from IceSentry on Discord,
but this did require me to change the texture format to support non-red
colors. Does this undermine the goals of the shader example? Is this the
wrong texture format?

## Testing

- Did you test these changes? If so, how?
- The changes were manually validated with a number of different
`LinearRgba` values for `alive_color`
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
  - ` cargo run --example compute_shader_game_of_life`
- Color can be set using `alive_color` property on `GameOfLifeUniforms`
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
  -  Manually validated on Windows and WASM (WebGPU) targets
    - WASM WebGL2 doesn't appear to support textures in compute shaders

---

## Showcase
<img width="1602" height="939" alt="image"
src="https://github.com/user-attachments/assets/9a535617-a179-4f20-b686-596899f11d18"
/>

---------

Co-authored-by: dontgetfoundout <inflatedego@gmail.com>
2025-08-11 22:52:02 +00:00
atlv 68b848217f Yeet RenderAssetUsages re-export (#20498)
# Objective

- Forgor to yeet this

## Solution

- rember and yeet

## Testing

cargo check --examples --all-features
2025-08-11 01:42:08 +00:00
atlv 6eca318add Use bevy::shader in examples instead of bevy::render::shader re-export (#20492)
# Objective

- Prepare for removing re-exports
- Probably depends on #20491 merging first

## Solution

- title

## Testing

- cargo check --examples --all-features
2025-08-10 18:08:47 +00:00
atlv ce416c37a2 Use bevy::light in examples instead of bevy::pbr::light re-export (#20487)
# Objective

- Prepare for removing re-exports

## Solution

- title

## Testing

- cargo check --examples --all-features
2025-08-10 05:25:03 +00:00
atlv acc8f6d455 Stop using mesh re-exports in-repo and add bevy_mesh prelude (#20473)
# Objective

- prepare to remove bevy_mesh re-export from bevy_render. This will be
done in 0.18, but we might as well prepare for it now.

## Solution

- Add a prelude and use bevy_mesh directly. After this pr and #20471, we
will be ready.

## Testing

- cargo check --examples
2025-08-09 17:46:27 +00:00
Gonçalo Rica Pais da Silva ef845e0cea Update rand, glam and encase to latest versions (#18047)
# Objective

New `rand` version, which means updating `glam` and `encase` to support
the newer ecosystem update. Does mean that this changes how WASM builds
need to be done in order to configure `getrandom` correctly, but this
can be remedied with updated docs.

## Solution

Updating all needed dependencies to their compatible versions. ~~This PR
is currently blocked by `encase`, which is waiting on [this
PR](https://github.com/teoxoy/encase/pull/88) to be merged and then a
new version published.~~ ~~This PR is no longer blocked~~,
~~`hexasphere` is blocking this PR now due to not yet having a new
release with the latest `glam` version support~~, The PR is all good to
go now, everything in order across glam/rand deps.

## Testing

- Must pass CI for all checks, tests, not introduce breaking changes.

---

## Migration Guide

With newer versions of `glam` & `encase`, the updated versions don't
seem to have introduced breakages, though as always, best to consult
their docs [1](https://docs.rs/glam/latest/glam/)
[2](https://docs.rs/encase/0.11.0/encase/) for any changes.

`rand` changes are more extensive, with changes such as `thread_rng()`
-> `rng()`, `from_entropy()` -> `from_os_rng()`, and so forth. `RngCore`
is now split into infallible `RngCore` and fallible `TryRngCore`, and
the `distributions` module has been renamed to `distr`. Most of this
affects only internals, and doesn't directly affect Bevy's APIs. For the
full set of changes, see `rand` [migration
notes](https://rust-random.github.io/book/update-0.9.html).

`getrandom` is also updated, and will require additional configuration
when building Bevy for WASM/Web (if also using `rand`). The full details
of how to do this is in the `getrandom` docs
[1](https://github.com/rust-random/getrandom?tab=readme-ov-file#opt-in-backends)
[2](https://github.com/rust-random/getrandom?tab=readme-ov-file#webassembly-support).

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2025-08-09 02:09:10 +00:00
IceSentry 8a51d39bb9 Move advanced shader examples to separate category (#20415)
# Objective

- Some shader examples are much more complicated than others. It can be
confusing for new users that simple example and advanced examples are
next to each other

## Solution

- Introduce a new "shader_advanced" example category
- I'm open to other names, but I named it like that so both folders are
next to each other

## Testing

N/A

## Notes

We should maybe consider a different name than "shader" because some of
them aren't that much about shaders. It could be advanced_rendering or
something like that.

I'm opened to moving more example to this. I just picked the one that
felt the most advanced to me.

I didn't move the compute_game_of_life example because, while it is
complex, the complexity is unavoidable if you want to run a compute
shader right now. I also plan on simplifying it a bit and introduce a
plugin to make it much easier but as it is today I think it's okay to
stay there.
2025-08-05 18:51:45 +00:00
JMS55 b378e0ad97 MainPassResolutionOverride changes (#20403)
Lots of changes extracted from #19864.

I haven't added support for MainPassResolutionOverride to every
rendering feature yet. Mostly just Solari and some of the main passes as
a proof of concept.
2025-08-04 22:09:34 +00:00
charlotte 🌸 52bcffb217 Upgrade to wgpu version 26.0 (#19868)
# Objective

- Upgrading to the latest wgpu version is good for features, bug fixes
and performance improvements.
- Also fixes #19626.

## Solution

- Upgrade dependency version.

---------

Co-authored-by: atlas dostal <rodol@rivalrebels.com>
2025-08-02 17:10:14 +00:00
tigregalis 1b6e3f53fd Add Image constructor specialised for rendering to a texture (#17209)
# Objective

Fixes #7358
Redo of #7360

Ergonomics. There's a bunch of enigmatic boilerplate for constructing a
texture for rendering to, which could be greatly simplified for the
external user-facing API.

## Solution

- Take part of the render_to_target example and turn it into a new
constructor for `Image`, with minimal changes beyond the `Default`
implementation.
- Update the render_to_target example to use the new API.

Strictly speaking, there are two small differences between the
constructor and the example:

~~1. The example sets the `size` when initially constructing the
`Image`, then `resize`s, but `resize` sets the `size` anyway so we don't
need to do this extra step.~~

~~2. The example sets `Image.texture_descriptor.format` to
`TextureFormat::Bgra8UnormSrgb`, but the default impl sets this to
`TextureFormat::Rgba8UnormSrgb` via
`wgpu::TextureFormat::bevy_default()`. I don't know what sort of impact
this has, but it works on my machine.~~

I've deliberately chosen to only include `width` and `height` as
parameters, but maybe it makes sense for some of the other properties to
be exposed as parameters.

---

## Changelog

### Added

Added `Image::new_target_texture` constructor for simpler creation of
render target textures.

---

Notes:

- This is a re-do of https://github.com/bevyengine/bevy/pull/7360 -
there's some relevant discussion on code style there.
- The docs for the method want to refer to `bevy_render::camera::Camera`
and `bevy_render::camera::RenderTarget::Image`. `bevy_image` used to be
part of `bevy_render` and was split out in the past, and `bevy_image`
doesn't depend on `bevy_render`. What's the recommendation here?

---------

Co-authored-by: Antony <antony.m.3012@gmail.com>
2025-07-21 22:23:23 +00:00
andriyDev 69ea8edd07 Improve the naming of a couple systems in RenderStartup. (#20193)
# Objective

- Followup for a PR for #19887.
- Minor style fix.

## Solution

- Rename these two cases to better match other systems in
`RenderStartup`
2025-07-19 08:23:32 +00:00
andriyDev 2a5e9c1150 Switch most examples to use RenderStartup instead of finish and FromWorld. (#20124)
# Objective

- Progress towards #19887.
- I am avoiding dealing with the `occlusion_culling` example since it is
kinda annoying to resolve nicely (I will do so in another PR).

## Solution

- Rewrite these examples to replace FromWorld implementations with
systems and other resource changes with systems as well.

## Testing

- All the changed examples have been tested and still work.
2025-07-14 21:56:03 +00:00
Sven Niederberger 3ce2f46ae5 GpuReadbackPlugin: Allow reading only a part of a buffer (#20133)
# Objective

- So far only full buffer reads were supported. This adds the ability to
read a part of a buffer.

## Solution

- Allow passing in a start offset and a number of bytes to read when
creating the `Readback` component.
- I also removed the unused `src_start` and `dst_start` fields from
`ReadbackSource` as they were always 0.

## Testing

- Did you test these changes? If so, how?

I extended the example to also demonstrate partial reads.

- Are there any parts that need more testing?

Can't think of any.

- How can other people (reviewers) test your changes? Is there anything
specific they need to know?

Run the `gpu_readback` example. It now also reads and prints a partially
read buffer.

- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

Only tested on Linux.

---

## Showcase

Example output:

<details>
  <summary>Click to view showcase</summary>

```
2025-07-14T14:05:15.614876Z  INFO gpu_readback: Buffer [257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272]
2025-07-14T14:05:15.614921Z  INFO gpu_readback: Buffer range [261, 262, 263, 264, 265, 266, 267, 268]
2025-07-14T14:05:15.614937Z  INFO gpu_readback: Image [257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```

</details>
2025-07-14 21:01:16 +00:00
Gilles Henaux ca25a67d0d Fix the extended_material example on WebGL2 (#18812)
# Objective

- Fixes #13872 (also mentioned in #17167)

## Solution

- Added conditional padding fields to the shader uniform

## Alternatives

### 1- Use a UVec4

Replace the `u32` field in `MyExtension` by a `UVec4` and only use the
`x` coordinate.

(This was the original approach, but for consistency with the rest of
the codebase, separate padding fields seem to be preferred)

### 2- Don't fix it, unlist it

While the fix is quite simple, it does muddy the waters a tiny bit due
to `quantize_steps` now being a UVec4 instead of a simple u32. We could
simply remove this example from the examples that support WebGL2.

## Testing

- Ran the example locally on WebGL2 (and native Vulkan) successfully
2025-07-07 19:34:12 +00:00
charlotte 🌸 18712f31f9 Make render and compute pipeline descriptors defaultable. (#19903)
A few versions ago, wgpu made it possible to set shader entry point to
`None`, which will select the correct entry point in file where only a
single entrypoint is specified. This makes it possible to implement
`Default` for pipeline descriptors. This PR does so and attempts to
`..default()` everything possible.
2025-07-02 18:47:27 +00:00
andriyDev f95f42b44a Allow calling add_render_graph_node on World. (#19912)
# Objective

- This unblocks some work I am doing for #19887.

## Solution

- Rename `RenderGraphApp` to `RenderGraphExt`.
- Implement `RenderGraphExt` for `World`.
- Change `SubApp` and `App` to call the `World` impl.
2025-07-02 14:56:18 +00:00
andriyDev d05c435848 Replace Handle::Weak with Handle::Uuid. (#19896)
# Objective

- Progress towards #19024.

## Solution

- Remove `Handle::Weak`!

If users were relying on `Handle::Weak` for some purpose, they can
almost certainly replace it with raw `AssetId` instead. If they cannot,
they can make their own enum that holds either a Handle or an AssetId.
In either case, we don't need weak handles!

Sadly we still need Uuid handles since we rely on them for "default"
assets and "invalid" assets, as well as anywhere where a component wants
to impl default with a non-defaulted asset handle. One step at a time
though!
2025-07-02 14:40:35 +00:00
Emerson Coskey bdd3ef71b8 Composable Pipeline Specialization (#17373)
Currently, our specialization API works through a series of wrapper
structs and traits, which make things confusing to follow and difficult
to generalize.

This pr takes a different approach, where "specializers" (types that
implement `Specialize`) are composable, but "flat" rather than composed
of a series of wrappers. The key is that specializers don't *produce*
pipeline descriptors, but instead *modify* existing ones:

```rs
pub trait Specialize<T: Specializable> {
    type Key: SpecializeKey;
    
    fn specialize(
        &self, 
        key: Self::Key, 
        descriptor: &mut T::Descriptor
    ) -> Result<Canonical<Self::Key>, BevyError>;
}
```

This lets us use some derive magic to stick multiple specializers
together:

```rs
pub struct A;
pub struct B;

impl Specialize<RenderPipeline> for A { ... }
impl Specialize<RenderPipeline> for A { ... }

#[derive(Specialize)]
#[specialize(RenderPipeline)]
struct C {
    // specialization is applied in struct field order
    applied_first: A,
    applied_second: B,
}

type C::Key = (A::Key, B::Key);

```

This approach is much easier to understand, IMO, and also lets us
separate concerns better. Specializers can be placed in fully separate
crates/modules, and key computation can be shared as well.

The only real breaking change here is that since specializers only
modify descriptors, we need a "base" descriptor to work off of. This can
either be manually supplied when constructing a `Specializer` (the new
collection replacing `Specialized[Render/Compute]Pipelines`), or
supplied by implementing `HasBaseDescriptor` on a specializer. See
`examples/shader/custom_phase_item.rs` for an example implementation.

## Testing

- Did some simple manual testing of the derive macro, it seems robust.

---

## Showcase

```rs
#[derive(Specialize, HasBaseDescriptor)]
#[specialize(RenderPipeline)]
pub struct SpecializeMeshMaterial<M: Material> {
    // set mesh bind group layout and shader defs
    mesh: SpecializeMesh,
    // set view bind group layout and shader defs
    view: SpecializeView,
    // since type SpecializeMaterial::Key = (), 
    // we can hide it from the wrapper's external API
    #[key(default)]
    // defer to the GetBaseDescriptor impl of SpecializeMaterial, 
    // since it carries the vertex and fragment handles
    #[base_descriptor]
    // set material bind group layout, etc
    material: SpecializeMaterial<M>,
}

// implementation generated by the derive macro
impl <M: Material> Specialize<RenderPipeline> for SpecializeMeshMaterial<M> {
    type Key = (MeshKey, ViewKey);

    fn specialize(
        &self, 
        key: Self::Key, 
        descriptor: &mut RenderPipelineDescriptor
    ) -> Result<Canonical<Self::Key>, BevyError>  {
        let mesh_key = self.mesh.specialize(key.0, descriptor)?;
        let view_key = self.view.specialize(key.1, descriptor)?;
        let _ = self.material.specialize((), descriptor)?;
        Ok((mesh_key, view_key));
    }
}

impl <M: Material> HasBaseDescriptor<RenderPipeline> for SpecializeMeshMaterial<M> {
    fn base_descriptor(&self) -> RenderPipelineDescriptor {
        self.material.base_descriptor()
    }
}
```

---------

Co-authored-by: Tim Overbeek <158390905+Bleachfuel@users.noreply.github.com>
2025-07-01 01:32:44 +00:00
IceSentry 735eb88db9 Use RenderStartup in custom_post_processing example (#19886)
# Objective

- This example uses a FromWorld impl to initialize a resource on startup
- #19887

## Solution

- Use RenderStartup instead

## Testing

- The example still works as expected
2025-06-30 23:54:05 +00:00
charlotte 🌸 e6ba9a6d18 Type erased materials (#19667)
# Objective

Closes #18075

In order to enable a number of patterns for dynamic materials in the
engine, it's necessary to decouple the renderer from the `Material`
trait.

This opens the possibility for:
- Materials that aren't coupled to `AsBindGroup`.
- 2d using the underlying 3d bindless infrastructure.
- Dynamic materials that can change their layout at runtime.
- Materials that aren't even backed by a Rust struct at all.

## Solution

In short, remove all trait bounds from render world material systems and
resources. This means moving a bunch of stuff onto `MaterialProperties`
and engaging in some hacks to make specialization work. Rather than
storing the bind group data in `MaterialBindGroupAllocator`, right now
we're storing it in a closure on `MaterialProperties`. TBD if this has
bad performance characteristics.

## Benchmarks

- `many_cubes`:
`cargo run --example many_cubes --release --features=bevy/trace_tracy --
--vary-material-data-per-instance`:
![Screenshot 2025-06-26
235426](https://github.com/user-attachments/assets/10a0ee29-9932-4f91-ab43-33518b117ac5)

- @DGriffin91's Caldera
`cargo run --release --features=bevy/trace_tracy -- --random-materials`

![image](https://github.com/user-attachments/assets/ef91ba6a-8e88-4922-a73f-acb0af5b0dbc)


- @DGriffin91's Caldera with 20 unique material types (i.e.
`MaterialPlugin<M>`) and random materials per mesh
`cargo run --release --features=bevy/trace_tracy -- --random-materials`
![Screenshot 2025-06-27
000425](https://github.com/user-attachments/assets/9561388b-881d-46cf-8c3d-b15b3e9aedc7)


### TODO

- We almost certainly lost some parallelization from removing the type
params that could be gained back from smarter iteration.
- Test all the things that could have broken.
- ~Fix meshlets~

## Showcase

See [the
example](https://github.com/bevyengine/bevy/pull/19667/files#diff-9d768cfe1c3aa81eff365d250d3cbe5a63e8df63e81dd85f64c3c3cd993f6d94)
for a custom material implemented without the use of the `Material`
trait and thus `AsBindGroup`.


![image](https://github.com/user-attachments/assets/e3fcca7c-e04e-4a4e-9d89-39d697a9e3b8)

---------

Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2025-06-27 22:57:24 +00:00
charlotte 🌸 a0b90cd618 Resolution override (#19817)
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: atlv <email@atlasdostal.com>
2025-06-27 16:30:54 +00:00
charlotte 🌸 96dcbc5f8c Ugrade to wgpu version 25.0 (#19563)
# Objective

Upgrade to `wgpu` version `25.0`.

Depends on https://github.com/bevyengine/naga_oil/pull/121

## Solution

### Problem

The biggest issue we face upgrading is the following requirement:
> To facilitate this change, there was an additional validation rule put
in place: if there is a binding array in a bind group, you may not use
dynamic offset buffers or uniform buffers in that bind group. This
requirement comes from vulkan rules on UpdateAfterBind descriptors.

This is a major difficulty for us, as there are a number of binding
arrays that are used in the view bind group. Note, this requirement does
not affect merely uniform buffors that use dynamic offset but the use of
*any* uniform in a bind group that also has a binding array.

### Attempted fixes

The easiest fix would be to change uniforms to be storage buffers
whenever binding arrays are in use:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<uniform> lights: types::Lights;
#else
@group(0) @binding(0) var<storage> view: array<View>;
@group(0) @binding(1) var<storage> lights: array<types::Lights>;
#endif
```

This requires passing the view index to the shader so that we know where
to index into the buffer:

```wgsl
struct PushConstants {
    view_index: u32,
}

var<push_constant> push_constants: PushConstants;
```

Using push constants is no problem because binding arrays are only
usable on native anyway.

However, this greatly complicates the ability to access `view` in
shaders. For example:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
mesh_view_bindings::view.view_from_world[0].z
#else
mesh_view_bindings::view[mesh_view_bindings::view_index].view_from_world[0].z
#endif
```

Using this approach would work but would have the effect of polluting
our shaders with ifdef spam basically *everywhere*.

Why not use a function? Unfortunately, the following is not valid wgsl
as it returns a binding directly from a function in the uniform path.

```wgsl
fn get_view() -> View {
#if BINDING_ARRAYS_ARE_USED
    let view_index = push_constants.view_index;
    let view = views[view_index];
#endif
    return view;
}
```

This also poses problems for things like lights where we want to return
a ptr to the light data. Returning ptrs from wgsl functions isn't
allowed even if both bindings were buffers.

The next attempt was to simply use indexed buffers everywhere, in both
the binding array and non binding array path. This would be viable if
push constants were available everywhere to pass the view index, but
unfortunately they are not available on webgpu. This means either
passing the view index in a storage buffer (not ideal for such a small
amount of state) or using push constants sometimes and uniform buffers
only on webgpu. However, this kind of conditional layout infects
absolutely everything.

Even if we were to accept just using storage buffer for the view index,
there's also the additional problem that some dynamic offsets aren't
actually per-view but per-use of a setting on a camera, which would
require passing that uniform data on *every* camera regardless of
whether that rendering feature is being used, which is also gross.

As such, although it's gross, the simplest solution just to bump binding
arrays into `@group(1)` and all other bindings up one bind group. This
should still bring us under the device limit of 4 for most users.

### Next steps / looking towards the future

I'd like to avoid needing split our view bind group into multiple parts.
In the future, if `wgpu` were to add `@builtin(draw_index)`, we could
build a list of draw state in gpu processing and avoid the need for any
kind of state change at all (see
https://github.com/gfx-rs/wgpu/issues/6823). This would also provide
significantly more flexibility to handle things like offsets into other
arrays that may not be per-view.

### Testing

Tested a number of examples, there are probably more that are still
broken.

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
2025-06-26 19:41:47 +00:00
andriyDev a7fdd6fc6f Replace FULLSCREEN_SHADER_HANDLE with a FullscreenShader resource. (#19426)
# Objective

- Related to #19024.

## Solution

- Remove the `FULLSCREEN_SHADER_HANDLE` `weak_handle` with a resource
holding the shader handle.
- This also changes us from using `load_internal_asset` to
`embedded_asset`/`load_embedded_asset`.
- All uses have been migrated to clone the `FullscreenShader` resource
and use its `to_vertex_state` method.

## Testing

- `anti_aliasing` example still works.
- `bloom_3d` example still works.

---------

Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
2025-06-24 00:02:23 +00:00
theotherphil 7645ce91ed Add newlines before impl blocks (#19746)
# Objective

Fix https://github.com/bevyengine/bevy/issues/19617 

# Solution

Add newlines before all impl blocks.

I suspect that at least some of these will be objectionable! If there's
a desired Bevy style for this then I'll update the PR. If not then we
can just close it - it's the work of a single find and replace.
2025-06-22 23:07:02 +00:00
Chris Russell f7e112a3c9 Let query items borrow from query state to avoid needing to clone (#15396)
# Objective

Improve the performance of `FilteredEntity(Ref|Mut)` and
`Entity(Ref|Mut)Except`.

`FilteredEntityRef` needs an `Access<ComponentId>` to determine what
components it can access. There is one stored in the query state, but
query items cannot borrow from the state, so it has to `clone()` the
access for each row. Cloning the access involves memory allocations and
can be expensive.


## Solution

Let query items borrow from their query state.  

Add an `'s` lifetime to `WorldQuery::Item` and `WorldQuery::Fetch`,
similar to the one in `SystemParam`, and provide `&'s Self::State` to
the fetch so that it can borrow from the state.

Unfortunately, there are a few cases where we currently return query
items from temporary query states: the sorted iteration methods create a
temporary state to query the sort keys, and the
`EntityRef::components<Q>()` methods create a temporary state for their
query.

To allow these to continue to work with most `QueryData`
implementations, introduce a new subtrait `ReleaseStateQueryData` that
converts a `QueryItem<'w, 's>` to `QueryItem<'w, 'static>`, and is
implemented for everything except `FilteredEntity(Ref|Mut)` and
`Entity(Ref|Mut)Except`.

`#[derive(QueryData)]` will generate `ReleaseStateQueryData`
implementations that apply when all of the subqueries implement
`ReleaseStateQueryData`.

This PR does not actually change the implementation of
`FilteredEntity(Ref|Mut)` or `Entity(Ref|Mut)Except`! That will be done
as a follow-up PR so that the changes are easier to review. I have
pushed the changes as chescock/bevy#5.

## Testing

I ran performance traces of many_foxes, both against main and against
chescock/bevy#5, both including #15282. These changes do appear to make
generalized animation a bit faster:

(Red is main, yellow is chescock/bevy#5)

![image](https://github.com/user-attachments/assets/de900117-0c6a-431d-ab62-c013834f97a9)


## Migration Guide

The `WorldQuery::Item` and `WorldQuery::Fetch` associated types and the
`QueryItem` and `ROQueryItem` type aliases now have an additional
lifetime parameter corresponding to the `'s` lifetime in `Query`. Manual
implementations of `WorldQuery` will need to update the method
signatures to include the new lifetimes. Other uses of the types will
need to be updated to include a lifetime parameter, although it can
usually be passed as `'_`. In particular, `ROQueryItem` is used when
implementing `RenderCommand`.

Before: 

```rust
fn render<'w>(
    item: &P,
    view: ROQueryItem<'w, Self::ViewQuery>,
    entity: Option<ROQueryItem<'w, Self::ItemQuery>>,
    param: SystemParamItem<'w, '_, Self::Param>,
    pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult;
```

After: 

```rust
fn render<'w>(
    item: &P,
    view: ROQueryItem<'w, '_, Self::ViewQuery>,
    entity: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
    param: SystemParamItem<'w, '_, Self::Param>,
    pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult;
```

---

Methods on `QueryState` that take `&mut self` may now result in
conflicting borrows if the query items capture the lifetime of the
mutable reference. This affects `get()`, `iter()`, and others. To fix
the errors, first call `QueryState::update_archetypes()`, and then
replace a call `state.foo(world, param)` with
`state.query_manual(world).foo_inner(param)`. Alternately, you may be
able to restructure the code to call `state.query(world)` once and then
make multiple calls using the `Query`.

Before:
```rust
let mut state: QueryState<_, _> = ...;
let d1 = state.get(world, e1);
let d2 = state.get(world, e2); // Error: cannot borrow `state` as mutable more than once at a time
println!("{d1:?}");
println!("{d2:?}");
```

After: 
```rust
let mut state: QueryState<_, _> = ...;

state.update_archetypes(world);
let d1 = state.get_manual(world, e1);
let d2 = state.get_manual(world, e2);
// OR
state.update_archetypes(world);
let d1 = state.query(world).get_inner(e1);
let d2 = state.query(world).get_inner(e2);
// OR
let query = state.query(world);
let d1 = query.get_inner(e1);
let d1 = query.get_inner(e2);

println!("{d1:?}");
println!("{d2:?}");
```
2025-06-16 21:05:41 +00:00
Joona Aalto e5dc177b4b Rename Trigger to On (#19596)
# Objective

Currently, the observer API looks like this:

```rust
app.add_observer(|trigger: Trigger<Explode>| {
    info!("Entity {} exploded!", trigger.target());
});
```

Future plans for observers also include "multi-event observers" with a
trigger that looks like this (see [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)):

```rust
trigger: Trigger<(
    OnAdd<Pressed>,
    OnRemove<Pressed>,
    OnAdd<InteractionDisabled>,
    OnRemove<InteractionDisabled>,
    OnInsert<Hovered>,
)>,
```

In scenarios like this, there is a lot of repetition of `On`. These are
expected to be very high-traffic APIs especially in UI contexts, so
ergonomics and readability are critical.

By renaming `Trigger` to `On`, we can make these APIs read more cleanly
and get rid of the repetition:

```rust
app.add_observer(|trigger: On<Explode>| {
    info!("Entity {} exploded!", trigger.target());
});
```

```rust
trigger: On<(
    Add<Pressed>,
    Remove<Pressed>,
    Add<InteractionDisabled>,
    Remove<InteractionDisabled>,
    Insert<Hovered>,
)>,
```

Names like `On<Add<Pressed>>` emphasize the actual event listener nature
more than `Trigger<OnAdd<Pressed>>`, and look cleaner. This *also* frees
up the `Trigger` name if we want to use it for the observer event type,
splitting them out from buffered events (bikeshedding this is out of
scope for this PR though).

For prior art:
[`bevy_eventlistener`](https://github.com/aevyrie/bevy_eventlistener)
used
[`On`](https://docs.rs/bevy_eventlistener/latest/bevy_eventlistener/event_listener/struct.On.html)
for its event listener type. Though in our case, the observer is the
event listener, and `On` is just a type containing information about the
triggered event.

## Solution

Steal from `bevy_event_listener` by @aevyrie and use `On`.

- Rename `Trigger` to `On`
- Rename `OnAdd` to `Add`
- Rename `OnInsert` to `Insert`
- Rename `OnReplace` to `Replace`
- Rename `OnRemove` to `Remove`
- Rename `OnDespawn` to `Despawn`

## Discussion

### Naming Conflicts??

Using a name like `Add` might initially feel like a very bad idea, since
it risks conflict with `core::ops::Add`. However, I don't expect this to
be a big problem in practice.

- You rarely need to actually implement the `Add` trait, especially in
modules that would use the Bevy ECS.
- In the rare cases where you *do* get a conflict, it is very easy to
fix by just disambiguating, for example using `ops::Add`.
- The `Add` event is a struct while the `Add` trait is a trait (duh), so
the compiler error should be very obvious.

For the record, renaming `OnAdd` to `Add`, I got exactly *zero* errors
or conflicts within Bevy itself. But this is of course not entirely
representative of actual projects *using* Bevy.

You might then wonder, why not use `Added`? This would conflict with the
`Added` query filter, so it wouldn't work. Additionally, the current
naming convention for observer events does not use past tense.

### Documentation

This does make documentation slightly more awkward when referring to
`On` or its methods. Previous docs often referred to `Trigger::target`
or "sends a `Trigger`" (which is... a bit strange anyway), which would
now be `On::target` and "sends an observer `Event`".

You can see the diff in this PR to see some of the effects. I think it
should be fine though, we may just need to reword more documentation to
read better.
2025-06-12 18:22:33 +00:00
andriyDev c364710d1f Fix the game of life example panicking if the pipeline shader isn't ready on the first frame. (#19420)
# Objective

- Due to recent changes related to #19024, the
`compute_shader_game_of_life` example panics on some machines especially
on Linux.
- This is due to us switching more shaders to embedded shaders - this
means the compute shader in this example takes more than one frame to
load.
- The panic in the example occurs if the shader fails to load by the
first frame (since the pipeline considers that an error).

## Solution

- Make the example do nothing if the shader isn't loaded yet. This has
the effect of waiting for the shader to load.

## Testing

- Tested the example on my Linux laptop.
2025-05-29 11:30:53 +00:00