Skip to content

Commit 2d1b493

Browse files
kristoff3ralice-i-cecileTrashtalk217
authored
Synchronize removed components with the render world (#15582)
# Objective Fixes #15560 Fixes (most of) #15570 Currently a lot of examples (and presumably some user code) depend on toggling certain render features by adding/removing a single component to an entity, e.g. `SpotLight` to toggle a light. Because of the retained render world this no longer works: Extract will add any new components, but when it is removed the entity persists unchanged in the render world. ## Solution Add `SyncComponentPlugin<C: Component>` that registers `SyncToRenderWorld` as a required component for `C`, and adds a component hook that will clear all components from the render world entity when `C` is removed. We add this plugin to `ExtractComponentPlugin` which fixes most instances of the problem. For custom extraction logic we can manually add `SyncComponentPlugin` for that component. We also rename `WorldSyncPlugin` to `SyncWorldPlugin` so we start a naming convention like all the `Extract` plugins. In this PR I also fixed a bunch of breakage related to the retained render world, stemming from old code that assumed that `Entity` would be the same in both worlds. I found that using the `RenderEntity` wrapper instead of `Entity` in data structures when referring to render world entities makes intent much clearer, so I propose we make this an official pattern. ## Testing Run examples like ``` cargo run --features pbr_multi_layer_material_textures --example clearcoat cargo run --example volumetric_fog ``` and see that they work, and that toggles work correctly. But really we should test every single example, as we might not even have caught all the breakage yet. --- ## Migration Guide The retained render world notes should be updated to explain this edge case and `SyncComponentPlugin` --------- Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: Trashtalk217 <[email protected]>
1 parent 45eff09 commit 2d1b493

File tree

36 files changed

+151
-84
lines changed

36 files changed

+151
-84
lines changed

crates/bevy_core_pipeline/src/auto_exposure/buffers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bevy_ecs::prelude::*;
22
use bevy_render::{
33
render_resource::{StorageBuffer, UniformBuffer},
44
renderer::{RenderDevice, RenderQueue},
5-
world_sync::RenderEntity,
5+
sync_world::RenderEntity,
66
Extract,
77
};
88
use bevy_utils::{Entry, HashMap};

crates/bevy_core_pipeline/src/core_2d/camera_2d.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77
use bevy_ecs::prelude::*;
88
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
9-
use bevy_render::world_sync::SyncToRenderWorld;
9+
use bevy_render::sync_world::SyncToRenderWorld;
1010
use bevy_render::{
1111
camera::{
1212
Camera, CameraMainTextureUsages, CameraProjection, CameraRenderGraph,

crates/bevy_core_pipeline/src/core_2d/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ use bevy_render::{
5555
TextureFormat, TextureUsages,
5656
},
5757
renderer::RenderDevice,
58+
sync_world::RenderEntity,
5859
texture::TextureCache,
5960
view::{Msaa, ViewDepthTexture},
60-
world_sync::RenderEntity,
6161
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
6262
};
6363

crates/bevy_core_pipeline/src/core_3d/camera_3d.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use bevy_render::{
1111
extract_component::ExtractComponent,
1212
primitives::Frustum,
1313
render_resource::{LoadOp, TextureUsages},
14+
sync_world::SyncToRenderWorld,
1415
view::{ColorGrading, Msaa, VisibleEntities},
15-
world_sync::SyncToRenderWorld,
1616
};
1717
use bevy_transform::prelude::{GlobalTransform, Transform};
1818
use serde::{Deserialize, Serialize};

crates/bevy_core_pipeline/src/core_3d/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ use bevy_render::{
8989
Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureView,
9090
},
9191
renderer::RenderDevice,
92+
sync_world::RenderEntity,
9293
texture::{BevyDefault, ColorAttachment, Image, TextureCache},
9394
view::{ExtractedView, ViewDepthTexture, ViewTarget},
94-
world_sync::RenderEntity,
9595
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
9696
};
9797
use bevy_utils::{tracing::warn, HashMap};

crates/bevy_core_pipeline/src/dof/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ use bevy_render::{
4646
TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
4747
},
4848
renderer::{RenderContext, RenderDevice},
49+
sync_world::RenderEntity,
4950
texture::{BevyDefault, CachedTexture, TextureCache},
5051
view::{
5152
prepare_view_targets, ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniform,
5253
ViewUniformOffset, ViewUniforms,
5354
},
54-
world_sync::RenderEntity,
5555
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
5656
};
5757
use bevy_utils::{info_once, prelude::default, warn_once};

