From 1c5ee801ae1434becef15678664ae79b28bdd113 Mon Sep 17 00:00:00 2001 From: andriyDev Date: Fri, 18 Jul 2025 01:12:55 -0700 Subject: [PATCH 1/2] Use `RenderStartup` for atmosphere rendering. --- crates/bevy_pbr/src/atmosphere/mod.rs | 150 ++++--- crates/bevy_pbr/src/atmosphere/resources.rs | 434 ++++++++++---------- 2 files changed, 301 insertions(+), 283 deletions(-) diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index ed4dabdf9621e..6ee405d298f51 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -42,8 +42,10 @@ use bevy_core_pipeline::core_3d::graph::Node3d; use bevy_ecs::{ component::Component, query::{Changed, QueryItem, With}, - schedule::IntoScheduleConfigs, - system::{lifetimeless::Read, Query}, + resource::Resource, + schedule::{common_conditions::resource_exists, IntoScheduleConfigs, SystemSet}, + system::{lifetimeless::Read, Commands, Query, Res}, + world::World, }; use bevy_math::{UVec2, UVec3, Vec3}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; @@ -52,6 +54,7 @@ use bevy_render::{ load_shader_library, render_resource::{DownlevelFlags, ShaderType, SpecializedRenderPipelines}, view::Hdr, + RenderStartup, }; use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, @@ -68,12 +71,14 @@ use resources::{ }; use tracing::warn; +use crate::resources::{ + init_atmosphere_bind_group_layouts, init_atmosphere_lut_pipelines, init_atmosphere_samplers, + init_render_sky_bind_group_layouts, +}; + use self::{ node::{AtmosphereLutsNode, AtmosphereNode, RenderSkyNode}, - resources::{ - prepare_atmosphere_bind_groups, prepare_atmosphere_textures, AtmosphereBindGroupLayouts, - AtmosphereLutPipelines, AtmosphereSamplers, - }, + resources::{prepare_atmosphere_bind_groups, prepare_atmosphere_textures}, }; #[doc(hidden)] @@ -100,40 +105,39 @@ impl Plugin for AtmospherePlugin { UniformComponentPlugin::::default(), UniformComponentPlugin::::default(), )); - } - fn finish(&self, app: &mut App) { let Some(render_app) = app.get_sub_app_mut(RenderApp) else { return; }; - let render_adapter = render_app.world().resource::(); - - if !render_adapter - .get_downlevel_capabilities() - .flags - .contains(DownlevelFlags::COMPUTE_SHADERS) - { - warn!("AtmospherePlugin not loaded. GPU lacks support for compute shaders."); - return; - } - - if !render_adapter - .get_texture_format_features(TextureFormat::Rgba16Float) - .allowed_usages - .contains(TextureUsages::STORAGE_BINDING) - { - warn!("AtmospherePlugin not loaded. GPU lacks support: TextureFormat::Rgba16Float does not support TextureUsages::STORAGE_BINDING."); - return; - } - render_app - .init_resource::() - .init_resource::() - .init_resource::() - .init_resource::() .init_resource::() .init_resource::>() + .configure_sets( + RenderStartup, + AtmosphereSystems + .after(check_atmosphere_supported) + .run_if(resource_exists::), + ) + .configure_sets( + Render, + AtmosphereSystems.run_if(resource_exists::), + ) + .add_systems(RenderStartup, check_atmosphere_supported) + .add_systems( + RenderStartup, + ( + add_atmosphere_render_graph_nodes, + init_render_sky_bind_group_layouts, + init_atmosphere_samplers, + ( + init_atmosphere_bind_group_layouts, + init_atmosphere_lut_pipelines, + ) + .chain(), + ) + .in_set(AtmosphereSystems), + ) .add_systems( Render, ( @@ -142,36 +146,66 @@ impl Plugin for AtmospherePlugin { prepare_atmosphere_textures.in_set(RenderSystems::PrepareResources), prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources), prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups), - ), - ) - .add_render_graph_node::>( - Core3d, - AtmosphereNode::RenderLuts, - ) - .add_render_graph_edges( - Core3d, - ( - // END_PRE_PASSES -> RENDER_LUTS -> MAIN_PASS - Node3d::EndPrepasses, - AtmosphereNode::RenderLuts, - Node3d::StartMainPass, - ), - ) - .add_render_graph_node::>( - Core3d, - AtmosphereNode::RenderSky, - ) - .add_render_graph_edges( - Core3d, - ( - Node3d::MainOpaquePass, - AtmosphereNode::RenderSky, - Node3d::MainTransparentPass, - ), + ) + .in_set(AtmosphereSystems), ); } } +#[derive(SystemSet, Hash, PartialEq, Eq, Clone, Debug)] +struct AtmosphereSystems; + +#[derive(Resource)] +struct AtmosphereSupported; + +fn check_atmosphere_supported(mut commands: Commands, render_adapter: Res) { + if !render_adapter + .get_downlevel_capabilities() + .flags + .contains(DownlevelFlags::COMPUTE_SHADERS) + { + warn!("AtmospherePlugin not loaded. GPU lacks support for compute shaders."); + return; + } + + if !render_adapter + .get_texture_format_features(TextureFormat::Rgba16Float) + .allowed_usages + .contains(TextureUsages::STORAGE_BINDING) + { + warn!("AtmospherePlugin not loaded. GPU lacks support: TextureFormat::Rgba16Float does not support TextureUsages::STORAGE_BINDING."); + return; + } + + commands.insert_resource(AtmosphereSupported); +} + +fn add_atmosphere_render_graph_nodes(world: &mut World) { + world + .add_render_graph_node::>( + Core3d, + AtmosphereNode::RenderLuts, + ) + .add_render_graph_edges( + Core3d, + ( + // END_PRE_PASSES -> RENDER_LUTS -> MAIN_PASS + Node3d::EndPrepasses, + AtmosphereNode::RenderLuts, + Node3d::StartMainPass, + ), + ) + .add_render_graph_node::>(Core3d, AtmosphereNode::RenderSky) + .add_render_graph_edges( + Core3d, + ( + Node3d::MainOpaquePass, + AtmosphereNode::RenderSky, + Node3d::MainTransparentPass, + ), + ); +} + /// This component describes the atmosphere of a planet, and when added to a camera /// will enable atmospheric scattering for that camera. This is only compatible with /// HDR cameras. diff --git a/crates/bevy_pbr/src/atmosphere/resources.rs b/crates/bevy_pbr/src/atmosphere/resources.rs index 3f4da25fc0e4e..876139b21b14e 100644 --- a/crates/bevy_pbr/src/atmosphere/resources.rs +++ b/crates/bevy_pbr/src/atmosphere/resources.rs @@ -1,5 +1,5 @@ use crate::{GpuLights, LightMeta}; -use bevy_asset::{load_embedded_asset, Handle}; +use bevy_asset::{load_embedded_asset, AssetServer, Handle}; use bevy_core_pipeline::{core_3d::Camera3d, FullscreenShader}; use bevy_ecs::{ component::Component, @@ -7,7 +7,6 @@ use bevy_ecs::{ query::With, resource::Resource, system::{Commands, Query, Res, ResMut}, - world::{FromWorld, World}, }; use bevy_image::ToExtents; use bevy_math::{Mat4, Vec3}; @@ -39,176 +38,166 @@ pub(crate) struct RenderSkyBindGroupLayouts { pub fragment_shader: Handle, } -impl FromWorld for AtmosphereBindGroupLayouts { - fn from_world(world: &mut World) -> Self { - let render_device = world.resource::(); - let transmittance_lut = render_device.create_bind_group_layout( - "transmittance_lut_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::COMPUTE, +pub(crate) fn init_atmosphere_bind_group_layouts( + mut commands: Commands, + render_device: Res, +) { + let transmittance_lut = render_device.create_bind_group_layout( + "transmittance_lut_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::COMPUTE, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - ( - // transmittance lut storage texture - 13, - texture_storage_2d( - TextureFormat::Rgba16Float, - StorageTextureAccess::WriteOnly, - ), - ), + // transmittance lut storage texture + 13, + texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly), ), ), - ); + ), + ); - let multiscattering_lut = render_device.create_bind_group_layout( - "multiscattering_lut_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::COMPUTE, + let multiscattering_lut = render_device.create_bind_group_layout( + "multiscattering_lut_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::COMPUTE, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), + (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler + (6, sampler(SamplerBindingType::Filtering)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler - (6, sampler(SamplerBindingType::Filtering)), - ( - //multiscattering lut storage texture - 13, - texture_storage_2d( - TextureFormat::Rgba16Float, - StorageTextureAccess::WriteOnly, - ), - ), + //multiscattering lut storage texture + 13, + texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly), ), ), - ); + ), + ); - let sky_view_lut = render_device.create_bind_group_layout( - "sky_view_lut_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::COMPUTE, + let sky_view_lut = render_device.create_bind_group_layout( + "sky_view_lut_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::COMPUTE, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), + (2, uniform_buffer::(true)), + (3, uniform_buffer::(true)), + (4, uniform_buffer::(true)), + (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler + (6, sampler(SamplerBindingType::Filtering)), + (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler + (8, sampler(SamplerBindingType::Filtering)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - (2, uniform_buffer::(true)), - (3, uniform_buffer::(true)), - (4, uniform_buffer::(true)), - (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler - (6, sampler(SamplerBindingType::Filtering)), - (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler - (8, sampler(SamplerBindingType::Filtering)), - ( - 13, - texture_storage_2d( - TextureFormat::Rgba16Float, - StorageTextureAccess::WriteOnly, - ), - ), + 13, + texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly), ), ), - ); + ), + ); - let aerial_view_lut = render_device.create_bind_group_layout( - "aerial_view_lut_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::COMPUTE, + let aerial_view_lut = render_device.create_bind_group_layout( + "aerial_view_lut_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::COMPUTE, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), + (3, uniform_buffer::(true)), + (4, uniform_buffer::(true)), + (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler + (6, sampler(SamplerBindingType::Filtering)), + (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler + (8, sampler(SamplerBindingType::Filtering)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - (3, uniform_buffer::(true)), - (4, uniform_buffer::(true)), - (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler - (6, sampler(SamplerBindingType::Filtering)), - (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler - (8, sampler(SamplerBindingType::Filtering)), - ( - //Aerial view lut storage texture - 13, - texture_storage_3d( - TextureFormat::Rgba16Float, - StorageTextureAccess::WriteOnly, - ), - ), + //Aerial view lut storage texture + 13, + texture_storage_3d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly), ), ), - ); + ), + ); - Self { - transmittance_lut, - multiscattering_lut, - sky_view_lut, - aerial_view_lut, - } - } + commands.insert_resource(AtmosphereBindGroupLayouts { + transmittance_lut, + multiscattering_lut, + sky_view_lut, + aerial_view_lut, + }); } -impl FromWorld for RenderSkyBindGroupLayouts { - fn from_world(world: &mut World) -> Self { - let render_device = world.resource::(); - let render_sky = render_device.create_bind_group_layout( - "render_sky_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::FRAGMENT, +pub(crate) fn init_render_sky_bind_group_layouts( + mut commands: Commands, + render_device: Res, + fullscreen_shader: Res, + asset_server: Res, +) { + let render_sky = render_device.create_bind_group_layout( + "render_sky_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::FRAGMENT, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), + (2, uniform_buffer::(true)), + (3, uniform_buffer::(true)), + (4, uniform_buffer::(true)), + (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler + (6, sampler(SamplerBindingType::Filtering)), + (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler + (10, sampler(SamplerBindingType::Filtering)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - (2, uniform_buffer::(true)), - (3, uniform_buffer::(true)), - (4, uniform_buffer::(true)), - (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler - (6, sampler(SamplerBindingType::Filtering)), - (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler - (10, sampler(SamplerBindingType::Filtering)), - ( - // aerial view lut and sampler - 11, - texture_3d(TextureSampleType::Float { filterable: true }), - ), - (12, sampler(SamplerBindingType::Filtering)), - ( - //view depth texture - 13, - texture_2d(TextureSampleType::Depth), - ), + // aerial view lut and sampler + 11, + texture_3d(TextureSampleType::Float { filterable: true }), + ), + (12, sampler(SamplerBindingType::Filtering)), + ( + //view depth texture + 13, + texture_2d(TextureSampleType::Depth), ), ), - ); + ), + ); - let render_sky_msaa = render_device.create_bind_group_layout( - "render_sky_msaa_bind_group_layout", - &BindGroupLayoutEntries::with_indices( - ShaderStages::FRAGMENT, + let render_sky_msaa = render_device.create_bind_group_layout( + "render_sky_msaa_bind_group_layout", + &BindGroupLayoutEntries::with_indices( + ShaderStages::FRAGMENT, + ( + (0, uniform_buffer::(true)), + (1, uniform_buffer::(true)), + (2, uniform_buffer::(true)), + (3, uniform_buffer::(true)), + (4, uniform_buffer::(true)), + (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler + (6, sampler(SamplerBindingType::Filtering)), + (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler + (10, sampler(SamplerBindingType::Filtering)), + ( + // aerial view lut and sampler + 11, + texture_3d(TextureSampleType::Float { filterable: true }), + ), + (12, sampler(SamplerBindingType::Filtering)), ( - (0, uniform_buffer::(true)), - (1, uniform_buffer::(true)), - (2, uniform_buffer::(true)), - (3, uniform_buffer::(true)), - (4, uniform_buffer::(true)), - (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler - (6, sampler(SamplerBindingType::Filtering)), - (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler - (10, sampler(SamplerBindingType::Filtering)), - ( - // aerial view lut and sampler - 11, - texture_3d(TextureSampleType::Float { filterable: true }), - ), - (12, sampler(SamplerBindingType::Filtering)), - ( - //view depth texture - 13, - texture_2d_multisampled(TextureSampleType::Depth), - ), + //view depth texture + 13, + texture_2d_multisampled(TextureSampleType::Depth), ), ), - ); + ), + ); - Self { - render_sky, - render_sky_msaa, - fullscreen_shader: world.resource::().clone(), - fragment_shader: load_embedded_asset!(world, "render_sky.wgsl"), - } - } + commands.insert_resource(RenderSkyBindGroupLayouts { + render_sky, + render_sky_msaa, + fullscreen_shader: fullscreen_shader.clone(), + fragment_shader: load_embedded_asset!(asset_server.as_ref(), "render_sky.wgsl"), + }); } #[derive(Resource)] @@ -219,45 +208,41 @@ pub struct AtmosphereSamplers { pub aerial_view_lut: Sampler, } -impl FromWorld for AtmosphereSamplers { - fn from_world(world: &mut World) -> Self { - let render_device = world.resource::(); - - let base_sampler = SamplerDescriptor { - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Nearest, - ..Default::default() - }; - - let transmittance_lut = render_device.create_sampler(&SamplerDescriptor { - label: Some("transmittance_lut_sampler"), - ..base_sampler - }); - - let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor { - label: Some("multiscattering_lut_sampler"), - ..base_sampler - }); - - let sky_view_lut = render_device.create_sampler(&SamplerDescriptor { - label: Some("sky_view_lut_sampler"), - address_mode_u: AddressMode::Repeat, - ..base_sampler - }); - - let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor { - label: Some("aerial_view_lut_sampler"), - ..base_sampler - }); +pub fn init_atmosphere_samplers(mut commands: Commands, render_device: Res) { + let base_sampler = SamplerDescriptor { + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + mipmap_filter: FilterMode::Nearest, + ..Default::default() + }; - Self { - transmittance_lut, - multiscattering_lut, - sky_view_lut, - aerial_view_lut, - } - } + let transmittance_lut = render_device.create_sampler(&SamplerDescriptor { + label: Some("transmittance_lut_sampler"), + ..base_sampler + }); + + let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor { + label: Some("multiscattering_lut_sampler"), + ..base_sampler + }); + + let sky_view_lut = render_device.create_sampler(&SamplerDescriptor { + label: Some("sky_view_lut_sampler"), + address_mode_u: AddressMode::Repeat, + ..base_sampler + }); + + let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor { + label: Some("aerial_view_lut_sampler"), + ..base_sampler + }); + + commands.insert_resource(AtmosphereSamplers { + transmittance_lut, + multiscattering_lut, + sky_view_lut, + aerial_view_lut, + }); } #[derive(Resource)] @@ -268,47 +253,46 @@ pub(crate) struct AtmosphereLutPipelines { pub aerial_view_lut: CachedComputePipelineId, } -impl FromWorld for AtmosphereLutPipelines { - fn from_world(world: &mut World) -> Self { - let pipeline_cache = world.resource::(); - let layouts = world.resource::(); - - let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { - label: Some("transmittance_lut_pipeline".into()), - layout: vec![layouts.transmittance_lut.clone()], - shader: load_embedded_asset!(world, "transmittance_lut.wgsl"), - ..default() - }); - - let multiscattering_lut = - pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { - label: Some("multi_scattering_lut_pipeline".into()), - layout: vec![layouts.multiscattering_lut.clone()], - shader: load_embedded_asset!(world, "multiscattering_lut.wgsl"), - ..default() - }); - - let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { - label: Some("sky_view_lut_pipeline".into()), - layout: vec![layouts.sky_view_lut.clone()], - shader: load_embedded_asset!(world, "sky_view_lut.wgsl"), - ..default() - }); - - let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { - label: Some("aerial_view_lut_pipeline".into()), - layout: vec![layouts.aerial_view_lut.clone()], - shader: load_embedded_asset!(world, "aerial_view_lut.wgsl"), - ..default() - }); - - Self { - transmittance_lut, - multiscattering_lut, - sky_view_lut, - aerial_view_lut, - } - } +pub(crate) fn init_atmosphere_lut_pipelines( + mut commands: Commands, + pipeline_cache: Res, + layouts: Res, + asset_server: Res, +) { + let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { + label: Some("transmittance_lut_pipeline".into()), + layout: vec![layouts.transmittance_lut.clone()], + shader: load_embedded_asset!(asset_server.as_ref(), "transmittance_lut.wgsl"), + ..default() + }); + + let multiscattering_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { + label: Some("multi_scattering_lut_pipeline".into()), + layout: vec![layouts.multiscattering_lut.clone()], + shader: load_embedded_asset!(asset_server.as_ref(), "multiscattering_lut.wgsl"), + ..default() + }); + + let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { + label: Some("sky_view_lut_pipeline".into()), + layout: vec![layouts.sky_view_lut.clone()], + shader: load_embedded_asset!(asset_server.as_ref(), "sky_view_lut.wgsl"), + ..default() + }); + + let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { + label: Some("aerial_view_lut_pipeline".into()), + layout: vec![layouts.aerial_view_lut.clone()], + shader: load_embedded_asset!(asset_server.as_ref(), "aerial_view_lut.wgsl"), + ..default() + }); + + commands.insert_resource(AtmosphereLutPipelines { + transmittance_lut, + multiscattering_lut, + sky_view_lut, + aerial_view_lut, + }); } #[derive(Component)] From cd380aa6d66c84bff43ce8288fd14d29db69a0f2 Mon Sep 17 00:00:00 2001 From: andriyDev Date: Fri, 18 Jul 2025 01:16:01 -0700 Subject: [PATCH 2/2] Add a migration guide for the one exposed atmosphere resource. --- release-content/migration-guides/render_startup.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release-content/migration-guides/render_startup.md b/release-content/migration-guides/render_startup.md index e888bd75883ba..fca167eca6d5c 100644 --- a/release-content/migration-guides/render_startup.md +++ b/release-content/migration-guides/render_startup.md @@ -24,6 +24,7 @@ The following are the (public) resources that are now initialized in `RenderStar - `OitBuffers` - `PostProcessingPipeline` - `TonemappingPipeline` +- `AtmosphereSamplers` - `BoxShadowPipeline` - `GradientPipeline` - `UiPipeline`