diff --git a/crates/bevy_core_pipeline/src/prepass/background_motion_vectors.rs b/crates/bevy_core_pipeline/src/prepass/background_motion_vectors.rs index 8ac7fd7e2b5cf..8b1e43c55ef3b 100644 --- a/crates/bevy_core_pipeline/src/prepass/background_motion_vectors.rs +++ b/crates/bevy_core_pipeline/src/prepass/background_motion_vectors.rs @@ -150,6 +150,18 @@ impl SpecializedRenderPipeline for BackgroundMotionVectorsPipeline { type Key = BackgroundMotionVectorsPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { + let mut targets = prepass_target_descriptors(key.normal_prepass, true, false); + // The shader only outputs to attachment at location 1, set write mask of the other attachments to empty + // to avoid WebGPU validation error "Color target has no corresponding fragment stage output but writeMask is not zero". + for target in + targets + .iter_mut() + .enumerate() + .filter_map(|(i, t)| if i == 1 { None } else { t.as_mut() }) + { + target.write_mask = bevy_render::render_resource::ColorWrites::empty(); + } + RenderPipelineDescriptor { label: Some("background_motion_vectors_pipeline".into()), layout: vec![self.bind_group_layout.clone()], @@ -168,7 +180,7 @@ impl SpecializedRenderPipeline for BackgroundMotionVectorsPipeline { }, fragment: Some(FragmentState { shader: self.fragment_shader.clone(), - targets: prepass_target_descriptors(key.normal_prepass, true, false), + targets, ..default() }), ..default() diff --git a/crates/bevy_post_process/src/dof/dof.wgsl b/crates/bevy_post_process/src/dof/dof.wgsl index 7dc32dc3cde1b..563b0af031644 100644 --- a/crates/bevy_post_process/src/dof/dof.wgsl +++ b/crates/bevy_post_process/src/dof/dof.wgsl @@ -212,7 +212,7 @@ fn gaussian_vertical(in: FullscreenVertexOutput) -> @location(0) vec4 { // │ // │ @fragment -fn bokeh_pass_0(in: FullscreenVertexOutput) -> DualOutput { +fn bokeh_pass_a(in: FullscreenVertexOutput) -> DualOutput { let coc = calculate_circle_of_confusion(in.position); let vertical = box_blur_a(in.position, coc, vec2(0.0, 1.0)); 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 { // • #ifdef DUAL_INPUT @fragment -fn bokeh_pass_1(in: FullscreenVertexOutput) -> @location(0) vec4 { +fn bokeh_pass_b(in: FullscreenVertexOutput) -> @location(0) vec4 { let coc = calculate_circle_of_confusion(in.position); let output_0 = box_blur_a(in.position, coc, vec2(COS_NEG_FRAC_PI_6, SIN_NEG_FRAC_PI_6)); let output_1 = box_blur_b(in.position, coc, vec2(COS_NEG_FRAC_PI_5_6, SIN_NEG_FRAC_PI_5_6)); diff --git a/crates/bevy_post_process/src/dof/mod.rs b/crates/bevy_post_process/src/dof/mod.rs index fe8f9f91398e2..0644b7c499188 100644 --- a/crates/bevy_post_process/src/dof/mod.rs +++ b/crates/bevy_post_process/src/dof/mod.rs @@ -124,8 +124,6 @@ pub enum DepthOfFieldMode { /// /// For more information, see [Wikipedia's article on *bokeh*]. /// - /// This doesn't work on WebGPU. - /// /// [Wikipedia's article on *bokeh*]: https://en.wikipedia.org/wiki/Bokeh Bokeh, @@ -135,9 +133,6 @@ pub enum DepthOfFieldMode { /// aesthetically pleasing but requires less video memory bandwidth. /// /// This is the default. - /// - /// This works on native and WebGPU. - /// If targeting native platforms, consider using [`DepthOfFieldMode::Bokeh`] instead. #[default] Gaussian, } @@ -642,8 +637,10 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline { entry_point: Some(match key.pass { DofPass::GaussianHorizontal => "gaussian_horizontal".into(), DofPass::GaussianVertical => "gaussian_vertical".into(), - DofPass::BokehPass0 => "bokeh_pass_0".into(), - DofPass::BokehPass1 => "bokeh_pass_1".into(), + // Entry point names that end with number don't work on wasm. Perhaps `naga_oil` bug. + // See + DofPass::BokehPass0 => "bokeh_pass_a".into(), + DofPass::BokehPass1 => "bokeh_pass_b".into(), }), targets, }), diff --git a/examples/3d/skybox.rs b/examples/3d/skybox.rs index 94ac4b98e001c..7b313172d4adf 100644 --- a/examples/3d/skybox.rs +++ b/examples/3d/skybox.rs @@ -1,6 +1,6 @@ //! Load a cubemap texture onto a cube like a skybox and cycle through different compressed texture formats -#[cfg(not(target_arch = "wasm32"))] +#[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))] use bevy::anti_alias::taa::TemporalAntiAliasing; use bevy::{ @@ -73,7 +73,7 @@ fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(( Camera3d::default(), Msaa::Off, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))] TemporalAntiAliasing::default(), ScreenSpaceAmbientOcclusion::default(), Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),