crates/bevy_core_pipeline/src/taa/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ use bevy_render::{
3232
TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
3333
},
3434
renderer::{RenderContext, RenderDevice},
35+
sync_world::RenderEntity,
3536
texture::{BevyDefault, CachedTexture, TextureCache},
3637
view::{ExtractedView, Msaa, ViewTarget},
37-
world_sync::RenderEntity,
3838
ExtractSchedule, MainWorld, Render, RenderApp, RenderSet,
3939
};
4040
use bevy_utils::tracing::warn;

crates/bevy_gizmos/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ use {
105105
ShaderStages, ShaderType, VertexFormat,
106106
},
107107
renderer::RenderDevice,
108-
world_sync::TemporaryRenderEntity,
108+
sync_world::TemporaryRenderEntity,
109109
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
110110
},
111111
bytemuck::cast_slice,

crates/bevy_pbr/src/bundle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
1515
use bevy_render::{
1616
mesh::Mesh3d,
1717
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
18+
sync_world::SyncToRenderWorld,
1819
view::{InheritedVisibility, ViewVisibility, Visibility},
19-
world_sync::SyncToRenderWorld,
2020
};
2121
use bevy_transform::components::{GlobalTransform, Transform};
2222

crates/bevy_pbr/src/cluster/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use bevy_render::{
2020
UniformBuffer,
2121
},
2222
renderer::{RenderDevice, RenderQueue},
23-
world_sync::RenderEntity,
23+
sync_world::RenderEntity,
2424
Extract,
2525
};
2626
use bevy_utils::{hashbrown::HashSet, tracing::warn};

