Record bloom render commands in parallel (#18330)
Closes https://github.com/bevyengine/bevy/issues/18304. Requesting that someone more experienced with tracy test performance on a larger scene please!
This commit is contained in:
parent
37b62b83c4
commit
8481b63ed8
@ -2,7 +2,6 @@ mod downsampling_pipeline;
|
||||
mod settings;
|
||||
mod upsampling_pipeline;
|
||||
|
||||
use bevy_color::{Gray, LinearRgba};
|
||||
pub use settings::{Bloom, BloomCompositeMode, BloomPrefilter};
|
||||
|
||||
use crate::{
|
||||
@ -11,6 +10,7 @@ use crate::{
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, weak_handle, Handle};
|
||||
use bevy_color::{Gray, LinearRgba};
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_math::{ops, UVec2};
|
||||
use bevy_render::{
|
||||
@ -30,6 +30,8 @@ use downsampling_pipeline::{
|
||||
prepare_downsampling_pipeline, BloomDownsamplingPipeline, BloomDownsamplingPipelineIds,
|
||||
BloomUniforms,
|
||||
};
|
||||
#[cfg(feature = "trace")]
|
||||
use tracing::info_span;
|
||||
use upsampling_pipeline::{
|
||||
prepare_upsampling_pipeline, BloomUpsamplingPipeline, UpsamplingPipelineIds,
|
||||
};
|
||||
@ -108,10 +110,10 @@ impl ViewNode for BloomNode {
|
||||
// Atypically for a post-processing effect, we do not need to
|
||||
// use a secondary texture normally provided by view_target.post_process_write(),
|
||||
// instead we write into our own bloom texture and then directly back onto main.
|
||||
fn run(
|
||||
fn run<'w>(
|
||||
&self,
|
||||
_graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(
|
||||
camera,
|
||||
view_target,
|
||||
@ -121,8 +123,8 @@ impl ViewNode for BloomNode {
|
||||
bloom_settings,
|
||||
upsampling_pipeline_ids,
|
||||
downsampling_pipeline_ids,
|
||||
): QueryItem<Self::ViewQuery>,
|
||||
world: &World,
|
||||
): QueryItem<'w, Self::ViewQuery>,
|
||||
world: &'w World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
if bloom_settings.intensity == 0.0 {
|
||||
return Ok(());
|
||||
@ -149,133 +151,152 @@ impl ViewNode for BloomNode {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
render_context.command_encoder().push_debug_group("bloom");
|
||||
|
||||
let view_texture = view_target.main_texture_view();
|
||||
let view_texture_unsampled = view_target.get_unsampled_color_attachment();
|
||||
let diagnostics = render_context.diagnostic_recorder();
|
||||
let command_encoder = render_context.command_encoder();
|
||||
let time_span = diagnostics.time_span(command_encoder, "bloom");
|
||||
|
||||
// First downsample pass
|
||||
{
|
||||
let downsampling_first_bind_group = render_context.render_device().create_bind_group(
|
||||
"bloom_downsampling_first_bind_group",
|
||||
&downsampling_pipeline_res.bind_group_layout,
|
||||
&BindGroupEntries::sequential((
|
||||
// Read from main texture directly
|
||||
view_target.main_texture_view(),
|
||||
&bind_groups.sampler,
|
||||
uniforms.clone(),
|
||||
)),
|
||||
);
|
||||
render_context.add_command_buffer_generation_task(move |render_device| {
|
||||
#[cfg(feature = "trace")]
|
||||
let _bloom_span = info_span!("bloom").entered();
|
||||
|
||||
let view = &bloom_texture.view(0);
|
||||
let mut downsampling_first_pass =
|
||||
render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||
label: Some("bloom_downsampling_first_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations::default(),
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
let mut command_encoder =
|
||||
render_device.create_command_encoder(&CommandEncoderDescriptor {
|
||||
label: Some("bloom_command_encoder"),
|
||||
});
|
||||
downsampling_first_pass.set_render_pipeline(downsampling_first_pipeline);
|
||||
downsampling_first_pass.set_bind_group(
|
||||
0,
|
||||
&downsampling_first_bind_group,
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
downsampling_first_pass.draw(0..3, 0..1);
|
||||
}
|
||||
command_encoder.push_debug_group("bloom");
|
||||
let time_span = diagnostics.time_span(&mut command_encoder, "bloom");
|
||||
|
||||
// Other downsample passes
|
||||
for mip in 1..bloom_texture.mip_count {
|
||||
let view = &bloom_texture.view(mip);
|
||||
let mut downsampling_pass =
|
||||
render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||
label: Some("bloom_downsampling_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations::default(),
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
downsampling_pass.set_render_pipeline(downsampling_pipeline);
|
||||
downsampling_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.downsampling_bind_groups[mip as usize - 1],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
downsampling_pass.draw(0..3, 0..1);
|
||||
}
|
||||
// First downsample pass
|
||||
{
|
||||
let downsampling_first_bind_group = render_device.create_bind_group(
|
||||
"bloom_downsampling_first_bind_group",
|
||||
&downsampling_pipeline_res.bind_group_layout,
|
||||
&BindGroupEntries::sequential((
|
||||
// Read from main texture directly
|
||||
view_texture,
|
||||
&bind_groups.sampler,
|
||||
uniforms.clone(),
|
||||
)),
|
||||
);
|
||||
|
||||
// Upsample passes except the final one
|
||||
for mip in (1..bloom_texture.mip_count).rev() {
|
||||
let view = &bloom_texture.view(mip - 1);
|
||||
let mut upsampling_pass =
|
||||
render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||
label: Some("bloom_upsampling_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations {
|
||||
load: LoadOp::Load,
|
||||
store: StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
upsampling_pass.set_render_pipeline(upsampling_pipeline);
|
||||
upsampling_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.upsampling_bind_groups[(bloom_texture.mip_count - mip - 1) as usize],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
let blend = compute_blend_factor(
|
||||
bloom_settings,
|
||||
mip as f32,
|
||||
(bloom_texture.mip_count - 1) as f32,
|
||||
);
|
||||
upsampling_pass.set_blend_constant(LinearRgba::gray(blend));
|
||||
upsampling_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
// Final upsample pass
|
||||
// This is very similar to the above upsampling passes with the only difference
|
||||
// being the pipeline (which itself is barely different) and the color attachment
|
||||
{
|
||||
let mut upsampling_final_pass =
|
||||
render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||
label: Some("bloom_upsampling_final_pass"),
|
||||
color_attachments: &[Some(view_target.get_unsampled_color_attachment())],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
upsampling_final_pass.set_render_pipeline(upsampling_final_pipeline);
|
||||
upsampling_final_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.upsampling_bind_groups[(bloom_texture.mip_count - 1) as usize],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
upsampling_final_pass.set_camera_viewport(viewport);
|
||||
let view = &bloom_texture.view(0);
|
||||
let mut downsampling_first_pass =
|
||||
command_encoder.begin_render_pass(&RenderPassDescriptor {
|
||||
label: Some("bloom_downsampling_first_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations::default(),
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
downsampling_first_pass.set_pipeline(downsampling_first_pipeline);
|
||||
downsampling_first_pass.set_bind_group(
|
||||
0,
|
||||
&downsampling_first_bind_group,
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
downsampling_first_pass.draw(0..3, 0..1);
|
||||
}
|
||||
let blend =
|
||||
compute_blend_factor(bloom_settings, 0.0, (bloom_texture.mip_count - 1) as f32);
|
||||
upsampling_final_pass.set_blend_constant(LinearRgba::gray(blend));
|
||||
upsampling_final_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
time_span.end(render_context.command_encoder());
|
||||
render_context.command_encoder().pop_debug_group();
|
||||
// Other downsample passes
|
||||
for mip in 1..bloom_texture.mip_count {
|
||||
let view = &bloom_texture.view(mip);
|
||||
let mut downsampling_pass =
|
||||
command_encoder.begin_render_pass(&RenderPassDescriptor {
|
||||
label: Some("bloom_downsampling_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations::default(),
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
downsampling_pass.set_pipeline(downsampling_pipeline);
|
||||
downsampling_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.downsampling_bind_groups[mip as usize - 1],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
downsampling_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
// Upsample passes except the final one
|
||||
for mip in (1..bloom_texture.mip_count).rev() {
|
||||
let view = &bloom_texture.view(mip - 1);
|
||||
let mut upsampling_pass =
|
||||
command_encoder.begin_render_pass(&RenderPassDescriptor {
|
||||
label: Some("bloom_upsampling_pass"),
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: Operations {
|
||||
load: LoadOp::Load,
|
||||
store: StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
upsampling_pass.set_pipeline(upsampling_pipeline);
|
||||
upsampling_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.upsampling_bind_groups
|
||||
[(bloom_texture.mip_count - mip - 1) as usize],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
let blend = compute_blend_factor(
|
||||
bloom_settings,
|
||||
mip as f32,
|
||||
(bloom_texture.mip_count - 1) as f32,
|
||||
);
|
||||
upsampling_pass.set_blend_constant(LinearRgba::gray(blend).into());
|
||||
upsampling_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
// Final upsample pass
|
||||
// This is very similar to the above upsampling passes with the only difference
|
||||
// being the pipeline (which itself is barely different) and the color attachment
|
||||
{
|
||||
let mut upsampling_final_pass =
|
||||
command_encoder.begin_render_pass(&RenderPassDescriptor {
|
||||
label: Some("bloom_upsampling_final_pass"),
|
||||
color_attachments: &[Some(view_texture_unsampled)],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
upsampling_final_pass.set_pipeline(upsampling_final_pipeline);
|
||||
upsampling_final_pass.set_bind_group(
|
||||
0,
|
||||
&bind_groups.upsampling_bind_groups[(bloom_texture.mip_count - 1) as usize],
|
||||
&[uniform_index.index()],
|
||||
);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
upsampling_final_pass.set_viewport(
|
||||
viewport.physical_position.x as f32,
|
||||
viewport.physical_position.y as f32,
|
||||
viewport.physical_size.x as f32,
|
||||
viewport.physical_size.y as f32,
|
||||
viewport.depth.start,
|
||||
viewport.depth.end,
|
||||
);
|
||||
}
|
||||
let blend =
|
||||
compute_blend_factor(bloom_settings, 0.0, (bloom_texture.mip_count - 1) as f32);
|
||||
upsampling_final_pass.set_blend_constant(LinearRgba::gray(blend).into());
|
||||
upsampling_final_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
time_span.end(&mut command_encoder);
|
||||
command_encoder.pop_debug_group();
|
||||
command_encoder.finish()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user