From 4f1d9a63152589d5286647e68cc3ce0e67f1838c Mon Sep 17 00:00:00 2001 From: James O'Brien Date: Sun, 27 Aug 2023 07:33:49 -0700 Subject: [PATCH] Reorder render sets, refactor bevy_sprite to take advantage (#9236) This is a continuation of this PR: #8062 # Objective - Reorder render schedule sets to allow data preparation when phase item order is known to support improved batching - Part of the batching/instancing etc plan from here: https://github.com/bevyengine/bevy/issues/89#issuecomment-1379249074 - The original idea came from @inodentry and proved to be a good one. Thanks! - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the new ordering ## Solution - Move `Prepare` and `PrepareFlush` after `PhaseSortFlush` - Add a `PrepareAssets` set that runs in parallel with other systems and sets in the render schedule. - Put prepare_assets systems in the `PrepareAssets` set - If explicit dependencies are needed on Mesh or Material RenderAssets then depend on the appropriate system. - Add `ManageViews` and `ManageViewsFlush` sets between `ExtractCommands` and Queue - Move `queue_mesh*_bind_group` to the Prepare stage - Rename them to `prepare_` - Put systems that prepare resources (buffers, textures, etc.) into a `PrepareResources` set inside `Prepare` - Put the `prepare_..._bind_group` systems into a `PrepareBindGroup` set after `PrepareResources` - Move `prepare_lights` to the `ManageViews` set - `prepare_lights` creates views and this must happen before `Queue` - This system needs refactoring to stop handling all responsibilities - Gather lights, sort, and create shadow map views. Store sorted light entities in a resource - Remove `BatchedPhaseItem` - Replace `batch_range` with `batch_size` representing how many items to skip after rendering the item or to skip the item entirely if `batch_size` is 0. - `queue_sprites` has been split into `queue_sprites` for queueing phase items and `prepare_sprites` for batching after the `PhaseSort` - `PhaseItem`s are still inserted in `queue_sprites` - After sorting adjacent compatible sprite phase items are accumulated into `SpriteBatch` components on the first entity of each batch, containing a range of vertex indices. The associated `PhaseItem`'s `batch_size` is updated appropriately. - `SpriteBatch` items are then drawn skipping over the other items in the batch based on the value in `batch_size` - A very similar refactor was performed on `bevy_ui` --- ## Changelog Changed: - Reordered and reworked render app schedule sets. The main change is that data is extracted, queued, sorted, and then prepared when the order of data is known. - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the reordering. ## Migration Guide - Assets such as materials and meshes should now be created in `PrepareAssets` e.g. `prepare_assets` - Queueing entities to `RenderPhase`s continues to be done in `Queue` e.g. `queue_sprites` - Preparing resources (textures, buffers, etc.) should now be done in `PrepareResources`, e.g. `prepare_prepass_textures`, `prepare_mesh_uniforms` - Prepare bind groups should now be done in `PrepareBindGroups` e.g. `prepare_mesh_bind_group` - Any batching or instancing can now be done in `Prepare` where the order of the phase items is known e.g. `prepare_sprites` ## Next Steps - Introduce some generic mechanism to ensure items that can be batched are grouped in the phase item order, currently you could easily have `[sprite at z 0, mesh at z 0, sprite at z 0]` preventing batching. - Investigate improved orderings for building the MeshUniform buffer - Implementing batching across the rest of bevy --------- Co-authored-by: Robert Swain Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com> --- crates/bevy_core_pipeline/src/bloom/mod.rs | 6 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 30 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 56 +- .../bevy_core_pipeline/src/msaa_writeback.rs | 4 +- crates/bevy_core_pipeline/src/prepass/mod.rs | 30 +- crates/bevy_core_pipeline/src/skybox/mod.rs | 4 +- crates/bevy_core_pipeline/src/taa/mod.rs | 11 +- .../bevy_core_pipeline/src/tonemapping/mod.rs | 4 +- .../bevy_core_pipeline/src/upscaling/mod.rs | 4 +- crates/bevy_gizmos/src/lib.rs | 7 +- crates/bevy_gizmos/src/pipeline_2d.rs | 11 +- crates/bevy_gizmos/src/pipeline_3d.rs | 10 +- crates/bevy_pbr/Cargo.toml | 1 + crates/bevy_pbr/src/lib.rs | 39 +- crates/bevy_pbr/src/material.rs | 42 +- crates/bevy_pbr/src/prepass/mod.rs | 49 +- crates/bevy_pbr/src/render/fog.rs | 12 +- crates/bevy_pbr/src/render/light.rs | 32 +- crates/bevy_pbr/src/render/mesh.rs | 82 ++- crates/bevy_pbr/src/ssao/mod.rs | 13 +- crates/bevy_pbr/src/wireframe.rs | 80 +-- crates/bevy_render/src/camera/mod.rs | 2 +- crates/bevy_render/src/extract_component.rs | 2 +- crates/bevy_render/src/globals.rs | 5 +- .../src/gpu_component_array_buffer.rs | 2 +- crates/bevy_render/src/lib.rs | 61 +- crates/bevy_render/src/mesh/mod.rs | 5 +- crates/bevy_render/src/render_asset.rs | 80 ++- crates/bevy_render/src/render_phase/mod.rs | 247 ++------ crates/bevy_render/src/texture/mod.rs | 14 +- crates/bevy_render/src/view/mod.rs | 30 +- crates/bevy_render/src/view/window/mod.rs | 8 +- crates/bevy_sprite/src/lib.rs | 9 +- crates/bevy_sprite/src/mesh2d/material.rs | 12 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 8 +- crates/bevy_sprite/src/render/mod.rs | 493 ++++++++-------- crates/bevy_text/src/text2d.rs | 30 +- crates/bevy_ui/src/render/mod.rs | 558 ++++++++++-------- crates/bevy_ui/src/render/render_pass.rs | 16 +- examples/2d/mesh2d_manual.rs | 4 +- .../shader/compute_shader_game_of_life.rs | 7 +- examples/shader/shader_instancing.rs | 5 +- 42 files changed, 989 insertions(+), 1136 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 5ec42d0c2e5cd..7ee2091031558 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -68,10 +68,10 @@ impl Plugin for BloomPlugin { .add_systems( Render, ( - prepare_bloom_textures.in_set(RenderSet::Prepare), prepare_downsampling_pipeline.in_set(RenderSet::Prepare), prepare_upsampling_pipeline.in_set(RenderSet::Prepare), - queue_bloom_bind_groups.in_set(RenderSet::Queue), + prepare_bloom_textures.in_set(RenderSet::PrepareResources), + prepare_bloom_bind_groups.in_set(RenderSet::PrepareBindGroups), ), ) // Add bloom to the 3d render graph @@ -403,7 +403,7 @@ struct BloomBindGroups { sampler: Sampler, } -fn queue_bloom_bind_groups( +fn prepare_bloom_bind_groups( mut commands: Commands, render_device: Res, downsampling_pipeline: Res, diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index d3d12130b393f..49f4260b203fc 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -29,14 +29,13 @@ use bevy_render::{ extract_component::ExtractComponentPlugin, render_graph::{EmptyNode, RenderGraphApp, ViewNodeRunner}, render_phase::{ - batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem, - DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase, + sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem, + RenderPhase, }, render_resource::CachedRenderPipelineId, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::FloatOrd; -use std::ops::Range; use crate::{tonemapping::TonemappingNode, upscaling::UpscalingNode}; @@ -57,12 +56,7 @@ impl Plugin for Core2dPlugin { .add_systems(ExtractSchedule, extract_core_2d_camera_phases) .add_systems( Render, - ( - sort_phase_system::.in_set(RenderSet::PhaseSort), - batch_phase_system:: - .after(sort_phase_system::) - .in_set(RenderSet::PhaseSort), - ), + sort_phase_system::.in_set(RenderSet::PhaseSort), ); use graph::node::*; @@ -89,8 +83,7 @@ pub struct Transparent2d { pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, - /// Range in the vertex buffer of this item - pub batch_range: Option>, + pub batch_size: usize, } impl PhaseItem for Transparent2d { @@ -115,6 +108,11 @@ impl PhaseItem for Transparent2d { fn sort(items: &mut [Self]) { items.sort_by_key(|item| item.sort_key()); } + + #[inline] + fn batch_size(&self) -> usize { + self.batch_size + } } impl CachedRenderPipelinePhaseItem for Transparent2d { @@ -124,16 +122,6 @@ impl CachedRenderPipelinePhaseItem for Transparent2d { } } -impl BatchedPhaseItem for Transparent2d { - fn batch_range(&self) -> &Option> { - &self.batch_range - } - - fn batch_range_mut(&mut self) -> &mut Option> { - &mut self.batch_range - } -} - pub fn extract_core_2d_camera_phases( mut commands: Commands, cameras_2d: Extract>>, diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 5ea5e9781260f..f415751cde719 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -87,17 +87,13 @@ impl Plugin for Core3dPlugin { .add_systems( Render, ( - prepare_core_3d_depth_textures - .in_set(RenderSet::Prepare) - .after(bevy_render::view::prepare_windows), - prepare_prepass_textures - .in_set(RenderSet::Prepare) - .after(bevy_render::view::prepare_windows), sort_phase_system::.in_set(RenderSet::PhaseSort), sort_phase_system::.in_set(RenderSet::PhaseSort), sort_phase_system::.in_set(RenderSet::PhaseSort), sort_phase_system::.in_set(RenderSet::PhaseSort), sort_phase_system::.in_set(RenderSet::PhaseSort), + prepare_core_3d_depth_textures.in_set(RenderSet::PrepareResources), + prepare_prepass_textures.in_set(RenderSet::PrepareResources), ), ); @@ -136,18 +132,15 @@ impl Plugin for Core3dPlugin { pub struct Opaque3d { pub distance: f32, - // Per-object data may be bound at different dynamic offsets within a buffer. If it is, then - // each batch of per-object data starts at the same dynamic offset. - pub per_object_binding_dynamic_offset: u32, pub pipeline: CachedRenderPipelineId, pub entity: Entity, pub draw_function: DrawFunctionId, + pub batch_size: usize, } impl PhaseItem for Opaque3d { - // NOTE: (dynamic offset, -distance) // NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort. - type SortKey = (u32, Reverse); + type SortKey = Reverse; #[inline] fn entity(&self) -> Entity { @@ -156,10 +149,7 @@ impl PhaseItem for Opaque3d { #[inline] fn sort_key(&self) -> Self::SortKey { - ( - self.per_object_binding_dynamic_offset, - Reverse(FloatOrd(self.distance)), - ) + Reverse(FloatOrd(self.distance)) } #[inline] @@ -170,9 +160,12 @@ impl PhaseItem for Opaque3d { #[inline] fn sort(items: &mut [Self]) { // Key negated to match reversed SortKey ordering - radsort::sort_by_key(items, |item| { - (item.per_object_binding_dynamic_offset, -item.distance) - }); + radsort::sort_by_key(items, |item| -item.distance); + } + + #[inline] + fn batch_size(&self) -> usize { + self.batch_size } } @@ -185,18 +178,15 @@ impl CachedRenderPipelinePhaseItem for Opaque3d { pub struct AlphaMask3d { pub distance: f32, - // Per-object data may be bound at different dynamic offsets within a buffer. If it is, then - // each batch of per-object data starts at the same dynamic offset. - pub per_object_binding_dynamic_offset: u32, pub pipeline: CachedRenderPipelineId, pub entity: Entity, pub draw_function: DrawFunctionId, + pub batch_size: usize, } impl PhaseItem for AlphaMask3d { - // NOTE: (dynamic offset, -distance) // NOTE: Values increase towards the camera. Front-to-back ordering for alpha mask means we need a descending sort. - type SortKey = (u32, Reverse); + type SortKey = Reverse; #[inline] fn entity(&self) -> Entity { @@ -205,10 +195,7 @@ impl PhaseItem for AlphaMask3d { #[inline] fn sort_key(&self) -> Self::SortKey { - ( - self.per_object_binding_dynamic_offset, - Reverse(FloatOrd(self.distance)), - ) + Reverse(FloatOrd(self.distance)) } #[inline] @@ -219,9 +206,12 @@ impl PhaseItem for AlphaMask3d { #[inline] fn sort(items: &mut [Self]) { // Key negated to match reversed SortKey ordering - radsort::sort_by_key(items, |item| { - (item.per_object_binding_dynamic_offset, -item.distance) - }); + radsort::sort_by_key(items, |item| -item.distance); + } + + #[inline] + fn batch_size(&self) -> usize { + self.batch_size } } @@ -237,6 +227,7 @@ pub struct Transparent3d { pub pipeline: CachedRenderPipelineId, pub entity: Entity, pub draw_function: DrawFunctionId, + pub batch_size: usize, } impl PhaseItem for Transparent3d { @@ -262,6 +253,11 @@ impl PhaseItem for Transparent3d { fn sort(items: &mut [Self]) { radsort::sort_by_key(items, |item| item.distance); } + + #[inline] + fn batch_size(&self) -> usize { + self.batch_size + } } impl CachedRenderPipelinePhaseItem for Transparent3d { diff --git a/crates/bevy_core_pipeline/src/msaa_writeback.rs b/crates/bevy_core_pipeline/src/msaa_writeback.rs index cd925c37225d5..0646d4ce67ffb 100644 --- a/crates/bevy_core_pipeline/src/msaa_writeback.rs +++ b/crates/bevy_core_pipeline/src/msaa_writeback.rs @@ -26,7 +26,7 @@ impl Plugin for MsaaWritebackPlugin { render_app.add_systems( Render, - queue_msaa_writeback_pipelines.in_set(RenderSet::Queue), + prepare_msaa_writeback_pipelines.in_set(RenderSet::Prepare), ); { use core_2d::graph::node::*; @@ -123,7 +123,7 @@ impl Node for MsaaWritebackNode { #[derive(Component)] pub struct MsaaWritebackBlitPipeline(CachedRenderPipelineId); -fn queue_msaa_writeback_pipelines( +fn prepare_msaa_writeback_pipelines( mut commands: Commands, pipeline_cache: Res, mut pipelines: ResMut>, diff --git a/crates/bevy_core_pipeline/src/prepass/mod.rs b/crates/bevy_core_pipeline/src/prepass/mod.rs index 8edae904f67a7..38c71050a194b 100644 --- a/crates/bevy_core_pipeline/src/prepass/mod.rs +++ b/crates/bevy_core_pipeline/src/prepass/mod.rs @@ -80,18 +80,14 @@ pub struct ViewPrepassTextures { /// Used to render all 3D meshes with materials that have no transparency. pub struct Opaque3dPrepass { pub distance: f32, - // Per-object data may be bound at different dynamic offsets within a buffer. If it is, then - // each batch of per-object data starts at the same dynamic offset. - pub per_object_binding_dynamic_offset: u32, pub entity: Entity, pub pipeline_id: CachedRenderPipelineId, pub draw_function: DrawFunctionId, } impl PhaseItem for Opaque3dPrepass { - // NOTE: (dynamic offset, -distance) // NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort. - type SortKey = (u32, Reverse); + type SortKey = Reverse; #[inline] fn entity(&self) -> Entity { @@ -100,10 +96,7 @@ impl PhaseItem for Opaque3dPrepass { #[inline] fn sort_key(&self) -> Self::SortKey { - ( - self.per_object_binding_dynamic_offset, - Reverse(FloatOrd(self.distance)), - ) + Reverse(FloatOrd(self.distance)) } #[inline] @@ -114,9 +107,7 @@ impl PhaseItem for Opaque3dPrepass { #[inline] fn sort(items: &mut [Self]) { // Key negated to match reversed SortKey ordering - radsort::sort_by_key(items, |item| { - (item.per_object_binding_dynamic_offset, -item.distance) - }); + radsort::sort_by_key(items, |item| -item.distance); } } @@ -134,18 +125,14 @@ impl CachedRenderPipelinePhaseItem for Opaque3dPrepass { /// Used to render all meshes with a material with an alpha mask. pub struct AlphaMask3dPrepass { pub distance: f32, - // Per-object data may be bound at different dynamic offsets within a buffer. If it is, then - // each batch of per-object data starts at the same dynamic offset. - pub per_object_binding_dynamic_offset: u32, pub entity: Entity, pub pipeline_id: CachedRenderPipelineId, pub draw_function: DrawFunctionId, } impl PhaseItem for AlphaMask3dPrepass { - // NOTE: (dynamic offset, -distance) // NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort. - type SortKey = (u32, Reverse); + type SortKey = Reverse; #[inline] fn entity(&self) -> Entity { @@ -154,10 +141,7 @@ impl PhaseItem for AlphaMask3dPrepass { #[inline] fn sort_key(&self) -> Self::SortKey { - ( - self.per_object_binding_dynamic_offset, - Reverse(FloatOrd(self.distance)), - ) + Reverse(FloatOrd(self.distance)) } #[inline] @@ -168,9 +152,7 @@ impl PhaseItem for AlphaMask3dPrepass { #[inline] fn sort(items: &mut [Self]) { // Key negated to match reversed SortKey ordering - radsort::sort_by_key(items, |item| { - (item.per_object_binding_dynamic_offset, -item.distance) - }); + radsort::sort_by_key(items, |item| -item.distance); } } diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index ccf21334aa10a..86fa28aa8a530 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -47,7 +47,7 @@ impl Plugin for SkyboxPlugin { Render, ( prepare_skybox_pipelines.in_set(RenderSet::Prepare), - queue_skybox_bind_groups.in_set(RenderSet::Queue), + prepare_skybox_bind_groups.in_set(RenderSet::PrepareBindGroups), ), ); } @@ -209,7 +209,7 @@ fn prepare_skybox_pipelines( #[derive(Component)] pub struct SkyboxBindGroup(pub BindGroup); -fn queue_skybox_bind_groups( +fn prepare_skybox_bind_groups( mut commands: Commands, pipeline: Res, view_uniforms: Res, diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 66097d3beeb20..a674ab825bcde 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -10,7 +10,7 @@ use bevy_core::FrameCount; use bevy_ecs::{ prelude::{Bundle, Component, Entity}, query::{QueryItem, With}, - schedule::{apply_deferred, IntoSystemConfigs}, + schedule::IntoSystemConfigs, system::{Commands, Query, Res, ResMut, Resource}, world::{FromWorld, World}, }; @@ -31,7 +31,7 @@ use bevy_render::{ }, renderer::{RenderContext, RenderDevice}, texture::{BevyDefault, CachedTexture, TextureCache}, - view::{prepare_view_uniforms, ExtractedView, Msaa, ViewTarget}, + view::{ExtractedView, Msaa, ViewTarget}, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet, }; @@ -67,12 +67,9 @@ impl Plugin for TemporalAntiAliasPlugin { .add_systems( Render, ( - (prepare_taa_jitter_and_mip_bias, apply_deferred) - .chain() - .before(prepare_view_uniforms) - .in_set(RenderSet::Prepare), - prepare_taa_history_textures.in_set(RenderSet::Prepare), + prepare_taa_jitter_and_mip_bias.in_set(RenderSet::ManageViews), prepare_taa_pipelines.in_set(RenderSet::Prepare), + prepare_taa_history_textures.in_set(RenderSet::PrepareResources), ), ) .add_render_graph_node::>(CORE_3D, draw_3d_graph::node::TAA) diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index c7a049604f8fd..5ff93f1fdc25d 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -97,7 +97,7 @@ impl Plugin for TonemappingPlugin { .init_resource::>() .add_systems( Render, - queue_view_tonemapping_pipelines.in_set(RenderSet::Queue), + prepare_view_tonemapping_pipelines.in_set(RenderSet::Prepare), ); } } @@ -272,7 +272,7 @@ impl FromWorld for TonemappingPipeline { #[derive(Component)] pub struct ViewTonemappingPipeline(CachedRenderPipelineId); -pub fn queue_view_tonemapping_pipelines( +pub fn prepare_view_tonemapping_pipelines( mut commands: Commands, pipeline_cache: Res, mut pipelines: ResMut>, diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index f3594397d5120..76475c8692bf5 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -16,7 +16,7 @@ impl Plugin for UpscalingPlugin { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app.add_systems( Render, - queue_view_upscaling_pipelines.in_set(RenderSet::Queue), + prepare_view_upscaling_pipelines.in_set(RenderSet::Prepare), ); } } @@ -25,7 +25,7 @@ impl Plugin for UpscalingPlugin { #[derive(Component)] pub struct ViewUpscalingPipeline(CachedRenderPipelineId); -fn queue_view_upscaling_pipelines( +fn prepare_view_upscaling_pipelines( mut commands: Commands, pipeline_cache: Res, mut pipelines: ResMut>, diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 22ca7291c38ff..631cb058fa4ac 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -102,7 +102,10 @@ impl Plugin for GizmoPlugin { render_app .add_systems(ExtractSchedule, extract_gizmo_data) - .add_systems(Render, queue_line_gizmo_bind_group.in_set(RenderSet::Queue)); + .add_systems( + Render, + prepare_line_gizmo_bind_group.in_set(RenderSet::PrepareBindGroups), + ); #[cfg(feature = "bevy_sprite")] app.add_plugins(pipeline_2d::LineGizmo2dPlugin); @@ -413,7 +416,7 @@ struct LineGizmoUniformBindgroup { bindgroup: BindGroup, } -fn queue_line_gizmo_bind_group( +fn prepare_line_gizmo_bind_group( mut commands: Commands, line_gizmo_uniform_layout: Res, render_device: Res, diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 128998b0b834b..fa345f2bf05e1 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -13,7 +13,7 @@ use bevy_ecs::{ world::{FromWorld, World}, }; use bevy_render::{ - render_asset::RenderAssets, + render_asset::{prepare_assets, RenderAssets}, render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline}, render_resource::*, texture::BevyDefault, @@ -34,7 +34,12 @@ impl Plugin for LineGizmo2dPlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_line_gizmos_2d.in_set(RenderSet::Queue)); + .add_systems( + Render, + queue_line_gizmos_2d + .in_set(RenderSet::Queue) + .after(prepare_assets::), + ); } fn finish(&self, app: &mut App) { @@ -173,7 +178,7 @@ fn queue_line_gizmos_2d( draw_function, pipeline, sort_key: FloatOrd(f32::INFINITY), - batch_range: None, + batch_size: 1, }); } } diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 9d015f0f047f7..33712fa020557 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -14,7 +14,7 @@ use bevy_ecs::{ }; use bevy_pbr::{MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup}; use bevy_render::{ - render_asset::RenderAssets, + render_asset::{prepare_assets, RenderAssets}, render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline}, render_resource::*, texture::BevyDefault, @@ -32,7 +32,12 @@ impl Plugin for LineGizmo3dPlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_line_gizmos_3d.in_set(RenderSet::Queue)); + .add_systems( + Render, + queue_line_gizmos_3d + .in_set(RenderSet::Queue) + .after(prepare_assets::), + ); } fn finish(&self, app: &mut App) { @@ -187,6 +192,7 @@ fn queue_line_gizmos_3d( draw_function, pipeline, distance: 0., + batch_size: 1, }); } } diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 8366556275585..5ff50b66d6644 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -27,6 +27,7 @@ bevy_derive = { path = "../bevy_derive", version = "0.12.0-dev" } # other bitflags = "2.3" +fixedbitset = "0.4" # direct dependency required for derive macro bytemuck = { version = "1", features = ["derive"] } naga_oil = "0.8" diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 32dee04f3419b..4d8f31fc8abeb 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -56,14 +56,10 @@ use bevy_asset::{load_internal_asset, AddAsset, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; use bevy_reflect::TypeUuid; use bevy_render::{ - camera::CameraUpdateSystem, - extract_resource::ExtractResourcePlugin, - prelude::Color, - render_graph::RenderGraph, - render_phase::sort_phase_system, - render_resource::Shader, - view::{ViewSet, VisibilitySystems}, - ExtractSchedule, Render, RenderApp, RenderSet, + camera::CameraUpdateSystem, extract_resource::ExtractResourcePlugin, prelude::Color, + render_asset::prepare_assets, render_graph::RenderGraph, render_phase::sort_phase_system, + render_resource::Shader, texture::Image, view::VisibilitySystems, ExtractSchedule, Render, + RenderApp, RenderSet, }; use bevy_transform::TransformSystem; use environment_map::EnvironmentMapPlugin; @@ -269,37 +265,18 @@ impl Plugin for PbrPlugin { // Extract the required data from the main world render_app - .configure_sets( - Render, - ( - RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare), - RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare), - RenderLightSystems::QueueShadows.in_set(RenderSet::Queue), - ), - ) .add_systems( ExtractSchedule, - ( - render::extract_clusters.in_set(RenderLightSystems::ExtractClusters), - render::extract_lights.in_set(RenderLightSystems::ExtractLights), - ), + (render::extract_clusters, render::extract_lights), ) .add_systems( Render, ( render::prepare_lights - .before(ViewSet::PrepareUniforms) - .in_set(RenderLightSystems::PrepareLights), - // A sync is needed after prepare_lights, before prepare_view_uniforms, - // because prepare_lights creates new views for shadow mapping - apply_deferred - .in_set(RenderSet::Prepare) - .after(RenderLightSystems::PrepareLights) - .before(ViewSet::PrepareUniforms), - render::prepare_clusters - .after(render::prepare_lights) - .in_set(RenderLightSystems::PrepareClusters), + .in_set(RenderSet::ManageViews) + .after(prepare_assets::), sort_phase_system::.in_set(RenderSet::PhaseSort), + render::prepare_clusters.in_set(RenderSet::PrepareResources), ), ) .init_resource::(); diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 13e736d139e9a..9c4e82d5de7d7 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1,7 +1,7 @@ use crate::{ render, AlphaMode, DrawMesh, DrawPrepass, EnvironmentMapLight, MeshPipeline, MeshPipelineKey, - MeshTransforms, MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, - ScreenSpaceAmbientOcclusionSettings, SetMeshBindGroup, SetMeshViewBindGroup, Shadow, + MeshTransforms, PrepassPipelinePlugin, PrepassPlugin, ScreenSpaceAmbientOcclusionSettings, + SetMeshBindGroup, SetMeshViewBindGroup, Shadow, }; use bevy_app::{App, Plugin}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; @@ -24,15 +24,15 @@ use bevy_render::{ extract_component::ExtractComponentPlugin, mesh::{Mesh, MeshVertexBufferLayout}, prelude::Image, - render_asset::{PrepareAssetSet, RenderAssets}, + render_asset::{prepare_assets, RenderAssets}, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, }, render_resource::{ - AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, GpuArrayBufferIndex, - OwnedBindingResource, PipelineCache, RenderPipelineDescriptor, Shader, ShaderRef, - SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines, + AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource, + PipelineCache, RenderPipelineDescriptor, Shader, ShaderRef, SpecializedMeshPipeline, + SpecializedMeshPipelineError, SpecializedMeshPipelines, }, renderer::RenderDevice, texture::FallbackImage, @@ -205,10 +205,14 @@ where Render, ( prepare_materials:: - .in_set(RenderSet::Prepare) - .after(PrepareAssetSet::PreAssetPrepare), - render::queue_shadows::.in_set(RenderLightSystems::QueueShadows), - queue_material_meshes::.in_set(RenderSet::Queue), + .in_set(RenderSet::PrepareAssets) + .after(prepare_assets::), + render::queue_shadows:: + .in_set(RenderSet::QueueMeshes) + .after(prepare_materials::), + queue_material_meshes:: + .in_set(RenderSet::QueueMeshes) + .after(prepare_materials::), ), ); } @@ -379,12 +383,7 @@ pub fn queue_material_meshes( msaa: Res, render_meshes: Res>, render_materials: Res>, - material_meshes: Query<( - &Handle, - &Handle, - &MeshTransforms, - &GpuArrayBufferIndex, - )>, + material_meshes: Query<(&Handle, &Handle, &MeshTransforms)>, images: Res>, mut views: Query<( &ExtractedView, @@ -468,7 +467,7 @@ pub fn queue_material_meshes( let rangefinder = view.rangefinder3d(); for visible_entity in &visible_entities.entities { - if let Ok((material_handle, mesh_handle, mesh_transforms, batch_indices)) = + if let Ok((material_handle, mesh_handle, mesh_transforms)) = material_meshes.get(*visible_entity) { if let (Some(mesh), Some(material)) = ( @@ -526,9 +525,7 @@ pub fn queue_material_meshes( draw_function: draw_opaque_pbr, pipeline: pipeline_id, distance, - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), + batch_size: 1, }); } AlphaMode::Mask(_) => { @@ -537,9 +534,7 @@ pub fn queue_material_meshes( draw_function: draw_alpha_mask_pbr, pipeline: pipeline_id, distance, - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), + batch_size: 1, }); } AlphaMode::Blend @@ -551,6 +546,7 @@ pub fn queue_material_meshes( draw_function: draw_transparent_pbr, pipeline: pipeline_id, distance, + batch_size: 1, }); } } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index c402b30e0aa6f..21ea58e57f8f6 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -30,11 +30,11 @@ use bevy_render::{ BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendState, BufferBindingType, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, - DynamicUniformBuffer, FragmentState, FrontFace, GpuArrayBufferIndex, MultisampleState, - PipelineCache, PolygonMode, PrimitiveState, PushConstantRange, RenderPipelineDescriptor, - Shader, ShaderRef, ShaderStages, ShaderType, SpecializedMeshPipeline, - SpecializedMeshPipelineError, SpecializedMeshPipelines, StencilFaceState, StencilState, - TextureSampleType, TextureViewDimension, VertexState, + DynamicUniformBuffer, FragmentState, FrontFace, MultisampleState, PipelineCache, + PolygonMode, PrimitiveState, PushConstantRange, RenderPipelineDescriptor, Shader, + ShaderRef, ShaderStages, ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError, + SpecializedMeshPipelines, StencilFaceState, StencilState, TextureSampleType, + TextureViewDimension, VertexState, }, renderer::{RenderDevice, RenderQueue}, texture::{FallbackImagesDepth, FallbackImagesMsaa}, @@ -45,9 +45,9 @@ use bevy_transform::prelude::GlobalTransform; use bevy_utils::tracing::error; use crate::{ - prepare_lights, setup_morph_and_skinning_defs, AlphaMode, DrawMesh, Material, MaterialPipeline, - MaterialPipelineKey, MeshLayouts, MeshPipeline, MeshPipelineKey, MeshTransforms, MeshUniform, - RenderMaterials, SetMaterialBindGroup, SetMeshBindGroup, + prepare_materials, setup_morph_and_skinning_defs, AlphaMode, DrawMesh, Material, + MaterialPipeline, MaterialPipelineKey, MeshLayouts, MeshPipeline, MeshPipelineKey, + MeshTransforms, RenderMaterials, SetMaterialBindGroup, SetMeshBindGroup, }; use std::{hash::Hash, marker::PhantomData}; @@ -105,7 +105,7 @@ where render_app .add_systems( Render, - queue_prepass_view_bind_group::.in_set(RenderSet::Queue), + prepare_prepass_view_bind_group::.in_set(RenderSet::PrepareBindGroups), ) .init_resource::() .init_resource::>>() @@ -161,15 +161,7 @@ where .add_systems(ExtractSchedule, extract_camera_previous_view_projection) .add_systems( Render, - ( - prepare_previous_view_projection_uniforms - .in_set(RenderSet::Prepare) - .after(PrepassLightsViewFlush), - apply_deferred - .in_set(RenderSet::Prepare) - .in_set(PrepassLightsViewFlush) - .after(prepare_lights), - ), + prepare_previous_view_projection_uniforms.in_set(RenderSet::PrepareResources), ); } @@ -178,7 +170,9 @@ where .add_render_command::>() .add_systems( Render, - queue_prepass_material_meshes::.in_set(RenderSet::Queue), + queue_prepass_material_meshes:: + .in_set(RenderSet::QueueMeshes) + .after(prepare_materials::), ); } } @@ -697,7 +691,7 @@ pub struct PrepassViewBindGroup { no_motion_vectors: Option, } -pub fn queue_prepass_view_bind_group( +pub fn prepare_prepass_view_bind_group( render_device: Res, prepass_pipeline: Res>, view_uniforms: Res, @@ -759,12 +753,7 @@ pub fn queue_prepass_material_meshes( msaa: Res, render_meshes: Res>, render_materials: Res>, - material_meshes: Query<( - &Handle, - &Handle, - &MeshTransforms, - &GpuArrayBufferIndex, - )>, + material_meshes: Query<(&Handle, &Handle, &MeshTransforms)>, mut views: Query<( &ExtractedView, &VisibleEntities, @@ -809,7 +798,7 @@ pub fn queue_prepass_material_meshes( let rangefinder = view.rangefinder3d(); for visible_entity in &visible_entities.entities { - let Ok((material_handle, mesh_handle, mesh_transforms, batch_indices)) = + let Ok((material_handle, mesh_handle, mesh_transforms)) = material_meshes.get(*visible_entity) else { continue; @@ -863,9 +852,6 @@ pub fn queue_prepass_material_meshes( draw_function: opaque_draw_prepass, pipeline_id, distance, - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), }); } AlphaMode::Mask(_) => { @@ -874,9 +860,6 @@ pub fn queue_prepass_material_meshes( draw_function: alpha_mask_draw_prepass, pipeline_id, distance, - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), }); } AlphaMode::Blend diff --git a/crates/bevy_pbr/src/render/fog.rs b/crates/bevy_pbr/src/render/fog.rs index 6c314ccd0495f..3cf9d4528af12 100644 --- a/crates/bevy_pbr/src/render/fog.rs +++ b/crates/bevy_pbr/src/render/fog.rs @@ -113,12 +113,6 @@ pub fn prepare_fog( .write_buffer(&render_device, &render_queue); } -/// Labels for fog-related systems -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -pub enum RenderFogSystems { - PrepareFog, -} - /// Inserted on each `Entity` with an `ExtractedView` to keep track of its offset /// in the `gpu_fogs` `DynamicUniformBuffer` within `FogMeta` #[derive(Component)] @@ -143,11 +137,7 @@ impl Plugin for FogPlugin { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .init_resource::() - .add_systems(Render, prepare_fog.in_set(RenderFogSystems::PrepareFog)) - .configure_set( - Render, - RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare), - ); + .add_systems(Render, prepare_fog.in_set(RenderSet::PrepareResources)); } } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 265a27e026f2d..d8469f527a4be 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -3,8 +3,8 @@ use crate::{ CascadeShadowConfig, Cascades, CascadesVisibleEntities, Clusters, CubemapVisibleEntities, DirectionalLight, DirectionalLightShadowMap, DrawPrepass, EnvironmentMapLight, GlobalVisiblePointLights, Material, MaterialPipelineKey, MeshPipeline, MeshPipelineKey, - MeshUniform, NotShadowCaster, PointLight, PointLightShadowMap, PrepassPipeline, - RenderMaterials, SpotLight, VisiblePointLights, + NotShadowCaster, PointLight, PointLightShadowMap, PrepassPipeline, RenderMaterials, SpotLight, + VisiblePointLights, }; use bevy_asset::Handle; use bevy_core_pipeline::core_3d::Transparent3d; @@ -32,15 +32,6 @@ use bevy_utils::{ }; use std::{hash::Hash, num::NonZeroU64}; -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -pub enum RenderLightSystems { - ExtractClusters, - ExtractLights, - PrepareClusters, - PrepareLights, - QueueShadows, -} - #[derive(Component)] pub struct ExtractedPointLight { color: Color, @@ -1556,10 +1547,7 @@ pub fn prepare_clusters( pub fn queue_shadows( shadow_draw_functions: Res>, prepass_pipeline: Res>, - casting_meshes: Query< - (&GpuArrayBufferIndex, &Handle, &Handle), - Without, - >, + casting_meshes: Query<(&Handle, &Handle), Without>, render_meshes: Res>, render_materials: Res>, mut pipelines: ResMut>>, @@ -1604,9 +1592,7 @@ pub fn queue_shadows( // NOTE: Lights with shadow mapping disabled will have no visible entities // so no meshes will be queued for entity in visible_entities.iter().copied() { - if let Ok((batch_indices, mesh_handle, material_handle)) = - casting_meshes.get(entity) - { + if let Ok((mesh_handle, material_handle)) = casting_meshes.get(entity) { if let (Some(mesh), Some(material)) = ( render_meshes.get(mesh_handle), render_materials.get(material_handle), @@ -1653,9 +1639,6 @@ pub fn queue_shadows( pipeline: pipeline_id, entity, distance: 0.0, // TODO: sort front-to-back - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), }); } } @@ -1666,16 +1649,13 @@ pub fn queue_shadows( pub struct Shadow { pub distance: f32, - // Per-object data may be bound at different dynamic offsets within a buffer. If it is, then - // each batch of per-object data starts at the same dynamic offset. - pub per_object_binding_dynamic_offset: u32, pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, } impl PhaseItem for Shadow { - type SortKey = (usize, u32); + type SortKey = usize; #[inline] fn entity(&self) -> Entity { @@ -1684,7 +1664,7 @@ impl PhaseItem for Shadow { #[inline] fn sort_key(&self) -> Self::SortKey { - (self.pipeline.id(), self.per_object_binding_dynamic_offset) + self.pipeline.id() } #[inline] diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 6c61f05b8f4fc..c1f0fed803d3d 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1,13 +1,14 @@ use crate::{ environment_map, prepass, EnvironmentMapLight, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta, NotShadowCaster, NotShadowReceiver, PreviousGlobalTransform, - ScreenSpaceAmbientOcclusionTextures, ShadowSamplers, ViewClusterBindings, ViewFogUniformOffset, - ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, + ScreenSpaceAmbientOcclusionTextures, Shadow, ShadowSamplers, ViewClusterBindings, + ViewFogUniformOffset, ViewLightsUniformOffset, ViewShadowBindings, + CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, }; use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Assets, Handle, HandleId, HandleUntyped}; use bevy_core_pipeline::{ + core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, prepass::ViewPrepassTextures, tonemapping::{ get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts, @@ -29,7 +30,7 @@ use bevy_render::{ }, prelude::Msaa, render_asset::RenderAssets, - render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, + render_phase::{PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, TrackedRenderPass}, render_resource::*, renderer::{RenderDevice, RenderQueue}, texture::{ @@ -41,6 +42,7 @@ use bevy_render::{ }; use bevy_transform::components::GlobalTransform; use bevy_utils::{tracing::error, HashMap, Hashed}; +use fixedbitset::FixedBitSet; use crate::render::{ morph::{extract_morphs, prepare_morphs, MorphIndex, MorphUniform}, @@ -126,11 +128,11 @@ impl Plugin for MeshRenderPlugin { .add_systems( Render, ( - prepare_mesh_uniforms.in_set(RenderSet::Prepare), - prepare_skinned_meshes.in_set(RenderSet::Prepare), - prepare_morphs.in_set(RenderSet::Prepare), - queue_mesh_bind_group.in_set(RenderSet::Queue), - queue_mesh_view_bind_groups.in_set(RenderSet::Queue), + prepare_mesh_uniforms.in_set(RenderSet::PrepareResources), + prepare_skinned_meshes.in_set(RenderSet::PrepareResources), + prepare_morphs.in_set(RenderSet::PrepareResources), + prepare_mesh_bind_group.in_set(RenderSet::PrepareBindGroups), + prepare_mesh_view_bind_groups.in_set(RenderSet::PrepareBindGroups), ), ); } @@ -380,25 +382,59 @@ pub fn extract_skinned_meshes( commands.insert_or_spawn_batch(values); } -fn prepare_mesh_uniforms( +#[allow(clippy::too_many_arguments)] +pub fn prepare_mesh_uniforms( + mut seen: Local, mut commands: Commands, + mut previous_len: Local, render_device: Res, render_queue: Res, mut gpu_array_buffer: ResMut>, - components: Query<(Entity, &MeshTransforms)>, + views: Query<( + &RenderPhase, + &RenderPhase, + &RenderPhase, + )>, + shadow_views: Query<&RenderPhase>, + meshes: Query<(Entity, &MeshTransforms)>, ) { gpu_array_buffer.clear(); + seen.clear(); + + let mut indices = Vec::with_capacity(*previous_len); + let mut push_indices = |(mesh, mesh_uniform): (Entity, &MeshTransforms)| { + let index = mesh.index() as usize; + if !seen.contains(index) { + if index >= seen.len() { + seen.grow(index + 1); + } + seen.insert(index); + indices.push((mesh, gpu_array_buffer.push(mesh_uniform.into()))); + } + }; - let entities = components - .iter() - .map(|(entity, mesh_transforms)| { - ( - entity, - gpu_array_buffer.push(MeshUniform::from(mesh_transforms)), - ) - }) - .collect::>(); - commands.insert_or_spawn_batch(entities); + for (opaque_phase, transparent_phase, alpha_phase) in &views { + meshes + .iter_many(opaque_phase.iter_entities()) + .for_each(&mut push_indices); + + meshes + .iter_many(transparent_phase.iter_entities()) + .for_each(&mut push_indices); + + meshes + .iter_many(alpha_phase.iter_entities()) + .for_each(&mut push_indices); + } + + for shadow_phase in &shadow_views { + meshes + .iter_many(shadow_phase.iter_entities()) + .for_each(&mut push_indices); + } + + *previous_len = indices.len(); + commands.insert_or_spawn_batch(indices); gpu_array_buffer.write_buffer(&render_device, &render_queue); } @@ -1062,7 +1098,7 @@ impl MeshBindGroups { } } -pub fn queue_mesh_bind_group( +pub fn prepare_mesh_bind_group( meshes: Res>, mut groups: ResMut, mesh_pipeline: Res, @@ -1138,7 +1174,7 @@ pub struct MeshViewBindGroup { } #[allow(clippy::too_many_arguments)] -pub fn queue_mesh_view_bind_groups( +pub fn prepare_mesh_view_bind_groups( mut commands: Commands, render_device: Res, mesh_pipeline: Res, diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index e2d016b95738a..30d8c07141dbd 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -116,9 +116,14 @@ impl Plugin for ScreenSpaceAmbientOcclusionPlugin { .init_resource::() .init_resource::>() .add_systems(ExtractSchedule, extract_ssao_settings) - .add_systems(Render, prepare_ssao_textures.in_set(RenderSet::Prepare)) - .add_systems(Render, prepare_ssao_pipelines.in_set(RenderSet::Prepare)) - .add_systems(Render, queue_ssao_bind_groups.in_set(RenderSet::Queue)) + .add_systems( + Render, + ( + prepare_ssao_pipelines.in_set(RenderSet::Prepare), + prepare_ssao_textures.in_set(RenderSet::PrepareResources), + prepare_ssao_bind_groups.in_set(RenderSet::PrepareBindGroups), + ), + ) .add_render_graph_node::>( CORE_3D, draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION, @@ -755,7 +760,7 @@ struct SsaoBindGroups { spatial_denoise_bind_group: BindGroup, } -fn queue_ssao_bind_groups( +fn prepare_ssao_bind_groups( mut commands: Commands, render_device: Res, pipelines: Res, diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index cefb2c83d3f7e..e227bfdb7d4d6 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -1,4 +1,4 @@ -use crate::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; +use crate::{DrawMesh, MeshPipelineKey, SetMeshBindGroup, SetMeshViewBindGroup}; use crate::{MeshPipeline, MeshTransforms}; use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; @@ -7,7 +7,6 @@ use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::{Reflect, TypeUuid}; use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin}; -use bevy_render::render_resource::GpuArrayBufferIndex; use bevy_render::Render; use bevy_render::{ extract_resource::{ExtractResource, ExtractResourcePlugin}, @@ -50,7 +49,7 @@ impl Plugin for WireframePlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_wireframes.in_set(RenderSet::Queue)); + .add_systems(Render, queue_wireframes.in_set(RenderSet::QueueMeshes)); } } @@ -118,21 +117,8 @@ fn queue_wireframes( pipeline_cache: Res, msaa: Res, mut material_meshes: ParamSet<( - Query<( - Entity, - &Handle, - &MeshTransforms, - &GpuArrayBufferIndex, - )>, - Query< - ( - Entity, - &Handle, - &MeshTransforms, - &GpuArrayBufferIndex, - ), - With, - >, + Query<(Entity, &Handle, &MeshTransforms)>, + Query<(Entity, &Handle, &MeshTransforms), With>, )>, mut views: Query<(&ExtractedView, &VisibleEntities, &mut RenderPhase)>, ) { @@ -142,36 +128,34 @@ fn queue_wireframes( let rangefinder = view.rangefinder3d(); let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); - let add_render_phase = |(entity, mesh_handle, mesh_transforms, batch_indices): ( - Entity, - &Handle, - &MeshTransforms, - &GpuArrayBufferIndex, - )| { - if let Some(mesh) = render_meshes.get(mesh_handle) { - let key = - view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology); - let pipeline_id = - pipelines.specialize(&pipeline_cache, &wireframe_pipeline, key, &mesh.layout); - let pipeline_id = match pipeline_id { - Ok(id) => id, - Err(err) => { - error!("{}", err); - return; - } - }; - opaque_phase.add(Opaque3d { - entity, - pipeline: pipeline_id, - draw_function: draw_custom, - distance: rangefinder - .distance_translation(&mesh_transforms.transform.translation), - per_object_binding_dynamic_offset: batch_indices - .dynamic_offset - .unwrap_or_default(), - }); - } - }; + let add_render_phase = + |(entity, mesh_handle, mesh_transforms): (Entity, &Handle, &MeshTransforms)| { + if let Some(mesh) = render_meshes.get(mesh_handle) { + let key = view_key + | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology); + let pipeline_id = pipelines.specialize( + &pipeline_cache, + &wireframe_pipeline, + key, + &mesh.layout, + ); + let pipeline_id = match pipeline_id { + Ok(id) => id, + Err(err) => { + error!("{}", err); + return; + } + }; + opaque_phase.add(Opaque3d { + entity, + pipeline: pipeline_id, + draw_function: draw_custom, + distance: rangefinder + .distance_translation(&mesh_transforms.transform.translation), + batch_size: 1, + }); + } + }; if wireframe_config.global { let query = material_meshes.p0(); diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index b57ae98dc7941..2a92ff159692c 100644 --- a/crates/bevy_render/src/camera/mod.rs +++ b/crates/bevy_render/src/camera/mod.rs @@ -39,7 +39,7 @@ impl Plugin for CameraPlugin { render_app .init_resource::() .add_systems(ExtractSchedule, extract_cameras) - .add_systems(Render, sort_cameras.in_set(RenderSet::Prepare)); + .add_systems(Render, sort_cameras.in_set(RenderSet::ManageViews)); let camera_driver_node = CameraDriverNode::new(&mut render_app.world); let mut render_graph = render_app.world.resource_mut::(); render_graph.add_node(crate::main_graph::node::CAMERA_DRIVER, camera_driver_node); diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 606c8ccbe09ac..758c3a7b50a12 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -85,7 +85,7 @@ impl Plugin for UniformComponentP .insert_resource(ComponentUniforms::::default()) .add_systems( Render, - prepare_uniform_components::.in_set(RenderSet::Prepare), + prepare_uniform_components::.in_set(RenderSet::PrepareResources), ); } } diff --git a/crates/bevy_render/src/globals.rs b/crates/bevy_render/src/globals.rs index eb91d019f3cf6..6d49d09373688 100644 --- a/crates/bevy_render/src/globals.rs +++ b/crates/bevy_render/src/globals.rs @@ -27,7 +27,10 @@ impl Plugin for GlobalsPlugin { .init_resource::() .init_resource::