Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_post_process/src/msaa_writeback.rs
9358 views
1
use bevy_app::{App, Plugin};
2
use bevy_camera::MsaaWriteback;
3
use bevy_color::LinearRgba;
4
use bevy_core_pipeline::{
5
blit::{BlitPipeline, BlitPipelineKey},
6
schedule::{Core2d, Core2dSystems, Core3d, Core3dSystems},
7
};
8
use bevy_ecs::prelude::*;
9
use bevy_render::{
10
camera::ExtractedCamera,
11
diagnostic::RecordDiagnostics,
12
render_resource::*,
13
renderer::{RenderContext, ViewQuery},
14
view::{Msaa, ViewTarget},
15
Render, RenderApp, RenderSystems,
16
};
17
18
/// This enables "msaa writeback" support for the `core_2d` and `core_3d` pipelines, which can be enabled on cameras
19
/// using [`bevy_camera::Camera::msaa_writeback`]. See the docs on that field for more information.
20
#[derive(Default)]
21
pub struct MsaaWritebackPlugin;
22
23
impl Plugin for MsaaWritebackPlugin {
24
fn build(&self, app: &mut App) {
25
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
26
return;
27
};
28
render_app.add_systems(
29
Render,
30
prepare_msaa_writeback_pipelines.in_set(RenderSystems::Prepare),
31
);
32
render_app.add_systems(Core3d, msaa_writeback.before(Core3dSystems::MainPass));
33
render_app.add_systems(Core2d, msaa_writeback.before(Core2dSystems::MainPass));
34
}
35
}
36
37
pub(crate) fn msaa_writeback(
38
view: ViewQuery<(&ViewTarget, &MsaaWritebackBlitPipeline, &Msaa)>,
39
blit_pipeline: Res<BlitPipeline>,
40
pipeline_cache: Res<PipelineCache>,
41
mut ctx: RenderContext,
42
) {
43
let (target, blit_pipeline_id, msaa) = view.into_inner();
44
45
if *msaa == Msaa::Off {
46
return;
47
}
48
49
let Some(pipeline) = pipeline_cache.get_render_pipeline(blit_pipeline_id.0) else {
50
return;
51
};
52
53
// The current "main texture" needs to be bound as an input resource, and we need the "other"
54
// unused target to be the "resolve target" for the MSAA write. Therefore this is the same
55
// as a post process write!
56
let post_process = target.post_process_write();
57
58
let pass_descriptor = RenderPassDescriptor {
59
label: Some("msaa_writeback"),
60
// The target's "resolve target" is the "destination" in post_process.
61
// We will indirectly write the results to the "destination" using
62
// the MSAA resolve step.
63
color_attachments: &[Some(RenderPassColorAttachment {
64
// If MSAA is enabled, then the sampled texture will always exist
65
view: target.sampled_main_texture_view().unwrap(),
66
depth_slice: None,
67
resolve_target: Some(post_process.destination),
68
ops: Operations {
69
load: LoadOp::Clear(LinearRgba::BLACK.into()),
70
store: StoreOp::Store,
71
},
72
})],
73
depth_stencil_attachment: None,
74
timestamp_writes: None,
75
occlusion_query_set: None,
76
multiview_mask: None,
77
};
78
79
let bind_group =
80
blit_pipeline.create_bind_group(ctx.render_device(), post_process.source, &pipeline_cache);
81
82
let diagnostics = ctx.diagnostic_recorder();
83
let diagnostics = diagnostics.as_deref();
84
let time_span = diagnostics.time_span(ctx.command_encoder(), "msaa_writeback");
85
86
{
87
let mut render_pass = ctx.command_encoder().begin_render_pass(&pass_descriptor);
88
89
render_pass.set_pipeline(pipeline);
90
render_pass.set_bind_group(0, &bind_group, &[]);
91
render_pass.draw(0..3, 0..1);
92
}
93
94
time_span.end(ctx.command_encoder());
95
}
96
97
#[derive(Component)]
98
pub struct MsaaWritebackBlitPipeline(CachedRenderPipelineId);
99
100
fn prepare_msaa_writeback_pipelines(
101
mut commands: Commands,
102
pipeline_cache: Res<PipelineCache>,
103
mut pipelines: ResMut<SpecializedRenderPipelines<BlitPipeline>>,
104
blit_pipeline: Res<BlitPipeline>,
105
view_targets: Query<(Entity, &ViewTarget, &ExtractedCamera, &Msaa)>,
106
) {
107
for (entity, view_target, camera, msaa) in view_targets.iter() {
108
// Determine if we should do MSAA writeback based on the camera's setting
109
let should_writeback = match camera.msaa_writeback {
110
MsaaWriteback::Off => false,
111
MsaaWriteback::Auto => camera.sorted_camera_index_for_target > 0,
112
MsaaWriteback::Always => true,
113
};
114
115
if msaa.samples() > 1 && should_writeback {
116
let key = BlitPipelineKey {
117
texture_format: view_target.main_texture_format(),
118
samples: msaa.samples(),
119
blend_state: None,
120
};
121
122
let pipeline = pipelines.specialize(&pipeline_cache, &blit_pipeline, key);
123
commands
124
.entity(entity)
125
.insert(MsaaWritebackBlitPipeline(pipeline));
126
} else {
127
// This isn't strictly necessary now, but if we move to retained render entity state I don't
128
// want this to silently break
129
commands
130
.entity(entity)
131
.remove::<MsaaWritebackBlitPipeline>();
132
}
133
}
134
}
135
136