Use RenderStartup in bevy_anti_aliasing. (#19897)

# Objective

- Progress towards #19887.

## Solution

- Rewrite the FromWorld impls to systems that create the pipeline
resources.

## Testing

- Ran the `anti_aliasing` example and it still works.
This commit is contained in:
andriyDev 2025-07-02 15:38:44 -07:00 committed by GitHub
parent e70f84536a
commit 8098cf21ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 176 additions and 196 deletions

View File

@ -1,5 +1,5 @@
use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
@ -18,7 +18,7 @@ use bevy_render::{
},
renderer::RenderDevice,
view::{ExtractedView, ViewTarget},
Render, RenderApp, RenderSystems,
Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::default;
@ -114,6 +114,7 @@ impl Plugin for CasPlugin {
};
render_app
.init_resource::<SpecializedRenderPipelines<CasPipeline>>()
.add_systems(RenderStartup, init_cas_pipeline)
.add_systems(Render, prepare_cas_pipelines.in_set(RenderSystems::Prepare));
{
@ -151,13 +152,6 @@ impl Plugin for CasPlugin {
);
}
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app.init_resource::<CasPipeline>();
}
}
#[derive(Resource)]
@ -168,34 +162,36 @@ pub struct CasPipeline {
fragment_shader: Handle<Shader>,
}
impl FromWorld for CasPipeline {
fn from_world(render_world: &mut World) -> Self {
let render_device = render_world.resource::<RenderDevice>();
let texture_bind_group = render_device.create_bind_group_layout(
"sharpening_texture_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
// CAS Settings
uniform_buffer::<CasUniform>(true),
),
pub fn init_cas_pipeline(
mut commands: Commands,
render_device: Res<RenderDevice>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
) {
let texture_bind_group = render_device.create_bind_group_layout(
"sharpening_texture_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
// CAS Settings
uniform_buffer::<CasUniform>(true),
),
);
),
);
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
CasPipeline {
texture_bind_group,
sampler,
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(
render_world,
"robust_contrast_adaptive_sharpening.wgsl"
),
}
}
commands.insert_resource(CasPipeline {
texture_bind_group,
sampler,
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(
asset_server.as_ref(),
"robust_contrast_adaptive_sharpening.wgsl"
),
});
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]

View File

@ -1,5 +1,5 @@
use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
@ -18,7 +18,7 @@ use bevy_render::{
},
renderer::RenderDevice,
view::{ExtractedView, ViewTarget},
Render, RenderApp, RenderSystems,
Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::default;
@ -94,6 +94,7 @@ impl Plugin for FxaaPlugin {
};
render_app
.init_resource::<SpecializedRenderPipelines<FxaaPipeline>>()
.add_systems(RenderStartup, init_fxaa_pipeline)
.add_systems(
Render,
prepare_fxaa_pipelines.in_set(RenderSystems::Prepare),
@ -117,13 +118,6 @@ impl Plugin for FxaaPlugin {
),
);
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app.init_resource::<FxaaPipeline>();
}
}
#[derive(Resource)]
@ -134,34 +128,36 @@ pub struct FxaaPipeline {
fragment_shader: Handle<Shader>,
}
impl FromWorld for FxaaPipeline {
fn from_world(render_world: &mut World) -> Self {
let render_device = render_world.resource::<RenderDevice>();
let texture_bind_group = render_device.create_bind_group_layout(
"fxaa_texture_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
),
pub fn init_fxaa_pipeline(
mut commands: Commands,
render_device: Res<RenderDevice>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
) {
let texture_bind_group = render_device.create_bind_group_layout(
"fxaa_texture_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
),
);
),
);
let sampler = render_device.create_sampler(&SamplerDescriptor {
mipmap_filter: FilterMode::Linear,
mag_filter: FilterMode::Linear,
min_filter: FilterMode::Linear,
..default()
});
let sampler = render_device.create_sampler(&SamplerDescriptor {
mipmap_filter: FilterMode::Linear,
mag_filter: FilterMode::Linear,
min_filter: FilterMode::Linear,
..default()
});
FxaaPipeline {
texture_bind_group,
sampler,
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
}
}
commands.insert_resource(FxaaPipeline {
texture_bind_group,
sampler,
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "fxaa.wgsl"),
});
}
#[derive(Component)]

View File

