bevy_post_process/
msaa_writeback.rs1use bevy_app::{App, Plugin};
2use bevy_color::LinearRgba;
3use bevy_core_pipeline::{
4 blit::{BlitPipeline, BlitPipelineKey},
5 core_2d::graph::{Core2d, Node2d},
6 core_3d::graph::{Core3d, Node3d},
7};
8use bevy_ecs::{prelude::*, query::QueryItem};
9use bevy_render::{
10 camera::ExtractedCamera,
11 diagnostic::RecordDiagnostics,
12 render_graph::{NodeRunError, RenderGraphContext, RenderGraphExt, ViewNode, ViewNodeRunner},
13 render_resource::*,
14 renderer::RenderContext,
15 view::{Msaa, ViewTarget},
16 Render, RenderApp, RenderSystems,
17};
18
19#[derive(Default)]
22pub struct MsaaWritebackPlugin;
23
24impl Plugin for MsaaWritebackPlugin {
25 fn build(&self, app: &mut App) {
26 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
27 return;
28 };
29 render_app.add_systems(
30 Render,
31 prepare_msaa_writeback_pipelines.in_set(RenderSystems::Prepare),
32 );
33 {
34 render_app
35 .add_render_graph_node::<ViewNodeRunner<MsaaWritebackNode>>(
36 Core2d,
37 Node2d::MsaaWriteback,
38 )
39 .add_render_graph_edge(Core2d, Node2d::MsaaWriteback, Node2d::StartMainPass);
40 }
41 {
42 render_app
43 .add_render_graph_node::<ViewNodeRunner<MsaaWritebackNode>>(
44 Core3d,
45 Node3d::MsaaWriteback,
46 )
47 .add_render_graph_edge(Core3d, Node3d::MsaaWriteback, Node3d::StartMainPass);
48 }
49 }
50}
51
52#[derive(Default)]
53pub struct MsaaWritebackNode;
54
55impl ViewNode for MsaaWritebackNode {
56 type ViewQuery = (
57 &'static ViewTarget,
58 &'static MsaaWritebackBlitPipeline,
59 &'static Msaa,
60 );
61
62 fn run<'w>(
63 &self,
64 _graph: &mut RenderGraphContext,
65 render_context: &mut RenderContext<'w>,
66 (target, blit_pipeline_id, msaa): QueryItem<'w, '_, Self::ViewQuery>,
67 world: &'w World,
68 ) -> Result<(), NodeRunError> {
69 if *msaa == Msaa::Off {
70 return Ok(());
71 }
72
73 let blit_pipeline = world.resource::<BlitPipeline>();
74 let pipeline_cache = world.resource::<PipelineCache>();
75 let Some(pipeline) = pipeline_cache.get_render_pipeline(blit_pipeline_id.0) else {
76 return Ok(());
77 };
78
79 let diagnostics = render_context.diagnostic_recorder();
80
81 let post_process = target.post_process_write();
85
86 let pass_descriptor = RenderPassDescriptor {
87 label: Some("msaa_writeback"),
88 color_attachments: &[Some(RenderPassColorAttachment {
92 view: target.sampled_main_texture_view().unwrap(),
94 depth_slice: None,
95 resolve_target: Some(post_process.destination),
96 ops: Operations {
97 load: LoadOp::Clear(LinearRgba::BLACK.into()),
98 store: StoreOp::Store,
99 },
100 })],
101 depth_stencil_attachment: None,
102 timestamp_writes: None,
103 occlusion_query_set: None,
104 };
105
106 let bind_group =
107 blit_pipeline.create_bind_group(render_context.render_device(), post_process.source);
108
109 let mut render_pass = render_context
110 .command_encoder()
111 .begin_render_pass(&pass_descriptor);
112 let pass_span = diagnostics.pass_span(&mut render_pass, "msaa_writeback");
113
114 render_pass.set_pipeline(pipeline);
115 render_pass.set_bind_group(0, &bind_group, &[]);
116 render_pass.draw(0..3, 0..1);
117
118 pass_span.end(&mut render_pass);
119
120 Ok(())
121 }
122}
123
124#[derive(Component)]
125pub struct MsaaWritebackBlitPipeline(CachedRenderPipelineId);
126
127fn prepare_msaa_writeback_pipelines(
128 mut commands: Commands,
129 pipeline_cache: Res<PipelineCache>,
130 mut pipelines: ResMut<SpecializedRenderPipelines<BlitPipeline>>,
131 blit_pipeline: Res<BlitPipeline>,
132 view_targets: Query<(Entity, &ViewTarget, &ExtractedCamera, &Msaa)>,
133) {
134 for (entity, view_target, camera, msaa) in view_targets.iter() {
135 if msaa.samples() > 1 && camera.msaa_writeback && camera.sorted_camera_index_for_target > 0
138 {
139 let key = BlitPipelineKey {
140 texture_format: view_target.main_texture_format(),
141 samples: msaa.samples(),
142 blend_state: None,
143 };
144
145 let pipeline = pipelines.specialize(&pipeline_cache, &blit_pipeline, key);
146 commands
147 .entity(entity)
148 .insert(MsaaWritebackBlitPipeline(pipeline));
149 } else {
150 commands
153 .entity(entity)
154 .remove::<MsaaWritebackBlitPipeline>();
155 }
156 }
157}