crates/bevy_pbr/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ use bevy_render::{
127127
render_asset::prepare_assets,
128128
render_graph::RenderGraph,
129129
render_resource::Shader,
130+
sync_component::SyncComponentPlugin,
130131
texture::{GpuImage, Image},
131132
view::{check_visibility, VisibilitySystems},
132133
ExtractSchedule, Render, RenderApp, RenderSet,
@@ -314,7 +315,6 @@ impl Plugin for PbrPlugin {
314315
.register_type::<PointLight>()
315316
.register_type::<PointLightShadowMap>()
316317
.register_type::<SpotLight>()
317-
.register_type::<DistanceFog>()
318318
.register_type::<ShadowFilteringMethod>()
319319
.init_resource::<AmbientLight>()
320320
.init_resource::<GlobalVisibleClusterableObjects>()
@@ -346,6 +346,11 @@ impl Plugin for PbrPlugin {
346346
VolumetricFogPlugin,
347347
ScreenSpaceReflectionsPlugin,
348348
))
349+
.add_plugins((
350+
SyncComponentPlugin::<DirectionalLight>::default(),
351+
SyncComponentPlugin::<PointLight>::default(),
352+
SyncComponentPlugin::<SpotLight>::default(),
353+
))
349354
.configure_sets(
350355
PostUpdate,
351356
(

crates/bevy_pbr/src/light/directional_light.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_render::{view::Visibility, world_sync::SyncToRenderWorld};
1+
use bevy_render::view::Visibility;
22

33
use super::*;
44

@@ -57,8 +57,7 @@ use super::*;
5757
CascadeShadowConfig,
5858
CascadesVisibleEntities,
5959
Transform,
60-
Visibility,
61-
SyncToRenderWorld
60+
Visibility
6261
)]
6362
pub struct DirectionalLight {
6463
/// The color of the light.

crates/bevy_pbr/src/light/point_light.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_render::{view::Visibility, world_sync::SyncToRenderWorld};
1+
use bevy_render::view::Visibility;
22

33
use super::*;
44

@@ -21,13 +21,7 @@ use super::*;
2121
/// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lumen_(unit)#Lighting)
2222
#[derive(Component, Debug, Clone, Copy, Reflect)]
2323
#[reflect(Component, Default, Debug)]
24-
#[require(
25-
CubemapFrusta,
26-
CubemapVisibleEntities,
27-
Transform,
28-
Visibility,
29-
SyncToRenderWorld
30-
)]
24+
#[require(CubemapFrusta, CubemapVisibleEntities, Transform, Visibility)]
3125
pub struct PointLight {
3226
/// The color of this light source.
3327
pub color: Color,

crates/bevy_pbr/src/light/spot_light.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_render::{view::Visibility, world_sync::SyncToRenderWorld};
1+
use bevy_render::view::Visibility;
22

33
use super::*;
44

@@ -9,7 +9,7 @@ use super::*;
99
/// the transform, and can be specified with [`Transform::looking_at`](Transform::looking_at).
1010
#[derive(Component, Debug, Clone, Copy, Reflect)]
1111
#[reflect(Component, Default, Debug)]
12-
#[require(Frustum, VisibleMeshEntities, Transform, Visibility, SyncToRenderWorld)]
12+
#[require(Frustum, VisibleMeshEntities, Transform, Visibility)]
1313
pub struct SpotLight {
1414
/// The color of the light.
1515
///

crates/bevy_pbr/src/light_probe/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ use bevy_render::{
2121
render_resource::{DynamicUniformBuffer, Sampler, Shader, ShaderType, TextureView},
2222
renderer::{RenderDevice, RenderQueue},
2323
settings::WgpuFeatures,
24+
sync_world::RenderEntity,
2425
texture::{FallbackImage, GpuImage, Image},
2526
view::ExtractedView,
26-
world_sync::RenderEntity,
2727
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
2828
};
2929
use bevy_transform::{components::Transform, prelude::GlobalTransform};

crates/bevy_pbr/src/prepass/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod prepass_bindings;
33
use bevy_render::{
44
mesh::{Mesh3d, MeshVertexBufferLayoutRef, RenderMesh},
55
render_resource::binding_types::uniform_buffer,
6-
world_sync::RenderEntity,
6+
sync_world::RenderEntity,
77
};
88
pub use prepass_bindings::*;
99

crates/bevy_pbr/src/render/light.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bevy_ecs::{
88
system::lifetimeless::Read,
99
};
1010
use bevy_math::{ops, Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles};
11-
use bevy_render::world_sync::RenderEntity;
11+
use bevy_render::sync_world::RenderEntity;
1212
use bevy_render::{
1313
diagnostic::RecordDiagnostics,
1414
mesh::RenderMesh,

crates/bevy_pbr/src/ssao/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ use bevy_render::{
3030
*,
3131
},
3232
renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue},
33+
sync_world::RenderEntity,
3334
texture::{CachedTexture, TextureCache},
3435
view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms},
35-
world_sync::RenderEntity,
3636
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
3737
};
3838
use bevy_utils::{

crates/bevy_pbr/src/volumetric_fog/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use bevy_render::{
5151
mesh::{Mesh, Meshable},
5252
render_graph::{RenderGraphApp, ViewNodeRunner},
5353
render_resource::{Shader, SpecializedRenderPipelines},
54+
sync_component::SyncComponentPlugin,
5455
texture::Image,
5556
view::{InheritedVisibility, ViewVisibility, Visibility},
5657
ExtractSchedule, Render, RenderApp, RenderSet,
@@ -231,6 +232,8 @@ impl Plugin for VolumetricFogPlugin {
231232
app.register_type::<VolumetricFog>()
232233
.register_type::<VolumetricLight>();
233234

235+
app.add_plugins(SyncComponentPlugin::<FogVolume>::default());
236+
234237
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
235238
return;
236239
};

crates/bevy_pbr/src/volumetric_fog/render.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ use bevy_render::{
3636
TextureSampleType, TextureUsages, VertexState,
3737
},
3838
renderer::{RenderContext, RenderDevice, RenderQueue},
39+
sync_world::RenderEntity,
3940
texture::{BevyDefault as _, GpuImage, Image},
4041
view::{ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniformOffset},
41-
world_sync::RenderEntity,
4242
Extract,
4343
};
4444
use bevy_transform::components::GlobalTransform;

crates/bevy_render/src/camera/camera.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use crate::{
66
render_asset::RenderAssets,
77
render_graph::{InternedRenderSubGraph, RenderSubGraph},
88
render_resource::TextureView,
9+
sync_world::{RenderEntity, SyncToRenderWorld},
910
texture::GpuImage,
1011
view::{
1112
ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, Msaa, RenderLayers, Visibility,
1213
VisibleEntities,
1314
},
14-
world_sync::{RenderEntity, SyncToRenderWorld},
1515
Extract,
1616
};
1717
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};

crates/bevy_render/src/extract_component.rs

+6-17
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::{
22
render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
33
renderer::{RenderDevice, RenderQueue},
4+
sync_component::SyncComponentPlugin,
5+
sync_world::RenderEntity,
46
view::ViewVisibility,
5-
world_sync::{RenderEntity, SyncToRenderWorld},
67
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
78
};
89
use bevy_app::{App, Plugin};
@@ -12,7 +13,6 @@ use bevy_ecs::{
1213
prelude::*,
1314
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
1415
system::lifetimeless::Read,
15-
world::OnAdd,
1616
};
1717
use core::{marker::PhantomData, ops::Deref};
1818