@ -32,7 +32,7 @@
use bevy_app::{App, Plugin};
#[cfg(feature = "smaa_luts")]
use bevy_asset::load_internal_binary_asset;
use bevy_asset::{embedded_asset, load_embedded_asset, uuid_handle, Handle};
use bevy_asset::{embedded_asset, load_embedded_asset, uuid_handle, AssetServer, Handle};
#[cfg(not(feature = "smaa_luts"))]
use bevy_core_pipeline::tonemapping::lut_placeholder;
use bevy_core_pipeline::{
@ -48,7 +48,7 @@ use bevy_ecs::{
resource::Resource,
schedule::IntoScheduleConfigs as _,
system::{lifetimeless::Read, Commands, Query, Res, ResMut},
world::{FromWorld, World},
world::World,
};
use bevy_image::{BevyDefault, Image, ToExtents};
use bevy_math::{vec4, Vec4};
@ -75,7 +75,7 @@ use bevy_render::{
renderer::{RenderContext, RenderDevice, RenderQueue},
texture::{CachedTexture, GpuImage, TextureCache},
view::{ExtractedView, ViewTarget},
Render, RenderApp, RenderSystems,
Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::prelude::default;
@ -346,6 +346,7 @@ impl Plugin for SmaaPlugin {
render_app
.init_resource::<SmaaSpecializedRenderPipelines>()
.init_resource::<SmaaInfoUniformBuffer>()
.add_systems(RenderStartup, init_smaa_pipelines)
.add_systems(
Render,
(
@ -374,86 +375,79 @@ impl Plugin for SmaaPlugin {
),
);
}
fn finish(&self, app: &mut App) {
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.init_resource::<SmaaPipelines>();
}
}
}
impl FromWorld for SmaaPipelines {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
// Create the postprocess bind group layout (all passes, bind group 0).
let postprocess_bind_group_layout = render_device.create_bind_group_layout(
"SMAA postprocess bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
uniform_buffer::<SmaaInfoUniform>(true)
.visibility(ShaderStages::VERTEX_FRAGMENT),
),
pub fn init_smaa_pipelines(
mut commands: Commands,
render_device: Res<RenderDevice>,
asset_server: Res<AssetServer>,
) {
// Create the postprocess bind group layout (all passes, bind group 0).
let postprocess_bind_group_layout = render_device.create_bind_group_layout(
"SMAA postprocess bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
uniform_buffer::<SmaaInfoUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
),
);
),
);
// Create the edge detection bind group layout (pass 1, bind group 1).
let edge_detection_bind_group_layout = render_device.create_bind_group_layout(
"SMAA edge detection bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(sampler(SamplerBindingType::Filtering),),
// Create the edge detection bind group layout (pass 1, bind group 1).
let edge_detection_bind_group_layout = render_device.create_bind_group_layout(
"SMAA edge detection bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(sampler(SamplerBindingType::Filtering),),
),
);
// Create the blending weight calculation bind group layout (pass 2, bind group 1).
let blending_weight_calculation_bind_group_layout = render_device.create_bind_group_layout(
"SMAA blending weight calculation bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }), // edges texture
sampler(SamplerBindingType::Filtering), // edges sampler
texture_2d(TextureSampleType::Float { filterable: true }), // search texture
texture_2d(TextureSampleType::Float { filterable: true }), // area texture
),
);
),
);
// Create the blending weight calculation bind group layout (pass 2, bind group 1).
let blending_weight_calculation_bind_group_layout = render_device.create_bind_group_layout(
"SMAA blending weight calculation bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }), // edges texture
sampler(SamplerBindingType::Filtering), // edges sampler
texture_2d(TextureSampleType::Float { filterable: true }), // search texture
texture_2d(TextureSampleType::Float { filterable: true }), // area texture
),
// Create the neighborhood blending bind group layout (pass 3, bind group 1).
let neighborhood_blending_bind_group_layout = render_device.create_bind_group_layout(
"SMAA neighborhood blending bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
),
);
),
);
// Create the neighborhood blending bind group layout (pass 3, bind group 1).
let neighborhood_blending_bind_group_layout = render_device.create_bind_group_layout(
"SMAA neighborhood blending bind group layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
),
),
);
let shader = load_embedded_asset!(asset_server.as_ref(), "smaa.wgsl");
let shader = load_embedded_asset!(world, "smaa.wgsl");
SmaaPipelines {
edge_detection: SmaaEdgeDetectionPipeline {
postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
edge_detection_bind_group_layout,
shader: shader.clone(),
},
blending_weight_calculation: SmaaBlendingWeightCalculationPipeline {
postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
blending_weight_calculation_bind_group_layout,
shader: shader.clone(),
},
neighborhood_blending: SmaaNeighborhoodBlendingPipeline {
postprocess_bind_group_layout,
neighborhood_blending_bind_group_layout,
shader,
},
}
}
commands.insert_resource(SmaaPipelines {
edge_detection: SmaaEdgeDetectionPipeline {
postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
edge_detection_bind_group_layout,
shader: shader.clone(),
},
blending_weight_calculation: SmaaBlendingWeightCalculationPipeline {
postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
blending_weight_calculation_bind_group_layout,
shader: shader.clone(),
},
neighborhood_blending: SmaaNeighborhoodBlendingPipeline {
postprocess_bind_group_layout,
neighborhood_blending_bind_group_layout,
shader,
},
});
}
// Phase 1: edge detection.

