Skip to content

Ugrade to wgpu version 25.0 #19563

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

Merged
merged 44 commits into from
Jun 26, 2025
Merged

Conversation

tychedelia
Copy link
Member

@tychedelia tychedelia commented Jun 9, 2025

Objective

Upgrade to wgpu version 25.0.

Depends on bevyengine/naga_oil#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:

#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:

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:

#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.

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 gfx-rs/wgpu#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.

Copy link
Contributor

github-actions bot commented Jun 9, 2025

You added a new example but didn't add metadata for it. Please update the root Cargo.toml file.

@tychedelia tychedelia added A-Rendering Drawing game state to the screen M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 9, 2025
@tychedelia tychedelia added this to the 0.17 milestone Jun 9, 2025
} else {
self.view_layout_no_motion_vectors.clone()
},
self.empty_layout.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the purpose of this empty_layout?

Copy link
Member Author

Choose a reason for hiding this comment

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

Wgpu gets upset if you have a gap in bind groups i guess. should double check that this doesn't have any perf implications but it seems to work.

@mockersf
Copy link
Member

could you also update codespan-reporting? #18508

Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19563

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19563

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

1 similar comment
Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19563

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

# `fragile-send-sync-non-atomic-wasm` feature means we can't use Wasm threads for rendering
# It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm.
# When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing
# and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread.
wgpu = { version = "24", default-features = false, features = [
wgpu = { version = "25", default-features = false, features = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to add the vulkan and webgl features now.

Maybe gles as well, but in my experience it hasn't worked in years and just spits out confusing error messages.

Copy link
Member Author

Choose a reason for hiding this comment

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

we have a separate top level feature webgl so i don't htink we want it here? i included gles just because we still have code for it.

Copy link
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19563

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@tychedelia tychedelia requested a review from Elabajaba June 20, 2025 06:57
@hukasu
Copy link
Contributor

hukasu commented Jun 24, 2025

instance_id and instance_index are both valid fields? are they built-in or are they bevy defined?

Copy link
Member

@mockersf mockersf left a comment

Choose a reason for hiding this comment

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

Example run is good apart from taking way too long on DX12 which can't be reproduced locally 👍

@JMS55
Copy link
Contributor

JMS55 commented Jun 25, 2025

@tychedelia need to run rustfmt.

@tychedelia
Copy link
Member Author

This should be good now sans the naga_oil release.

Copy link
Contributor

@Elabajaba Elabajaba left a comment

Choose a reason for hiding this comment

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

@blend_src(0) doesn't work if the dual_source_blending feature isn't enabled, so the atmosphere shader needs a bit more #ifdef spaghetti. (sorry for splitting it up into 2 suggestions, but github won't let me do it as a single suggestion due to the deleted lines in the middle...).

- `@group(0)` view uniforms
- `@group(1)` view uniforms requiring binding arrays
- `@group(2)` mesh uniforms
- `@group(3)` material uniforms
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're telling users to use group 3 for their material uniforms, doesn't that mean that we can't put our bindless stuff in group 3? (eg. crates/bevy_render/src/bindless.wgsl or assets/shaders/bindless_material.wgsl)

Copy link
Member Author

Choose a reason for hiding this comment

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

I was being a bit too loose so just pushed some clarifying language. I don't think our existing bindless mechanism via AsBindGroup lets users bind uniform buffers in combination with binding arrays anyway, despite the attr being named #[uniform] it puts everything in storage afaict.

tychedelia and others added 5 commits June 25, 2025 20:36
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 26, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jun 26, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 26, 2025
Merged via the queue into bevyengine:main with commit 96dcbc5 Jun 26, 2025
36 checks passed
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 M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

8 participants