diff --git a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs index 6230234bb53a6..857c2202164ab 100644 --- a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs +++ b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs @@ -2,6 +2,7 @@ use crate::core_2d::graph::Core2d; use crate::tonemapping::{DebandDither, Tonemapping}; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; +use bevy_render::prelude::Msaa; use bevy_render::{ camera::{ Camera, CameraMainTextureUsages, CameraProjection, CameraRenderGraph, @@ -35,6 +36,7 @@ pub struct Camera2dBundle { pub tonemapping: Tonemapping, pub deband_dither: DebandDither, pub main_texture_usages: CameraMainTextureUsages, + pub msaa: Msaa, } impl Default for Camera2dBundle { @@ -58,6 +60,7 @@ impl Default for Camera2dBundle { tonemapping: Tonemapping::None, deband_dither: DebandDither::Disabled, main_texture_usages: Default::default(), + msaa: Default::default(), } } } @@ -90,6 +93,7 @@ impl Camera2dBundle { tonemapping: Tonemapping::None, deband_dither: DebandDither::Disabled, main_texture_usages: Default::default(), + msaa: Default::default(), } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index cf062d340ff79..697d9df64b339 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -4,6 +4,7 @@ use crate::{ }; use bevy_ecs::prelude::*; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +use bevy_render::view::Msaa; use bevy_render::{ camera::{Camera, CameraMainTextureUsages, CameraRenderGraph, Exposure, Projection}, extract_component::ExtractComponent, @@ -152,6 +153,7 @@ pub struct Camera3dBundle { pub color_grading: ColorGrading, pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, + pub msaa: Msaa, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference @@ -171,6 +173,7 @@ impl Default for Camera3dBundle { exposure: Default::default(), main_texture_usages: Default::default(), deband_dither: DebandDither::Enabled, + msaa: Default::default(), } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index ae82cd58fb411..bf38e1deb2159 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -610,16 +610,21 @@ pub fn extract_camera_prepass_phase( pub fn prepare_core_3d_depth_textures( mut commands: Commands, mut texture_cache: ResMut, - msaa: Res, render_device: Res, opaque_3d_phases: Res>, alpha_mask_3d_phases: Res>, transmissive_3d_phases: Res>, transparent_3d_phases: Res>, - views_3d: Query<(Entity, &ExtractedCamera, Option<&DepthPrepass>, &Camera3d)>, + views_3d: Query<( + Entity, + &ExtractedCamera, + Option<&DepthPrepass>, + &Camera3d, + &Msaa, + )>, ) { let mut render_target_usage = HashMap::default(); - for (view, camera, depth_prepass, camera_3d) in &views_3d { + for (view, camera, depth_prepass, camera_3d, _msaa) in &views_3d { if !opaque_3d_phases.contains_key(&view) || !alpha_mask_3d_phases.contains_key(&view) || !transmissive_3d_phases.contains_key(&view) @@ -641,13 +646,13 @@ pub fn prepare_core_3d_depth_textures( } let mut textures = HashMap::default(); - for (entity, camera, _, camera_3d) in &views_3d { + for (entity, camera, _, camera_3d, msaa) in &views_3d { let Some(physical_target_size) = camera.physical_target_size else { continue; }; let cached_texture = textures - .entry(camera.target.clone()) + .entry((camera.target.clone(), msaa)) .or_insert_with(|| { // The size of the depth texture let size = Extent3d { @@ -779,11 +784,8 @@ pub fn prepare_core_3d_transmission_textures( } // Disable MSAA and warn if using deferred rendering -pub fn check_msaa( - mut msaa: ResMut, - deferred_views: Query, With)>, -) { - if !deferred_views.is_empty() { +pub fn check_msaa(mut deferred_views: Query<&mut Msaa, (With, With)>) { + for mut msaa in deferred_views.iter_mut() { match *msaa { Msaa::Off => (), _ => { @@ -799,7 +801,6 @@ pub fn check_msaa( pub fn prepare_prepass_textures( mut commands: Commands, mut texture_cache: ResMut, - msaa: Res, render_device: Res, opaque_3d_prepass_phases: Res>, alpha_mask_3d_prepass_phases: Res>, @@ -808,6 +809,7 @@ pub fn prepare_prepass_textures( views_3d: Query<( Entity, &ExtractedCamera, + &Msaa, Has, Has, Has, @@ -819,8 +821,15 @@ pub fn prepare_prepass_textures( let mut deferred_textures = HashMap::default(); let mut deferred_lighting_id_textures = HashMap::default(); let mut motion_vectors_textures = HashMap::default(); - for (entity, camera, depth_prepass, normal_prepass, motion_vector_prepass, deferred_prepass) in - &views_3d + for ( + entity, + camera, + msaa, + depth_prepass, + normal_prepass, + motion_vector_prepass, + deferred_prepass, + ) in &views_3d { if !opaque_3d_prepass_phases.contains_key(&entity) && !alpha_mask_3d_prepass_phases.contains_key(&entity) diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index 032e9f63d703c..91e836dfee595 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -515,11 +515,10 @@ impl FromWorld for DepthOfFieldGlobalBindGroupLayout { /// specific to each view. pub fn prepare_depth_of_field_view_bind_group_layouts( mut commands: Commands, - view_targets: Query<(Entity, &DepthOfFieldSettings)>, - msaa: Res, + view_targets: Query<(Entity, &DepthOfFieldSettings, &Msaa)>, render_device: Res, ) { - for (view, dof_settings) in view_targets.iter() { + for (view, dof_settings, msaa) in view_targets.iter() { // Create the bind group layout for the passes that take one input. let single_input = render_device.create_bind_group_layout( Some("depth of field bind group layout (single input)"), @@ -646,16 +645,16 @@ pub fn prepare_depth_of_field_pipelines( mut commands: Commands, pipeline_cache: Res, mut pipelines: ResMut>, - msaa: Res, global_bind_group_layout: Res, view_targets: Query<( Entity, &ExtractedView, &DepthOfFieldSettings, &ViewDepthOfFieldBindGroupLayouts, + &Msaa, )>, ) { - for (entity, view, dof_settings, view_bind_group_layouts) in view_targets.iter() { + for (entity, view, dof_settings, view_bind_group_layouts, msaa) in view_targets.iter() { let dof_pipeline = DepthOfFieldPipeline { view_bind_group_layouts: view_bind_group_layouts.clone(), global_bind_group_layout: global_bind_group_layout.layout.clone(), diff --git a/crates/bevy_core_pipeline/src/motion_blur/node.rs b/crates/bevy_core_pipeline/src/motion_blur/node.rs index 395314892bb51..24f470c563742 100644 --- a/crates/bevy_core_pipeline/src/motion_blur/node.rs +++ b/crates/bevy_core_pipeline/src/motion_blur/node.rs @@ -27,12 +27,13 @@ impl ViewNode for MotionBlurNode { &'static MotionBlurPipelineId, &'static ViewPrepassTextures, &'static MotionBlur, + &'static Msaa, ); fn run( &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (view_target, pipeline_id, prepass_textures, settings): QueryItem, + (view_target, pipeline_id, prepass_textures, settings, msaa): QueryItem, world: &World, ) -> Result<(), NodeRunError> { if settings.samples == 0 || settings.shutter_angle <= 0.0 { @@ -60,7 +61,6 @@ impl ViewNode for MotionBlurNode { let post_process = view_target.post_process_write(); - let msaa = world.resource::(); let layout = if msaa.samples() == 1 { &motion_blur_pipeline.layout } else { diff --git a/crates/bevy_core_pipeline/src/motion_blur/pipeline.rs b/crates/bevy_core_pipeline/src/motion_blur/pipeline.rs index 7ad94d8874253..cff26a9e22f17 100644 --- a/crates/bevy_core_pipeline/src/motion_blur/pipeline.rs +++ b/crates/bevy_core_pipeline/src/motion_blur/pipeline.rs @@ -153,10 +153,9 @@ pub(crate) fn prepare_motion_blur_pipelines( pipeline_cache: Res, mut pipelines: ResMut>, pipeline: Res, - msaa: Res, - views: Query<(Entity, &ExtractedView), With>, + views: Query<(Entity, &ExtractedView, &Msaa), With>, ) { - for (entity, view) in &views { + for (entity, view, msaa) in &views { let pipeline_id = pipelines.specialize( &pipeline_cache, &pipeline, diff --git a/crates/bevy_core_pipeline/src/msaa_writeback.rs b/crates/bevy_core_pipeline/src/msaa_writeback.rs index 5165f51ab08da..01f579a0e1404 100644 --- a/crates/bevy_core_pipeline/src/msaa_writeback.rs +++ b/crates/bevy_core_pipeline/src/msaa_writeback.rs @@ -6,9 +6,11 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_color::LinearRgba; use bevy_ecs::prelude::*; +use bevy_ecs::query::QueryItem; +use bevy_render::render_graph::{ViewNode, ViewNodeRunner}; use bevy_render::{ camera::ExtractedCamera, - render_graph::{Node, NodeRunError, RenderGraphApp, RenderGraphContext}, + render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext}, renderer::RenderContext, view::{Msaa, ViewTarget}, Render, RenderSet, @@ -30,90 +32,87 @@ impl Plugin for MsaaWritebackPlugin { ); { render_app - .add_render_graph_node::(Core2d, Node2d::MsaaWriteback) + .add_render_graph_node::>( + Core2d, + Node2d::MsaaWriteback, + ) .add_render_graph_edge(Core2d, Node2d::MsaaWriteback, Node2d::StartMainPass); } { render_app - .add_render_graph_node::(Core3d, Node3d::MsaaWriteback) + .add_render_graph_node::>( + Core3d, + Node3d::MsaaWriteback, + ) .add_render_graph_edge(Core3d, Node3d::MsaaWriteback, Node3d::StartMainPass); } } } -pub struct MsaaWritebackNode { - cameras: QueryState<(&'static ViewTarget, &'static MsaaWritebackBlitPipeline)>, -} +#[derive(Default)] +pub struct MsaaWritebackNode; -impl FromWorld for MsaaWritebackNode { - fn from_world(world: &mut World) -> Self { - Self { - cameras: world.query(), - } - } -} +impl ViewNode for MsaaWritebackNode { + type ViewQuery = ( + &'static ViewTarget, + &'static MsaaWritebackBlitPipeline, + &'static Msaa, + ); -impl Node for MsaaWritebackNode { - fn update(&mut self, world: &mut World) { - self.cameras.update_archetypes(world); - } - - fn run( + fn run<'w>( &self, - graph: &mut RenderGraphContext, - render_context: &mut RenderContext, - world: &World, + _graph: &mut RenderGraphContext, + render_context: &mut RenderContext<'w>, + (target, blit_pipeline_id, msaa): QueryItem<'w, Self::ViewQuery>, + world: &'w World, ) -> Result<(), NodeRunError> { - if *world.resource::() == Msaa::Off { + if *msaa == Msaa::Off { return Ok(()); } - let view_entity = graph.view_entity(); - if let Ok((target, blit_pipeline_id)) = self.cameras.get_manual(world, view_entity) { - let blit_pipeline = world.resource::(); - let pipeline_cache = world.resource::(); - let Some(pipeline) = pipeline_cache.get_render_pipeline(blit_pipeline_id.0) else { - return Ok(()); - }; - - // The current "main texture" needs to be bound as an input resource, and we need the "other" - // unused target to be the "resolve target" for the MSAA write. Therefore this is the same - // as a post process write! - let post_process = target.post_process_write(); + let blit_pipeline = world.resource::(); + let pipeline_cache = world.resource::(); + let Some(pipeline) = pipeline_cache.get_render_pipeline(blit_pipeline_id.0) else { + return Ok(()); + }; - let pass_descriptor = RenderPassDescriptor { - label: Some("msaa_writeback"), - // The target's "resolve target" is the "destination" in post_process. - // We will indirectly write the results to the "destination" using - // the MSAA resolve step. - color_attachments: &[Some(RenderPassColorAttachment { - // If MSAA is enabled, then the sampled texture will always exist - view: target.sampled_main_texture_view().unwrap(), - resolve_target: Some(post_process.destination), - ops: Operations { - load: LoadOp::Clear(LinearRgba::BLACK.into()), - store: StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }; + // The current "main texture" needs to be bound as an input resource, and we need the "other" + // unused target to be the "resolve target" for the MSAA write. Therefore this is the same + // as a post process write! + let post_process = target.post_process_write(); + + let pass_descriptor = RenderPassDescriptor { + label: Some("msaa_writeback"), + // The target's "resolve target" is the "destination" in post_process. + // We will indirectly write the results to the "destination" using + // the MSAA resolve step. + color_attachments: &[Some(RenderPassColorAttachment { + // If MSAA is enabled, then the sampled texture will always exist + view: target.sampled_main_texture_view().unwrap(), + resolve_target: Some(post_process.destination), + ops: Operations { + load: LoadOp::Clear(LinearRgba::BLACK.into()), + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }; - let bind_group = render_context.render_device().create_bind_group( - None, - &blit_pipeline.texture_bind_group, - &BindGroupEntries::sequential((post_process.source, &blit_pipeline.sampler)), - ); + let bind_group = render_context.render_device().create_bind_group( + None, + &blit_pipeline.texture_bind_group, + &BindGroupEntries::sequential((post_process.source, &blit_pipeline.sampler)), + ); - let mut render_pass = render_context - .command_encoder() - .begin_render_pass(&pass_descriptor); + let mut render_pass = render_context + .command_encoder() + .begin_render_pass(&pass_descriptor); - render_pass.set_pipeline(pipeline); - render_pass.set_bind_group(0, &bind_group, &[]); - render_pass.draw(0..3, 0..1); - } + render_pass.set_pipeline(pipeline); + render_pass.set_bind_group(0, &bind_group, &[]); + render_pass.draw(0..3, 0..1); Ok(()) } @@ -127,10 +126,9 @@ fn prepare_msaa_writeback_pipelines( pipeline_cache: Res, mut pipelines: ResMut>, blit_pipeline: Res, - view_targets: Query<(Entity, &ViewTarget, &ExtractedCamera)>, - msaa: Res, + view_targets: Query<(Entity, &ViewTarget, &ExtractedCamera, &Msaa)>, ) { - for (entity, view_target, camera) in view_targets.iter() { + for (entity, view_target, camera, msaa) in view_targets.iter() { // only do writeback if writeback is enabled for the camera and this isn't the first camera in the target, // as there is nothing to write back for the first camera. if msaa.samples() > 1 && camera.msaa_writeback && camera.sorted_camera_index_for_target > 0 diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index 9d1ef61b4384a..59cfa908863c2 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -245,10 +245,9 @@ fn prepare_skybox_pipelines( pipeline_cache: Res, mut pipelines: ResMut>, pipeline: Res, - msaa: Res, - views: Query<(Entity, &ExtractedView), With>, + views: Query<(Entity, &ExtractedView, &Msaa), With>, ) { - for (entity, view) in &views { + for (entity, view, msaa) in &views { let pipeline_id = pipelines.specialize( &pipeline_cache, &pipeline, diff --git a/crates/bevy_core_pipeline/src/skybox/prepass.rs b/crates/bevy_core_pipeline/src/skybox/prepass.rs index 86d5d296f251d..f6f47d01167bc 100644 --- a/crates/bevy_core_pipeline/src/skybox/prepass.rs +++ b/crates/bevy_core_pipeline/src/skybox/prepass.rs @@ -116,11 +116,10 @@ pub fn prepare_skybox_prepass_pipelines( mut commands: Commands, pipeline_cache: Res, mut pipelines: ResMut>, - msaa: Res, pipeline: Res, - views: Query<(Entity, Has), (With, With)>, + views: Query<(Entity, Has, &Msaa), (With, With)>, ) { - for (entity, normal_prepass) in &views { + for (entity, normal_prepass, msaa) in &views { let pipeline_key = SkyboxPrepassPipelineKey { samples: msaa.samples(), normal_prepass, diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 04d67f451d43e..b3e0d55dcabb7 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -34,6 +34,7 @@ use bevy_render::{ view::{ExtractedView, Msaa, ViewTarget}, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet, }; +use bevy_utils::tracing::warn; const TAA_SHADER_HANDLE: Handle = Handle::weak_from_u128(656865235226276); @@ -46,8 +47,7 @@ impl Plugin for TemporalAntiAliasPlugin { fn build(&self, app: &mut App) { load_internal_asset!(app, TAA_SHADER_HANDLE, "taa.wgsl", Shader::from_wgsl); - app.insert_resource(Msaa::Off) - .register_type::(); + app.register_type::(); let Some(render_app) = app.get_sub_app_mut(RenderApp) else { return; @@ -162,17 +162,23 @@ impl ViewNode for TemporalAntiAliasNode { &'static TemporalAntiAliasHistoryTextures, &'static ViewPrepassTextures, &'static TemporalAntiAliasPipelineId, + &'static Msaa, ); fn run( &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (camera, view_target, taa_history_textures, prepass_textures, taa_pipeline_id): QueryItem< + (camera, view_target, taa_history_textures, prepass_textures, taa_pipeline_id, msaa): QueryItem< Self::ViewQuery, >, world: &World, ) -> Result<(), NodeRunError> { + if *msaa != Msaa::Off { + warn!("Temporal anti-aliasing requires MSAA to be disabled"); + return Ok(()); + } + let (Some(pipelines), Some(pipeline_cache)) = ( world.get_resource::(), world.get_resource::(), diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index df84a48256cd0..77b4efb57454d 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -255,15 +255,14 @@ fn queue_line_gizmos_2d( pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, - mut views: Query<(Entity, &ExtractedView, Option<&RenderLayers>)>, + mut views: Query<(Entity, &ExtractedView, &Msaa, Option<&RenderLayers>)>, ) { let draw_function = draw_functions.read().get_id::().unwrap(); - for (view_entity, view, render_layers) in &mut views { + for (view_entity, view, msaa, render_layers) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; @@ -309,18 +308,17 @@ fn queue_line_joint_gizmos_2d( pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, - mut views: Query<(Entity, &ExtractedView, Option<&RenderLayers>)>, + mut views: Query<(Entity, &ExtractedView, &Msaa, Option<&RenderLayers>)>, ) { let draw_function = draw_functions .read() .get_id::() .unwrap(); - for (view_entity, view, render_layers) in &mut views { + for (view_entity, view, msaa, render_layers) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 761278ca3e1cb..8197623b3618c 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -280,13 +280,13 @@ fn queue_line_gizmos_3d( pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, mut views: Query<( Entity, &ExtractedView, + &Msaa, Option<&RenderLayers>, ( Has, @@ -301,6 +301,7 @@ fn queue_line_gizmos_3d( for ( view_entity, view, + msaa, render_layers, (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass), ) in &mut views @@ -368,13 +369,13 @@ fn queue_line_joint_gizmos_3d( pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, mut views: Query<( Entity, &ExtractedView, + &Msaa, Option<&RenderLayers>, ( Has, @@ -392,6 +393,7 @@ fn queue_line_joint_gizmos_3d( for ( view_entity, view, + msaa, render_layers, (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass), ) in &mut views diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index ba25fa30cda69..b491bb2195ed4 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -536,7 +536,6 @@ pub fn queue_material_meshes( material_pipeline: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, - msaa: Res, render_meshes: Res>, render_materials: Res>>, render_mesh_instances: Res, @@ -551,6 +550,7 @@ pub fn queue_material_meshes( Entity, &ExtractedView, &VisibleEntities, + &Msaa, Option<&Tonemapping>, Option<&DebandDither>, Option<&ShadowFilteringMethod>, @@ -576,6 +576,7 @@ pub fn queue_material_meshes( view_entity, view, visible_entities, + msaa, tonemapping, dither, shadow_filter_method, @@ -691,9 +692,14 @@ pub fn queue_material_meshes( continue; }; + let mut mesh_pipeline_key_bits = material.properties.mesh_pipeline_key_bits; + mesh_pipeline_key_bits.insert(alpha_mode_pipeline_key( + material.properties.alpha_mode, + msaa, + )); let mut mesh_key = view_key | MeshPipelineKey::from_bits_retain(mesh.key_bits.bits()) - | material.properties.mesh_pipeline_key_bits; + | mesh_pipeline_key_bits; let lightmap_image = render_lightmaps .render_lightmaps @@ -906,12 +912,11 @@ impl RenderAsset for PreparedMaterial { SRes, SRes>, SRes, - SRes, ); fn prepare_asset( material: Self::SourceAsset, - (render_device, images, fallback_image, pipeline, default_opaque_render_method, msaa): &mut SystemParamItem, + (render_device, images, fallback_image, pipeline, default_opaque_render_method): &mut SystemParamItem, ) -> Result> { match material.as_bind_group( &pipeline.material_layout, @@ -930,7 +935,6 @@ impl RenderAsset for PreparedMaterial { MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE, material.reads_view_transmission_texture(), ); - mesh_pipeline_key_bits.insert(alpha_mode_pipeline_key(material.alpha_mode(), msaa)); Ok(PreparedMaterial { bindings: prepared.bindings, diff --git a/crates/bevy_pbr/src/meshlet/mod.rs b/crates/bevy_pbr/src/meshlet/mod.rs index 2a19bbd280af3..101cc9b2b0b0b 100644 --- a/crates/bevy_pbr/src/meshlet/mod.rs +++ b/crates/bevy_pbr/src/meshlet/mod.rs @@ -172,7 +172,6 @@ impl Plugin for MeshletPlugin { app.init_asset::() .register_asset_loader(MeshletMeshSaverLoader) - .insert_resource(Msaa::Off) .add_systems( PostUpdate, check_visibility::.in_set(VisibilitySystems::CheckVisibility), @@ -282,15 +281,20 @@ fn configure_meshlet_views( mut views_3d: Query<( Entity, &mut Camera3d, + &Msaa, Has, Has, Has, )>, mut commands: Commands, ) { - for (entity, mut camera_3d, normal_prepass, motion_vector_prepass, deferred_prepass) in + for (entity, mut camera_3d, msaa, normal_prepass, motion_vector_prepass, deferred_prepass) in &mut views_3d { + if *msaa != Msaa::Off { + panic!("MeshletPlugin can't be used. MSAA is not supported."); + } + let mut usages: TextureUsages = camera_3d.depth_texture_usages.into(); usages |= TextureUsages::TEXTURE_BINDING; camera_3d.depth_texture_usages = usages.into(); diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 80c6b31121623..a8ca69a41f176 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -679,7 +679,6 @@ pub fn queue_prepass_material_meshes( prepass_pipeline: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, - msaa: Res, render_meshes: Res>, render_mesh_instances: Res, render_materials: Res>>, @@ -693,6 +692,7 @@ pub fn queue_prepass_material_meshes( ( Entity, &VisibleEntities, + &Msaa, Option<&DepthPrepass>, Option<&NormalPrepass>, Option<&MotionVectorPrepass>, @@ -722,6 +722,7 @@ pub fn queue_prepass_material_meshes( for ( view, visible_entities, + msaa, depth_prepass, normal_prepass, motion_vector_prepass, @@ -780,7 +781,7 @@ pub fn queue_prepass_material_meshes( let alpha_mode = material.properties.alpha_mode; match alpha_mode { AlphaMode::Opaque | AlphaMode::AlphaToCoverage | AlphaMode::Mask(_) => { - mesh_key |= alpha_mode_pipeline_key(alpha_mode, &msaa); + mesh_key |= alpha_mode_pipeline_key(alpha_mode, msaa); } AlphaMode::Blend | AlphaMode::Premultiplied diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index adc1802a47857..36c5d7bfe044f 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -456,6 +456,7 @@ pub fn prepare_mesh_view_bind_groups( Entity, &ViewShadowBindings, &ViewClusterBindings, + &Msaa, Option<&ScreenSpaceAmbientOcclusionTextures>, Option<&ViewPrepassTextures>, Option<&ViewTransmissionTexture>, @@ -469,7 +470,6 @@ pub fn prepare_mesh_view_bind_groups( Res, Res, ), - msaa: Res, globals_buffer: Res, tonemapping_luts: Res, light_probes_buffer: Res, @@ -501,6 +501,7 @@ pub fn prepare_mesh_view_bind_groups( entity, shadow_bindings, cluster_bindings, + msaa, ssao_textures, prepass_textures, transmission_texture, diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 9c43854b94810..cba48b8f8b1bd 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -484,17 +484,16 @@ fn extract_ssao_settings( mut commands: Commands, cameras: Extract< Query< - (Entity, &Camera, &ScreenSpaceAmbientOcclusionSettings), + (Entity, &Camera, &ScreenSpaceAmbientOcclusionSettings, &Msaa), (With, With, With), >, >, - msaa: Extract>, ) { - for (entity, camera, ssao_settings) in &cameras { - if **msaa != Msaa::Off { + for (entity, camera, ssao_settings, msaa) in &cameras { + if *msaa != Msaa::Off { error!( "SSAO is being used which requires Msaa::Off, but Msaa is currently set to Msaa::{:?}", - **msaa + *msaa ); return; } diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index 735a9653ddb16..c1420f32a241c 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -307,6 +307,7 @@ impl ViewNode for VolumetricFogNode { Read, Read, Read, + Read, Read, ); @@ -325,6 +326,7 @@ impl ViewNode for VolumetricFogNode { view_fog_volumes, view_bind_group, view_ssr_offset, + msaa, view_environment_map_offset, ): QueryItem<'w, Self::ViewQuery>, world: &'w World, @@ -333,7 +335,6 @@ impl ViewNode for VolumetricFogNode { let volumetric_lighting_pipeline = world.resource::(); let volumetric_lighting_uniform_buffers = world.resource::(); let image_assets = world.resource::>(); - let msaa = world.resource::(); let mesh_allocator = world.resource::(); // Fetch the uniform buffer and binding. @@ -594,6 +595,7 @@ pub fn prepare_volumetric_fog_pipelines( ( Entity, &ExtractedView, + &Msaa, Has, Has, Has, @@ -601,13 +603,19 @@ pub fn prepare_volumetric_fog_pipelines( ), With, >, - msaa: Res, meshes: Res>, ) { let plane_mesh = meshes.get(&PLANE_MESH).expect("Plane mesh not found!"); - for (entity, view, normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass) in - view_targets.iter() + for ( + entity, + view, + msaa, + normal_prepass, + depth_prepass, + motion_vector_prepass, + deferred_prepass, + ) in view_targets.iter() { // Create a mesh pipeline view layout key corresponding to the view. let mut mesh_pipeline_view_key = MeshPipelineViewLayoutKey::from(*msaa); diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 9c3caa9ebee94..85932e014d1e4 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -5,12 +5,12 @@ use bevy_asset::{load_internal_asset, Handle}; pub use visibility::*; pub use window::*; +use crate::extract_component::ExtractComponentPlugin; use crate::{ camera::{ CameraMainTextureUsages, ClearColor, ClearColorConfig, Exposure, ExtractedCamera, ManualTextureViews, MipBias, TemporalJitter, }, - extract_resource::{ExtractResource, ExtractResourcePlugin}, prelude::Shader, primitives::Frustum, render_asset::RenderAssets, @@ -28,6 +28,7 @@ use bevy_color::LinearRgba; use bevy_ecs::prelude::*; use bevy_math::{mat3, vec2, vec3, Mat3, Mat4, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_render_macros::ExtractComponent; use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; use std::{ @@ -107,10 +108,9 @@ impl Plugin for ViewPlugin { .register_type::() .register_type::() .register_type::() - .init_resource::() // NOTE: windows.is_changed() handles cases where a window was resized .add_plugins(( - ExtractResourcePlugin::::default(), + ExtractComponentPlugin::::default(), VisibilityPlugin, VisibilityRangePlugin, )); @@ -139,24 +139,26 @@ impl Plugin for ViewPlugin { /// Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing). /// -/// The number of samples to run for Multi-Sample Anti-Aliasing. Higher numbers result in -/// smoother edges. -/// Defaults to 4 samples. +/// The number of samples to run for Multi-Sample Anti-Aliasing for a given camera. Higher numbers +/// result in smoother edges. /// -/// Note that web currently only supports 1 or 4 samples. +/// Defaults to 4 samples. Some advanced rendering features may require that MSAA be disabled. /// -/// # Example -/// ``` -/// # use bevy_app::prelude::App; -/// # use bevy_render::prelude::Msaa; -/// App::new() -/// .insert_resource(Msaa::default()) -/// .run(); -/// ``` +/// Note that web currently only supports 1 or 4 samples. #[derive( - Resource, Default, Clone, Copy, ExtractResource, Reflect, PartialEq, PartialOrd, Eq, Hash, Debug, + Component, + Default, + Clone, + Copy, + ExtractComponent, + Reflect, + PartialEq, + PartialOrd, + Eq, + Hash, + Debug, )] -#[reflect(Resource, Default)] +#[reflect(Component, Default)] pub enum Msaa { Off = 1, Sample2 = 2, @@ -797,7 +799,6 @@ pub fn prepare_view_targets( mut commands: Commands, windows: Res, images: Res>, - msaa: Res, clear_color_global: Res, render_device: Res, mut texture_cache: ResMut, @@ -806,12 +807,13 @@ pub fn prepare_view_targets( &ExtractedCamera, &ExtractedView, &CameraMainTextureUsages, + &Msaa, )>, manual_texture_views: Res, ) { let mut textures = HashMap::default(); let mut output_textures = HashMap::default(); - for (entity, camera, view, texture_usage) in cameras.iter() { + for (entity, camera, view, texture_usage, msaa) in cameras.iter() { let (Some(target_size), Some(target)) = (camera.physical_target_size, &camera.target) else { continue; @@ -847,7 +849,7 @@ pub fn prepare_view_targets( }; let (a, b, sampled, main_texture) = textures - .entry((camera.target.clone(), view.hdr)) + .entry((camera.target.clone(), view.hdr, msaa)) .or_insert_with(|| { let descriptor = TextureDescriptor { label: None, diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index cf347586e6429..a0cd1fc62ed88 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -30,8 +30,6 @@ use screenshot::{ ScreenshotManager, ScreenshotPlugin, ScreenshotPreparedState, ScreenshotToScreenPipeline, }; -use super::Msaa; - pub struct WindowRenderPlugin; impl Plugin for WindowRenderPlugin { @@ -250,11 +248,9 @@ pub fn prepare_windows( mut windows: ResMut, mut window_surfaces: ResMut, render_device: Res, - render_adapter: Res, screenshot_pipeline: Res, pipeline_cache: Res, mut pipelines: ResMut>, - mut msaa: ResMut, #[cfg(target_os = "linux")] render_instance: Res, ) { for window in windows.windows.values_mut() { @@ -263,35 +259,6 @@ pub fn prepare_windows( continue; }; - // This is an ugly hack to work around drivers that don't support MSAA. - // This should be removed once https://github.com/bevyengine/bevy/issues/7194 lands and we're doing proper - // feature detection for MSAA. - // When removed, we can also remove the `.after(prepare_windows)` of `prepare_core_3d_depth_textures` and `prepare_prepass_textures` - let sample_flags = render_adapter - .get_texture_format_features(surface_data.configuration.format) - .flags; - - if !sample_flags.sample_count_supported(msaa.samples()) { - let fallback = if sample_flags.sample_count_supported(Msaa::default().samples()) { - Msaa::default() - } else { - Msaa::Off - }; - - let fallback_str = if fallback == Msaa::Off { - "disabling MSAA".to_owned() - } else { - format!("MSAA {}x", fallback.samples()) - }; - - bevy_utils::tracing::warn!( - "MSAA {}x is not supported on this device. Falling back to {}.", - msaa.samples(), - fallback_str, - ); - *msaa = fallback; - } - // A recurring issue is hitting `wgpu::SurfaceError::Timeout` on certain Linux // mesa driver implementations. This seems to be a quirk of some drivers. // We'd rather keep panicking when not on Linux mesa, because in those case, diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 1ef8ca1eaa935..56be442f49ffa 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -369,7 +369,6 @@ pub fn queue_material2d_meshes( material2d_pipeline: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, - msaa: Res, render_meshes: Res>, render_materials: Res>>, mut render_mesh_instances: ResMut, @@ -379,6 +378,7 @@ pub fn queue_material2d_meshes( Entity, &ExtractedView, &VisibleEntities, + &Msaa, Option<&Tonemapping>, Option<&DebandDither>, )>, @@ -389,7 +389,7 @@ pub fn queue_material2d_meshes( return; } - for (view_entity, view, visible_entities, tonemapping, dither) in &mut views { + for (view_entity, view, visible_entities, msaa, tonemapping, dither) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index d60efb0977eb2..55e64886dabc8 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -472,26 +472,25 @@ pub fn queue_sprites( sprite_pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, extracted_sprites: Res, mut transparent_render_phases: ResMut>, mut views: Query<( Entity, &VisibleEntities, &ExtractedView, + &Msaa, Option<&Tonemapping>, Option<&DebandDither>, )>, ) { - let msaa_key = SpritePipelineKey::from_msaa_samples(msaa.samples()); - let draw_sprite_function = draw_functions.read().id::(); - for (view_entity, visible_entities, view, tonemapping, dither) in &mut views { + for (view_entity, visible_entities, view, msaa, tonemapping, dither) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; + let msaa_key = SpritePipelineKey::from_msaa_samples(msaa.samples()); let mut view_key = SpritePipelineKey::from_hdr(view.hdr) | msaa_key; if !view.hdr { diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index 01195bc39e3ed..fabdafba4c8ab 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -351,17 +351,16 @@ pub fn queue_colored_mesh2d( colored_mesh2d_pipeline: Res, mut pipelines: ResMut>, pipeline_cache: Res, - msaa: Res, render_meshes: Res>, render_mesh_instances: Res, mut transparent_render_phases: ResMut>, - mut views: Query<(Entity, &VisibleEntities, &ExtractedView)>, + mut views: Query<(Entity, &VisibleEntities, &ExtractedView, &Msaa)>, ) { if render_mesh_instances.is_empty() { return; } // Iterate each view (a camera is a view) - for (view_entity, visible_entities, view) in &mut views { + for (view_entity, visible_entities, view, msaa) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; diff --git a/examples/2d/pixel_grid_snap.rs b/examples/2d/pixel_grid_snap.rs index 075dc06818f39..c191ad8c345c3 100644 --- a/examples/2d/pixel_grid_snap.rs +++ b/examples/2d/pixel_grid_snap.rs @@ -29,7 +29,6 @@ const HIGH_RES_LAYERS: RenderLayers = RenderLayers::layer(1); fn main() { App::new() .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) - .insert_resource(Msaa::Off) .add_systems(Startup, (setup_camera, setup_sprite, setup_mesh)) .add_systems(Update, (rotate, fit_canvas)) .run(); @@ -131,6 +130,7 @@ fn setup_camera(mut commands: Commands, mut images: ResMut>) { target: RenderTarget::Image(image_handle.clone()), ..default() }, + msaa: Msaa::Off, ..default() }, InGameCamera, @@ -149,7 +149,14 @@ fn setup_camera(mut commands: Commands, mut images: ResMut>) { // the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen. // here, the canvas and one of the sample sprites will be rendered by this camera - commands.spawn((Camera2dBundle::default(), OuterCamera, HIGH_RES_LAYERS)); + commands.spawn(( + Camera2dBundle { + msaa: Msaa::Off, + ..default() + }, + OuterCamera, + HIGH_RES_LAYERS, + )); } /// Rotates entities to demonstrate grid snapping. diff --git a/examples/3d/anti_aliasing.rs b/examples/3d/anti_aliasing.rs index 4738cf9c8bab3..b5e785b95385d 100644 --- a/examples/3d/anti_aliasing.rs +++ b/examples/3d/anti_aliasing.rs @@ -23,7 +23,6 @@ use bevy::{ fn main() { App::new() - .insert_resource(Msaa::Off) .add_plugins((DefaultPlugins, TemporalAntiAliasPlugin)) .add_systems(Startup, setup) .add_systems(Update, (modify_aa, modify_sharpening, update_ui)) @@ -38,13 +37,13 @@ fn modify_aa( Option<&mut Fxaa>, Option<&mut SmaaSettings>, Option<&TemporalAntiAliasSettings>, + &mut Msaa, ), With, >, - mut msaa: ResMut, mut commands: Commands, ) { - let (camera_entity, fxaa, smaa, taa) = camera.single_mut(); + let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.single_mut(); let mut camera = commands.entity(camera_entity); // No AA @@ -176,13 +175,13 @@ fn update_ui( Option<&SmaaSettings>, Option<&TemporalAntiAliasSettings>, &ContrastAdaptiveSharpeningSettings, + &Msaa, ), With, >, - msaa: Res, mut ui: Query<&mut Text>, ) { - let (fxaa, smaa, taa, cas_settings) = camera.single(); + let (fxaa, smaa, taa, cas_settings, msaa) = camera.single(); let mut ui = ui.single_mut(); let ui = &mut ui.sections[0].value; diff --git a/examples/3d/deferred_rendering.rs b/examples/3d/deferred_rendering.rs index 5ed07ab344bce..1de231aebb277 100644 --- a/examples/3d/deferred_rendering.rs +++ b/examples/3d/deferred_rendering.rs @@ -17,7 +17,6 @@ use bevy::{ fn main() { App::new() - .insert_resource(Msaa::Off) .insert_resource(DefaultOpaqueRendererMethod::deferred()) .insert_resource(DirectionalLightShadowMap { size: 4096 }) .add_plugins(DefaultPlugins) @@ -42,6 +41,8 @@ fn setup( }, transform: Transform::from_xyz(0.7, 0.7, 1.0) .looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y), + // MSAA needs to be off for Deferred rendering + msaa: Msaa::Off, ..default() }, FogSettings { diff --git a/examples/3d/ssr.rs b/examples/3d/ssr.rs index 93c57ae325b98..98859de4d46f9 100644 --- a/examples/3d/ssr.rs +++ b/examples/3d/ssr.rs @@ -98,7 +98,6 @@ fn main() { // reflections at this time. Disable multisampled antialiasing, as deferred // rendering doesn't support that. App::new() - .insert_resource(Msaa::Off) .insert_resource(DefaultOpaqueRendererMethod::deferred()) .init_resource::() .add_plugins(DefaultPlugins.set(WindowPlugin { @@ -236,6 +235,7 @@ fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) { hdr: true, ..default() }, + msaa: Msaa::Off, ..default() }) .insert(EnvironmentMapLight { diff --git a/examples/3d/transmission.rs b/examples/3d/transmission.rs index ea44abb2947a5..b796f95704c6d 100644 --- a/examples/3d/transmission.rs +++ b/examples/3d/transmission.rs @@ -57,8 +57,7 @@ fn main() { // it _greatly enhances_ the look of the resulting blur effects. // Sadly, it's not available under WebGL. #[cfg(not(all(feature = "webgl2", target_arch = "wasm32")))] - app.insert_resource(Msaa::Off) - .add_plugins(TemporalAntiAliasPlugin); + app.add_plugins(TemporalAntiAliasPlugin); app.run(); } @@ -352,6 +351,8 @@ fn setup( }, tonemapping: Tonemapping::TonyMcMapface, exposure: Exposure { ev100: 6.0 }, + #[cfg(not(all(feature = "webgl2", target_arch = "wasm32")))] + msaa: Msaa::Off, ..default() }, #[cfg(not(all(feature = "webgl2", target_arch = "wasm32")))] diff --git a/examples/3d/transparency_3d.rs b/examples/3d/transparency_3d.rs index 63a9c43210909..6c25a1d4106e4 100644 --- a/examples/3d/transparency_3d.rs +++ b/examples/3d/transparency_3d.rs @@ -6,7 +6,6 @@ use bevy::prelude::*; fn main() { App::new() - .insert_resource(Msaa::default()) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, fade_transparency) @@ -100,6 +99,7 @@ fn setup( // Camera commands.spawn(Camera3dBundle { transform: Transform::from_xyz(-2.0, 3.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + msaa: Msaa::Off, ..default() }); } diff --git a/examples/mobile/src/lib.rs b/examples/mobile/src/lib.rs index 50657091755c9..6665f38a5f47b 100644 --- a/examples/mobile/src/lib.rs +++ b/examples/mobile/src/lib.rs @@ -23,14 +23,8 @@ fn main() { ..default() })) .add_systems(Startup, (setup_scene, setup_music)) - .add_systems(Update, (touch_camera, button_handler, handle_lifetime)); - - // MSAA makes some Android devices panic, this is under investigation - // https://github.com/bevyengine/bevy/issues/8229 - #[cfg(target_os = "android")] - app.insert_resource(Msaa::Off); - - app.run(); + .add_systems(Update, (touch_camera, button_handler, handle_lifetime)) + .run(); } fn touch_camera( @@ -109,6 +103,10 @@ fn setup_scene( // camera commands.spawn(Camera3dBundle { transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + // MSAA makes some Android devices panic, this is under investigation + // https://github.com/bevyengine/bevy/issues/8229 + #[cfg(target_os = "android")] + msaa: Msaa::Off, ..default() }); diff --git a/examples/shader/custom_phase_item.rs b/examples/shader/custom_phase_item.rs index 299c64bf8fdab..51c291d7551f8 100644 --- a/examples/shader/custom_phase_item.rs +++ b/examples/shader/custom_phase_item.rs @@ -233,11 +233,10 @@ fn prepare_custom_phase_item_buffers(mut commands: Commands) { fn queue_custom_phase_item( pipeline_cache: Res, custom_phase_pipeline: Res, - msaa: Res, mut opaque_render_phases: ResMut>, opaque_draw_functions: Res>, mut specialized_render_pipelines: ResMut>, - views: Query<(Entity, &VisibleEntities), With>, + views: Query<(Entity, &VisibleEntities, &Msaa), With>, ) { let draw_custom_phase_item = opaque_draw_functions .read() @@ -246,7 +245,7 @@ fn queue_custom_phase_item( // Render phases are per-view, so we need to iterate over all views so that // the entity appears in them. (In this example, we have only one view, but // it's good practice to loop over all views anyway.) - for (view_entity, view_visible_entities) in views.iter() { + for (view_entity, view_visible_entities, msaa) in views.iter() { let Some(opaque_phase) = opaque_render_phases.get_mut(&view_entity) else { continue; }; diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 9ae798b2a7877..b2a8631f87ac1 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -116,24 +116,23 @@ struct InstanceData { fn queue_custom( transparent_3d_draw_functions: Res>, custom_pipeline: Res, - msaa: Res, mut pipelines: ResMut>, pipeline_cache: Res, meshes: Res>, render_mesh_instances: Res, material_meshes: Query>, mut transparent_render_phases: ResMut>, - mut views: Query<(Entity, &ExtractedView)>, + mut views: Query<(Entity, &ExtractedView, &Msaa)>, ) { let draw_custom = transparent_3d_draw_functions.read().id::(); - let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); - - for (view_entity, view) in &mut views { + for (view_entity, view, msaa) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { continue; }; + let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); + let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); let rangefinder = view.rangefinder3d(); for entity in &material_meshes { diff --git a/examples/shader/shader_prepass.rs b/examples/shader/shader_prepass.rs index b3e4b4ab256e6..82515640ec147 100644 --- a/examples/shader/shader_prepass.rs +++ b/examples/shader/shader_prepass.rs @@ -34,8 +34,6 @@ fn main() { )) .add_systems(Startup, setup) .add_systems(Update, (rotate, toggle_prepass_view)) - // Disabling MSAA for maximum compatibility. Shader prepass with MSAA needs GPU capability MULTISAMPLED_SHADING - .insert_resource(Msaa::Off) .run(); } @@ -52,6 +50,8 @@ fn setup( commands.spawn(( Camera3dBundle { transform: Transform::from_xyz(-2.0, 3., 5.0).looking_at(Vec3::ZERO, Vec3::Y), + // Disabling MSAA for maximum compatibility. Shader prepass with MSAA needs GPU capability MULTISAMPLED_SHADING + msaa: Msaa::Off, ..default() }, // To enable the prepass you need to add the components associated with the ones you need