Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ impl Plugin for PbrPlugin {
ExtractSchedule,
(
extract_lights,
extract_lights_render_layers_meta,
extract_ambient_light_resource,
extract_ambient_light,
extract_shadow_filtering_method,
Expand Down
35 changes: 33 additions & 2 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ use bevy_render::occlusion_culling::{
};
use bevy_render::sync_world::{MainEntity, MainEntityHashMap, MainEntityHashSet, RenderEntity};
use bevy_render::view::{
RenderExtractedShadowMapVisibleEntities, RenderShadowLodOrigin, RenderShadowMapVisibleEntities,
RenderVisibleEntities, VisibilityExtractionSystemParam,
ExtractedRenderLayersMeta, RenderExtractedShadowMapVisibleEntities, RenderShadowLodOrigin,
RenderShadowMapVisibleEntities, RenderVisibleEntities, VisibilityExtractionSystemParam,
};
use bevy_render::{
batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
Expand Down Expand Up @@ -951,6 +951,37 @@ pub fn extract_lights(
}
}

pub fn extract_lights_render_layers_meta(
mut commands: Commands,
all_light_query: Extract<
Query<
(RenderEntity, Ref<RenderLayers>),
Or<(
With<PointLight>,
With<SpotLight>,
With<DirectionalLight>,
With<RectLight>,
)>,
>,
>,
mut extracted_render_layer_meta_query: Query<&mut ExtractedRenderLayersMeta>,
) {
for (render_entity, render_layers) in all_light_query.iter() {
match extracted_render_layer_meta_query.get_mut(render_entity) {
Ok(mut meta) => {
meta.changed = render_layers.is_changed();
}
Err(_) => {
commands
.entity(render_entity)
.insert(ExtractedRenderLayersMeta {
changed: render_layers.is_changed(),
});
}
}
}
}

#[derive(Component, Default, Deref, DerefMut)]
/// Component automatically attached to a light entity to track light-view entities
/// for each view.
Expand Down
59 changes: 46 additions & 13 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ use bevy_render::camera::{DirtySpecializations, ExtractedCamera, TemporalJitter}
use bevy_render::prelude::Msaa;
use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
use bevy_render::view::{
texture_format_from_code, texture_format_to_code, ExtractedView,
texture_format_from_code, texture_format_to_code, ExtractedRenderLayersMeta, ExtractedView,
RenderShadowMapVisibleEntities, RenderVisibleEntities,
};
use bevy_render::RenderSystems::PrepareAssets;
Expand Down Expand Up @@ -2285,34 +2285,57 @@ impl<'a> Iterator for AtomicU64ZeroBitIter<'a> {
/// Each view must maintain a separate list of GPU-culled entities because the
/// views and entities might belong to different render layers.
pub fn collect_gpu_culled_meshes(
mut cameras: Query<(Option<&RenderLayers>, &mut RenderVisibleEntities), With<ExtractedView>>,
mut lights: Query<(Option<&RenderLayers>, &mut RenderShadowMapVisibleEntities)>,
mut cameras: Query<
(
Option<&RenderLayers>,
Option<&ExtractedRenderLayersMeta>,
&mut RenderVisibleEntities,
),
With<ExtractedView>,
>,
mut lights: Query<(
Option<&RenderLayers>,
Option<&ExtractedRenderLayersMeta>,
&mut RenderShadowMapVisibleEntities,
)>,
render_gpu_culled_entities: Res<RenderGpuCulledEntities>,
) {
let default_render_layers = RenderLayers::default();

// Collect cameras.
for (maybe_render_layers, mut render_visible_entities) in &mut cameras {
for (maybe_render_layers, maybe_extracted_render_layers_meta, mut render_visible_entities) in
&mut cameras
{
let just_added_render_visible_entities = render_visible_entities.is_added();
collect_gpu_culled_meshes_for_subview(
maybe_render_layers.unwrap_or(&default_render_layers),
&mut render_visible_entities,
maybe_extracted_render_layers_meta
.is_some_and(|extracted_render_layers_meta| extracted_render_layers_meta.changed),
just_added_render_visible_entities,
&render_gpu_culled_entities,
);
}

// Collect shadow maps.
for (maybe_render_layers, mut render_shadow_map_visible_entities) in &mut lights {
for (
maybe_render_layers,
maybe_extracted_render_layers_meta,
mut render_shadow_map_visible_entities,
) in &mut lights
{
let last_run = render_shadow_map_visible_entities.last_run();
let this_run = render_shadow_map_visible_entities.this_run();

let view_render_layers_changed = maybe_extracted_render_layers_meta
.is_some_and(|extracted_render_layers_meta| extracted_render_layers_meta.changed);
Comment thread
CodingDaniel1 marked this conversation as resolved.
for (render_visible_entities_added_tick, render_visible_entities) in
render_shadow_map_visible_entities.subviews.values_mut()
{
collect_gpu_culled_meshes_for_subview(
maybe_render_layers.unwrap_or(&default_render_layers),
render_visible_entities,
view_render_layers_changed,
render_visible_entities_added_tick.is_newer_than(last_run, this_run),
&render_gpu_culled_entities,
);
Expand All @@ -2329,6 +2352,7 @@ pub fn collect_gpu_culled_meshes(
fn collect_gpu_culled_meshes_for_subview(
view_render_layers: &RenderLayers,
render_visible_entities: &mut RenderVisibleEntities,
view_render_layers_changed: bool,
just_added_render_visible_entities: bool,
render_mesh_instance_gpu_queues: &RenderGpuCulledEntities,
) {
Expand Down Expand Up @@ -2392,17 +2416,12 @@ fn collect_gpu_culled_meshes_for_subview(
}

// Process entities that changed layers.
for main_entity in &render_mesh_instance_gpu_queues.changed_layers {
let Some(render_layers) = render_mesh_instance_gpu_queues.entities.get(main_entity)
else {
continue;
};

// This is either treated as no change, as an addition, or as a removal.
let mut process_changed_layer = |main_entity: &MainEntity, render_layers: &RenderLayers| {
let entity_is_relevant = is_entity_relevant(render_layers);
let entity_was_relevant = render_view_visible_mesh_entities
.entities_gpu_culling
.contains_key(main_entity);
let entity_is_relevant = is_entity_relevant(render_layers);

match (entity_was_relevant, entity_is_relevant) {
(false, false) | (true, true) => {
// No change; do nothing.
Expand All @@ -2427,6 +2446,20 @@ fn collect_gpu_culled_meshes_for_subview(
.push((Entity::PLACEHOLDER, *main_entity));
}
}
};

if view_render_layers_changed {
for (main_entity, render_layers) in render_mesh_instance_gpu_queues.entities.iter() {
process_changed_layer(main_entity, render_layers);
}
} else {
for main_entity in &render_mesh_instance_gpu_queues.changed_layers {
let Some(render_layers) = render_mesh_instance_gpu_queues.entities.get(main_entity)
else {
continue;
};
process_changed_layer(main_entity, render_layers);
}
}

// Make sure the `added_entities` list is sorted, as the
Expand Down
21 changes: 13 additions & 8 deletions crates/bevy_render/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ use crate::{
sync_world::{MainEntity, MainEntityHashSet, RenderEntity, SyncToRenderWorld},
texture::{GpuImage, ManualTextureViews},
view::{
ColorGrading, ExtractedView, ExtractedWindow, Msaa, NoIndirectDrawing,
RenderExtractedVisibleEntities, RenderVisibleEntities, RenderVisibleEntitiesClass,
ResolvedCompositingSpace, RetainedViewEntity, ViewUniformOffset,
VisibilityExtractionSystemParam,
ColorGrading, ExtractedRenderLayersMeta, ExtractedView, ExtractedWindow, Msaa,
NoIndirectDrawing, RenderExtractedVisibleEntities, RenderVisibleEntities,
RenderVisibleEntitiesClass, ResolvedCompositingSpace, RetainedViewEntity,
ViewUniformOffset, VisibilityExtractionSystemParam,
},
Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
};
Expand Down Expand Up @@ -41,7 +41,7 @@ use bevy_ecs::{
resource::Resource,
schedule::{InternedScheduleLabel, IntoScheduleConfigs, ScheduleLabel, SystemSet},
system::{Commands, Query, Res, ResMut},
world::DeferredWorld,
world::{DeferredWorld, Ref},
};
use bevy_image::Image;
use bevy_log::warn;
Expand Down Expand Up @@ -490,7 +490,7 @@ pub fn extract_cameras(
Option<&Exposure>,
Option<&TemporalJitter>,
Option<&MipBias>,
Option<&RenderLayers>,
Option<Ref<RenderLayers>>,
Option<&Projection>,
Has<NoIndirectDrawing>,
),
Expand Down Expand Up @@ -677,9 +677,14 @@ pub fn extract_cameras(
}

if let Some(render_layers) = render_layers {
commands.insert(render_layers.clone());
commands.insert((
(*render_layers).clone(),
ExtractedRenderLayersMeta {
changed: render_layers.is_changed(),
},
));
} else {
commands.remove::<RenderLayers>();
commands.remove::<(RenderLayers, ExtractedRenderLayersMeta)>();
}

if let Some(projection) = projection {
Expand Down
12 changes: 12 additions & 0 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ mod range;
use bevy_camera::visibility::*;
pub use range::*;

/// Extracted metadata about [`RenderLayers`].
///
/// Presented on every [`ExtractedView`](crate::view::ExtractedView) with [`RenderLayers`]. E.g. extracted camera, extracted light shadow map views.
///
/// Currently this is used for detecting render layers changes on the view for gpu culling entities.
/// Since cpu culling entities is not retained, thus does not care about render layers metadata
#[derive(Debug, Clone, Copy, PartialEq, Eq, Component, Default)]
pub struct ExtractedRenderLayersMeta {
/// Did render layers change in this extracted frame
pub changed: bool,
}

/// Stores a list of all entities that are visible from a single view or
/// subview, as well as the change lists.
///
Expand Down