View File

@ -1,5 +1,5 @@
use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d},
prelude::Camera3d,
@ -13,7 +13,7 @@ use bevy_ecs::{
resource::Resource,
schedule::IntoScheduleConfigs,
system::{Commands, Query, Res, ResMut},
world::{FromWorld, World},
world::World,
};
use bevy_image::{BevyDefault as _, ToExtents};
use bevy_math::vec2;
@ -36,7 +36,7 @@ use bevy_render::{
sync_world::RenderEntity,
texture::{CachedTexture, TextureCache},
view::{ExtractedView, Msaa, ViewTarget},
ExtractSchedule, MainWorld, Render, RenderApp, RenderSystems,
ExtractSchedule, MainWorld, Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::default;
use tracing::warn;
@ -59,6 +59,7 @@ impl Plugin for TemporalAntiAliasPlugin {
};
render_app
.init_resource::<SpecializedRenderPipelines<TaaPipeline>>()
.add_systems(RenderStartup, init_taa_pipeline)
.add_systems(ExtractSchedule, extract_taa_settings)
.add_systems(
Render,
@ -80,14 +81,6 @@ impl Plugin for TemporalAntiAliasPlugin {
),
);
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app.init_resource::<TaaPipeline>();
}
}
/// Component to apply temporal anti-aliasing to a 3D perspective camera.
@ -243,52 +236,53 @@ struct TaaPipeline {
fragment_shader: Handle<Shader>,
}
impl FromWorld for TaaPipeline {
fn from_world(world: &mut World) -> Self {
let render_device = world.resource::<RenderDevice>();
fn init_taa_pipeline(
mut commands: Commands,
render_device: Res<RenderDevice>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
) {
let nearest_sampler = render_device.create_sampler(&SamplerDescriptor {
label: Some("taa_nearest_sampler"),
mag_filter: FilterMode::Nearest,
min_filter: FilterMode::Nearest,
..SamplerDescriptor::default()
});
let linear_sampler = render_device.create_sampler(&SamplerDescriptor {
label: Some("taa_linear_sampler"),
mag_filter: FilterMode::Linear,
min_filter: FilterMode::Linear,
..SamplerDescriptor::default()
});
let nearest_sampler = render_device.create_sampler(&SamplerDescriptor {
label: Some("taa_nearest_sampler"),
mag_filter: FilterMode::Nearest,
min_filter: FilterMode::Nearest,
..SamplerDescriptor::default()
});
let linear_sampler = render_device.create_sampler(&SamplerDescriptor {
label: Some("taa_linear_sampler"),
mag_filter: FilterMode::Linear,
min_filter: FilterMode::Linear,
..SamplerDescriptor::default()
});
let taa_bind_group_layout = render_device.create_bind_group_layout(
"taa_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
// View target (read)
texture_2d(TextureSampleType::Float { filterable: true }),
// TAA History (read)
texture_2d(TextureSampleType::Float { filterable: true }),
// Motion Vectors
texture_2d(TextureSampleType::Float { filterable: true }),
// Depth
texture_depth_2d(),
// Nearest sampler
sampler(SamplerBindingType::NonFiltering),
// Linear sampler
sampler(SamplerBindingType::Filtering),
),
let taa_bind_group_layout = render_device.create_bind_group_layout(
"taa_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
// View target (read)
texture_2d(TextureSampleType::Float { filterable: true }),
// TAA History (read)
texture_2d(TextureSampleType::Float { filterable: true }),
// Motion Vectors
texture_2d(TextureSampleType::Float { filterable: true }),
// Depth
texture_depth_2d(),
// Nearest sampler
sampler(SamplerBindingType::NonFiltering),
// Linear sampler
sampler(SamplerBindingType::Filtering),
),
);
),
);
TaaPipeline {
taa_bind_group_layout,
nearest_sampler,
linear_sampler,
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "taa.wgsl"),
}
}
commands.insert_resource(TaaPipeline {
taa_bind_group_layout,
nearest_sampler,
linear_sampler,
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "taa.wgsl"),
});
}
#[derive(PartialEq, Eq, Hash, Clone)]