@@ -160,15 +160,6 @@ fn prepare_uniform_components<C>(
160160
/// This plugin extracts the components into the render world for synced entities.
161161
///
162162
/// To do so, it sets up the [`ExtractSchedule`] step for the specified [`ExtractComponent`].
163-
///
164-
/// # Warning
165-
///
166-
/// Be careful when removing the [`ExtractComponent`] from an entity. When an [`ExtractComponent`]
167-
/// is added to an entity, that entity is automatically synced with the render world (see also
168-
/// [`WorldSyncPlugin`](crate::world_sync::WorldSyncPlugin)). When removing the entity in the main
169-
/// world, the synced entity also gets removed. However, if only the [`ExtractComponent`] is removed
170-
/// this *doesn't* happen, and the synced entity stays around with the old extracted data.
171-
/// We recommend despawning the entire entity, instead of only removing [`ExtractComponent`].
172163
pub struct ExtractComponentPlugin<C, F = ()> {
173164
only_extract_visible: bool,
174165
marker: PhantomData<fn() -> (C, F)>,
@@ -194,10 +185,8 @@ impl<C, F> ExtractComponentPlugin<C, F> {
194185

195186
impl<C: ExtractComponent> Plugin for ExtractComponentPlugin<C> {
196187
fn build(&self, app: &mut App) {
197-
// TODO: use required components
198-
app.observe(|trigger: Trigger<OnAdd, C>, mut commands: Commands| {
199-
commands.entity(trigger.entity()).insert(SyncToRenderWorld);
200-
});
188+
app.add_plugins(SyncComponentPlugin::<C>::default());
189+
201190
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
202191
if self.only_extract_visible {
203192
render_app.add_systems(ExtractSchedule, extract_visible_components::<C>);
@@ -219,7 +208,7 @@ impl<T: Asset> ExtractComponent for Handle<T> {
219208
}
220209
}
221210

222-
/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are synced via [`SyncToRenderWorld`].
211+
/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are synced via [`crate::sync_world::SyncToRenderWorld`].
223212
fn extract_components<C: ExtractComponent>(
224213
mut commands: Commands,
225214
mut previous_len: Local<usize>,
@@ -235,7 +224,7 @@ fn extract_components<C: ExtractComponent>(
235224
commands.insert_or_spawn_batch(values);
236225
}
237226

238-
/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are visible and synced via [`SyncToRenderWorld`].
227+
/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are visible and synced via [`crate::sync_world::SyncToRenderWorld`].
239228
fn extract_visible_components<C: ExtractComponent>(
240229
mut commands: Commands,
241230
mut previous_len: Local<usize>,

crates/bevy_render/src/extract_param.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use core::ops::{Deref, DerefMut};
3030
/// ```
3131
/// use bevy_ecs::prelude::*;
3232
/// use bevy_render::Extract;
33-
/// use bevy_render::world_sync::RenderEntity;
33+
/// use bevy_render::sync_world::RenderEntity;
3434
/// # #[derive(Component)]
3535
/// // Do make sure to sync the cloud entities before extracting them.
3636
/// # struct Cloud;

crates/bevy_render/src/gpu_readback.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
render_resource::{Buffer, BufferUsages, Extent3d, ImageDataLayout, Texture, TextureFormat},
66
renderer::{render_system, RenderDevice},
77
storage::{GpuShaderStorageBuffer, ShaderStorageBuffer},
8+
sync_world::MainEntity,
89
texture::{GpuImage, TextureFormatPixelInfo},
910
ExtractSchedule, MainWorld, Render, RenderApp, RenderSet,
1011
};
@@ -232,7 +233,7 @@ fn prepare_buffers(
232233
mut buffer_pool: ResMut<GpuReadbackBufferPool>,
233234
gpu_images: Res<RenderAssets<GpuImage>>,
234235
ssbos: Res<RenderAssets<GpuShaderStorageBuffer>>,
235-
handles: Query<(Entity, &Readback)>,
236+
handles: Query<(&MainEntity, &Readback)>,
236237
) {
237238
for (entity, readback) in handles.iter() {
238239
match readback {
@@ -254,7 +255,7 @@ fn prepare_buffers(
254255
);
255256
let (tx, rx) = async_channel::bounded(1);
256257
readbacks.requested.push(GpuReadback {
257-
entity,
258+
entity: entity.id(),
258259
src: ReadbackSource::Texture {
259260
texture: gpu_image.texture.clone(),
260261
layout,
@@ -272,7 +273,7 @@ fn prepare_buffers(
272273
let buffer = buffer_pool.get(&render_device, size);
273274
let (tx, rx) = async_channel::bounded(1);
274275
readbacks.requested.push(GpuReadback {
275-
entity,
276+
entity: entity.id(),
276277
src: ReadbackSource::Buffer {
277278
src_start: 0,
278279
dst_start: 0,

0 commit comments

Comments
 (0)