Skip to content

Commit c4cff62

Browse files
beicausetychedelia
authored andcommitted
Fix dof and background motion vectors on webgpu (bevyengine#23629)
# Objective WebGPU-only fix extracted from bevyengine#22554 and bevyengine#22555. Fixes bevyengine#20459 ## Solution Fix normal + motion vector prepass by setting write mask to empty. This is a firefox/wgpu bug that it's not validated gfx-rs/wgpu#9147, but chromium does. Fix dof with bokeh mode. I guess it's `naga_oil` bug but I'm not sure. ## Testing I tested dof and skybox examples on web.
1 parent 1407f35 commit c4cff62

4 files changed

Lines changed: 21 additions & 12 deletions

File tree

crates/bevy_core_pipeline/src/prepass/background_motion_vectors.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ impl SpecializedRenderPipeline for BackgroundMotionVectorsPipeline {
150150
type Key = BackgroundMotionVectorsPipelineKey;
151151

152152
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
153+
let mut targets = prepass_target_descriptors(key.normal_prepass, true, false);
154+
// The shader only outputs to attachment at location 1, set write mask of the other attachments to empty
155+
// to avoid WebGPU validation error "Color target has no corresponding fragment stage output but writeMask is not zero".
156+
for target in
157+
targets
158+
.iter_mut()
159+
.enumerate()
160+
.filter_map(|(i, t)| if i == 1 { None } else { t.as_mut() })
161+
{
162+
target.write_mask = bevy_render::render_resource::ColorWrites::empty();
163+
}
164+
153165
RenderPipelineDescriptor {
154166
label: Some("background_motion_vectors_pipeline".into()),
155167
layout: vec![self.bind_group_layout.clone()],
@@ -168,7 +180,7 @@ impl SpecializedRenderPipeline for BackgroundMotionVectorsPipeline {
168180
},
169181
fragment: Some(FragmentState {
170182
shader: self.fragment_shader.clone(),
171-
targets: prepass_target_descriptors(key.normal_prepass, true, false),
183+
targets,
172184
..default()
173185
}),
174186
..default()

crates/bevy_post_process/src/dof/dof.wgsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ fn gaussian_vertical(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
212212
// │
213213
// │
214214
@fragment
215-
fn bokeh_pass_0(in: FullscreenVertexOutput) -> DualOutput {
215+
fn bokeh_pass_a(in: FullscreenVertexOutput) -> DualOutput {
216216
let coc = calculate_circle_of_confusion(in.position);
217217
let vertical = box_blur_a(in.position, coc, vec2(0.0, 1.0));
218218
let diagonal = box_blur_a(in.position, coc, vec2(COS_NEG_FRAC_PI_6, SIN_NEG_FRAC_PI_6));
@@ -232,7 +232,7 @@ fn bokeh_pass_0(in: FullscreenVertexOutput) -> DualOutput {
232232
// •
233233
#ifdef DUAL_INPUT
234234
@fragment
235-
fn bokeh_pass_1(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
235+
fn bokeh_pass_b(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
236236
let coc = calculate_circle_of_confusion(in.position);
237237
let output_0 = box_blur_a(in.position, coc, vec2(COS_NEG_FRAC_PI_6, SIN_NEG_FRAC_PI_6));
238238
let output_1 = box_blur_b(in.position, coc, vec2(COS_NEG_FRAC_PI_5_6, SIN_NEG_FRAC_PI_5_6));

crates/bevy_post_process/src/dof/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,6 @@ pub enum DepthOfFieldMode {
124124
///
125125
/// For more information, see [Wikipedia's article on *bokeh*].
126126
///
127-
/// This doesn't work on WebGPU.
128-
///
129127
/// [Wikipedia's article on *bokeh*]: https://en.wikipedia.org/wiki/Bokeh
130128
Bokeh,
131129

@@ -135,9 +133,6 @@ pub enum DepthOfFieldMode {
135133
/// aesthetically pleasing but requires less video memory bandwidth.
136134
///
137135
/// This is the default.
138-
///
139-
/// This works on native and WebGPU.
140-
/// If targeting native platforms, consider using [`DepthOfFieldMode::Bokeh`] instead.
141136
#[default]
142137
Gaussian,
143138
}
@@ -642,8 +637,10 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline {
642637
entry_point: Some(match key.pass {
643638
DofPass::GaussianHorizontal => "gaussian_horizontal".into(),
644639
DofPass::GaussianVertical => "gaussian_vertical".into(),
645-
DofPass::BokehPass0 => "bokeh_pass_0".into(),
646-
DofPass::BokehPass1 => "bokeh_pass_1".into(),
640+
// Entry point names that end with number don't work on wasm. Perhaps `naga_oil` bug.
641+
// See <https://github.com/bevyengine/bevy/pull/23629>
642+
DofPass::BokehPass0 => "bokeh_pass_a".into(),
643+
DofPass::BokehPass1 => "bokeh_pass_b".into(),
647644
}),
648645
targets,
649646
}),

examples/3d/skybox.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Load a cubemap texture onto a cube like a skybox and cycle through different compressed texture formats
22
3-
#[cfg(not(target_arch = "wasm32"))]
3+
#[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))]
44
use bevy::anti_alias::taa::TemporalAntiAliasing;
55

66
use bevy::{
@@ -73,7 +73,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
7373
commands.spawn((
7474
Camera3d::default(),
7575
Msaa::Off,
76-
#[cfg(not(target_arch = "wasm32"))]
76+
#[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))]
7777
TemporalAntiAliasing::default(),
7878
ScreenSpaceAmbientOcclusion::default(),
7979
Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),

0 commit comments

Comments
 (0)