From 81352fcb754ac5bd281f2e80f704e6a1841a1c70 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sat, 2 Apr 2022 23:06:10 +0100 Subject: [PATCH] Squash pr #4402 Setup infrastructure for render app owns extract Commit 'progress' Finish API Cleverly avoid needing the param to be 'static This same trick can't work for `StaticSystemParam` fwiw This is because `StaticSystemParam`'s item needs to exactly reference the original param, whereas this just stores it Migrate to the new pattern Remove `spawn_and_forget` It's unused, and was only ever needed for the weird extract logic Fix clippy errors Remove the trick because it's actually stupid Add some docs Fixup docs --- crates/bevy_core_pipeline/src/lib.rs | 22 +++--- crates/bevy_ecs/src/event.rs | 4 +- crates/bevy_ecs/src/system/commands/mod.rs | 6 -- crates/bevy_pbr/src/render/light.rs | 56 +++++++++------ crates/bevy_pbr/src/render/mesh.rs | 60 +++++++++------- crates/bevy_pbr/src/wireframe.rs | 11 ++- crates/bevy_render/src/camera/camera.rs | 20 +++--- crates/bevy_render/src/extract_param.rs | 68 +++++++++++++++++++ crates/bevy_render/src/lib.rs | 41 ++++++----- crates/bevy_render/src/render_asset.rs | 8 ++- crates/bevy_render/src/render_component.rs | 16 +++-- .../src/render_resource/pipeline_cache.rs | 18 ++--- crates/bevy_render/src/view/mod.rs | 6 +- crates/bevy_render/src/view/window.rs | 10 +-- crates/bevy_sprite/src/mesh2d/mesh.rs | 6 +- crates/bevy_sprite/src/render/mod.rs | 35 +++++----- crates/bevy_text/src/text2d.rs | 20 +++--- crates/bevy_ui/src/render/camera.rs | 6 +- crates/bevy_ui/src/render/mod.rs | 62 +++++++++-------- examples/2d/mesh2d_manual.rs | 6 +- examples/3d/render_to_texture.rs | 6 +- examples/shader/animate_shader.rs | 10 +-- .../shader/compute_shader_game_of_life.rs | 6 +- examples/window/multiple_windows.rs | 6 +- 24 files changed, 313 insertions(+), 196 deletions(-) create mode 100644 crates/bevy_render/src/extract_param.rs diff --git a/crates/bevy_core_pipeline/src/lib.rs b/crates/bevy_core_pipeline/src/lib.rs index 8fa6be9f299c28..c10859ddca57c9 100644 --- a/crates/bevy_core_pipeline/src/lib.rs +++ b/crates/bevy_core_pipeline/src/lib.rs @@ -34,7 +34,7 @@ use bevy_render::{ renderer::RenderDevice, texture::TextureCache, view::{ExtractedView, Msaa, ViewDepthTexture}, - RenderApp, RenderStage, RenderWorld, + Extract, RenderApp, RenderStage, }; /// When used as a resource, sets the color that is used to clear the screen between frames. @@ -348,34 +348,36 @@ impl CachedRenderPipelinePhaseItem for Transparent3d { } pub fn extract_clear_color( - clear_color: Res, - clear_colors: Res, - mut render_world: ResMut, + mut clear_color: Extract>, + mut clear_colors: Extract>, + mut commands: Commands, ) { + let clear_color = clear_color.value(); // If the clear color has changed if clear_color.is_changed() { // Update the clear color resource in the render world - render_world.insert_resource(clear_color.clone()); + commands.insert_resource(clear_color.clone()); } + let clear_colors = clear_colors.value(); // If the clear color has changed if clear_colors.is_changed() { // Update the clear color resource in the render world - render_world.insert_resource(clear_colors.clone()); + commands.insert_resource(clear_colors.clone()); } } pub fn extract_core_pipeline_camera_phases( mut commands: Commands, - active_2d: Res>, - active_3d: Res>, + mut active_2d: Extract>>, + mut active_3d: Extract>>, ) { - if let Some(entity) = active_2d.get() { + if let Some(entity) = active_2d.value().get() { commands .get_or_spawn(entity) .insert(RenderPhase::::default()); } - if let Some(entity) = active_3d.get() { + if let Some(entity) = active_3d.value().get() { commands.get_or_spawn(entity).insert_bundle(( RenderPhase::::default(), RenderPhase::::default(), diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 7147a275ddb3f7..8034c106672a99 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -1,6 +1,6 @@ //! Event handling types. -use crate::system::{Local, Res, ResMut, SystemParam}; +use crate::system::{Local, ReadOnlySystemParamFetch, Res, ResMut, SystemParam}; use crate::{self as bevy_ecs, system::Resource}; use bevy_utils::tracing::trace; use std::{ @@ -164,6 +164,8 @@ pub struct EventReader<'w, 's, T: Resource> { events: Res<'w, Events>, } +unsafe impl ReadOnlySystemParamFetch for EventReaderState {} + /// Sends events of type `T`. #[derive(SystemParam)] pub struct EventWriter<'w, 's, T: Resource> { diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 7d3f541dab930a..5695e971dab5ae 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -104,12 +104,6 @@ impl<'w, 's> Commands<'w, 's> { } } - /// Spawns a [`Bundle`] without pre-allocating an [`Entity`]. The [`Entity`] will be allocated - /// when this [`Command`] is applied. - pub fn spawn_and_forget(&mut self, bundle: impl Bundle) { - self.queue.push(Spawn { bundle }); - } - /// Creates a new entity with the components contained in `bundle`. /// /// This returns an [`EntityCommands`] builder, which enables inserting more components and diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index fbffe9cd021cd7..a7ac32b254ee8c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -28,6 +28,7 @@ use bevy_render::{ view::{ ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities, }, + Extract, }; use bevy_transform::components::GlobalTransform; use bevy_utils::{ @@ -331,8 +332,11 @@ pub struct ExtractedClustersPointLights { data: Vec, } -pub fn extract_clusters(mut commands: Commands, views: Query<(Entity, &Clusters), With>) { - for (entity, clusters) in views.iter() { +pub fn extract_clusters( + mut commands: Commands, + mut views: Extract>>, +) { + for (entity, clusters) in views.value().iter() { commands.get_or_spawn(entity).insert_bundle(( ExtractedClustersPointLights { data: clusters.lights.clone(), @@ -348,20 +352,25 @@ pub fn extract_clusters(mut commands: Commands, views: Query<(Entity, &Clusters) pub fn extract_lights( mut commands: Commands, - ambient_light: Res, - point_light_shadow_map: Res, - directional_light_shadow_map: Res, - global_point_lights: Res, + mut ambient_light: Extract>, + mut point_light_shadow_map: Extract>, + mut directional_light_shadow_map: Extract>, + mut global_point_lights: Extract>, // visible_point_lights: Query<&VisiblePointLights>, - mut point_lights: Query<(&PointLight, &mut CubemapVisibleEntities, &GlobalTransform)>, - mut directional_lights: Query<( - Entity, - &DirectionalLight, - &mut VisibleEntities, - &GlobalTransform, - &Visibility, - )>, + mut point_lights: Extract>, + mut directional_lights: Extract< + Query<( + Entity, + &DirectionalLight, + &VisibleEntities, + &GlobalTransform, + &Visibility, + )>, + >, ) { + let ambient_light = ambient_light.value(); + let point_light_shadow_map = point_light_shadow_map.value(); + let directional_light_shadow_map = directional_light_shadow_map.value(); commands.insert_resource(ExtractedAmbientLight { color: ambient_light.color, brightness: ambient_light.brightness, @@ -379,11 +388,15 @@ pub fn extract_lights( // https://catlikecoding.com/unity/tutorials/custom-srp/point-and-spot-shadows/ let point_light_texel_size = 2.0 / point_light_shadow_map.size as f32; - for entity in global_point_lights.iter().copied() { - if let Ok((point_light, cubemap_visible_entities, transform)) = point_lights.get_mut(entity) - { - let render_cubemap_visible_entities = - std::mem::take(cubemap_visible_entities.into_inner()); + let point_lights = point_lights.value(); + for entity in global_point_lights.value().iter().copied() { + if let Ok((point_light, cubemap_visible_entities, transform)) = point_lights.get(entity) { + // PERF: Ideally, this would avoid creating new allocations each frame. + // The nicest way to do that would be to get last frame's render_cubemap_visible_entities, + // and clone into that buffer. + // TODO: Evaluate whether moving the buffers into a resource at the end of frame + // is more performant. + let render_cubemap_visible_entities = cubemap_visible_entities.clone(); commands.get_or_spawn(entity).insert_bundle(( ExtractedPointLight { color: point_light.color, @@ -407,7 +420,7 @@ pub fn extract_lights( } for (entity, directional_light, visible_entities, transform, visibility) in - directional_lights.iter_mut() + directional_lights.value().iter() { if !visibility.is_visible { continue; @@ -425,7 +438,8 @@ pub fn extract_lights( ); let directional_light_texel_size = largest_dimension / directional_light_shadow_map.size as f32; - let render_visible_entities = std::mem::take(visible_entities.into_inner()); + // See above + let render_visible_entities = visible_entities.clone(); commands.get_or_spawn(entity).insert_bundle(( ExtractedDirectionalLight { color: directional_light.color, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 08ac42b83865d9..aed47c4023b748 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -22,7 +22,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }; use bevy_transform::components::GlobalTransform; use smallvec::SmallVec; @@ -97,29 +97,35 @@ pub fn extract_meshes( mut commands: Commands, mut previous_caster_len: Local, mut previous_not_caster_len: Local, - caster_query: Query< - ( - Entity, - &ComputedVisibility, - &GlobalTransform, - &Handle, - Option<&NotShadowReceiver>, - ), - Without, + mut caster_query: Extract< + Query< + ( + Entity, + &ComputedVisibility, + &GlobalTransform, + &Handle, + Option<&NotShadowReceiver>, + ), + Without, + >, >, - not_caster_query: Query< - ( - Entity, - &ComputedVisibility, - &GlobalTransform, - &Handle, - Option<&NotShadowReceiver>, - ), - With, + mut not_caster_query: Extract< + Query< + ( + Entity, + &ComputedVisibility, + &GlobalTransform, + &Handle, + Option<&NotShadowReceiver>, + ), + With, + >, >, ) { let mut caster_values = Vec::with_capacity(*previous_caster_len); - for (entity, computed_visibility, transform, handle, not_receiver) in caster_query.iter() { + for (entity, computed_visibility, transform, handle, not_receiver) in + caster_query.value().iter() + { if !computed_visibility.is_visible { continue; } @@ -144,7 +150,9 @@ pub fn extract_meshes( commands.insert_or_spawn_batch(caster_values); let mut not_caster_values = Vec::with_capacity(*previous_not_caster_len); - for (entity, computed_visibility, transform, mesh, not_receiver) in not_caster_query.iter() { + for (entity, computed_visibility, transform, mesh, not_receiver) in + not_caster_query.value().iter() + { if !computed_visibility.is_visible { continue; } @@ -216,18 +224,20 @@ impl SkinnedMeshJoints { } pub fn extract_skinned_meshes( - query: Query<(Entity, &ComputedVisibility, &SkinnedMesh)>, - inverse_bindposes: Res>, - joint_query: Query<&GlobalTransform>, + mut query: Extract>, + mut inverse_bindposes: Extract>>, + mut joint_query: Extract>, mut commands: Commands, mut previous_len: Local, mut previous_joint_len: Local, ) { + let inverse_bindposes = inverse_bindposes.value(); let mut values = Vec::with_capacity(*previous_len); let mut joints = Vec::with_capacity(*previous_joint_len); let mut last_start = 0; - for (entity, computed_visibility, skin) in query.iter() { + let joint_query = joint_query.value(); + for (entity, computed_visibility, skin) in query.value().iter() { if !computed_visibility.is_visible { continue; } diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index c79b04513570fd..10b1168be2aae3 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -5,6 +5,7 @@ use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_core_pipeline::Opaque3d; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_reflect::{Reflect, TypeUuid}; +use bevy_render::Extract; use bevy_render::{ mesh::{Mesh, MeshVertexBufferLayout}, render_asset::RenderAssets, @@ -47,14 +48,18 @@ impl Plugin for WireframePlugin { } } -fn extract_wireframe_config(mut commands: Commands, wireframe_config: Res) { +fn extract_wireframe_config( + mut commands: Commands, + mut wireframe_config: Extract>, +) { + let wireframe_config = wireframe_config.value(); if wireframe_config.is_added() || wireframe_config.is_changed() { commands.insert_resource(wireframe_config.into_inner().clone()); } } -fn extract_wireframes(mut commands: Commands, query: Query>) { - for entity in query.iter() { +fn extract_wireframes(mut commands: Commands, mut query: Extract>>) { + for entity in query.value().iter() { commands.get_or_spawn(entity).insert(Wireframe); } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 528926ebd4be96..b74847b49791b0 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -6,7 +6,7 @@ use crate::{ render_asset::RenderAssets, render_resource::TextureView, view::{ExtractedView, ExtractedWindows, VisibleEntities}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }; use bevy_app::{App, CoreStage, Plugin, StartupStage}; use bevy_asset::{AssetEvent, Assets, Handle}; @@ -288,18 +288,22 @@ pub struct ExtractedCamera { pub fn extract_cameras( mut commands: Commands, - windows: Res, - images: Res>, - active_camera: Res>, - query: Query<(&Camera, &GlobalTransform, &VisibleEntities), With>, + mut windows: Extract>, + mut images: Extract>>, + mut active_camera: Extract>>, + mut query: Extract>>, ) { + let active_camera = active_camera.value(); if let Some(entity) = active_camera.get() { - if let Ok((camera, transform, visible_entities)) = query.get(entity) { - if let Some(size) = camera.target.get_physical_size(&windows, &images) { + if let Ok((camera, transform, visible_entities)) = query.value().get(entity) { + if let Some(size) = camera + .target + .get_physical_size(&windows.value(), &images.value()) + { commands.get_or_spawn(entity).insert_bundle(( ExtractedCamera { target: camera.target.clone(), - physical_size: camera.target.get_physical_size(&windows, &images), + physical_size: Some(size), }, ExtractedView { projection: camera.projection_matrix, diff --git a/crates/bevy_render/src/extract_param.rs b/crates/bevy_render/src/extract_param.rs new file mode 100644 index 00000000000000..95ba1333ae5581 --- /dev/null +++ b/crates/bevy_render/src/extract_param.rs @@ -0,0 +1,68 @@ +use crate::MainWorld; +use bevy_ecs::{ + prelude::*, + system::{ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState}, +}; + +/// Implementation detail of [`Extract`] +pub struct MainWorldState(SystemState

); + +impl FromWorld for MainWorldState

{ + fn from_world(world: &mut World) -> Self { + Self(SystemState::new(&mut world.resource_mut::().0)) + } +} + +/// A helper for accessing [`MainWorld`] content using a system parameter. +/// +/// A [`SystemParam`] adapter which applies the contained `SystemParam` to the [`World`] +/// contained in [`MainWorld`]. This parameter only works for systems run +/// during [`RenderStage::Extract`]. +/// +/// This requires that the contained [`SystemParam`] does not mutate the world, as it +/// uses [`Res`](Res). To get access to the contained `SystemParam`'s item, you +/// must use [`Extract::value`]. This is required because of lifetime limitations in +/// the `SystemParam` api. +/// +/// ## Context +/// +/// [`RenderStage::Extract`] is used to extract (move) data from the simulation world ([`MainWorld`]) to the +/// render world. The render world drives rendering each frame (generally to a [Window]). +/// This design is used to allow performing calculations related to rendering a prior frame at the same +/// time as the next frame is simulated, which increases throughput (FPS). +/// +/// [`Extract`] is used to get data from the main world during [`RenderStage::Extract`]. +/// +/// ## Examples +/// +/// ```rust +/// use bevy_ecs::prelude::*; +/// use bevy_render::Extract; +/// # #[derive(Component)] +/// # struct Cloud; +/// fn extract_clouds(mut commands: Commands, mut clouds: Extract>>) { +/// for cloud in clouds.value().iter() { +/// commands.get_or_spawn(cloud).insert(Cloud); +/// } +/// } +/// ``` +/// +/// [`RenderStage::Extract`]: crate::RenderStage::Extract +/// [Window]: bevy_window::Window +#[derive(SystemParam)] +pub struct Extract<'w, 's, P: SystemParam + 'static> +where + P::Fetch: ReadOnlySystemParamFetch, +{ + state: Local<'s, MainWorldState

>, + world: Res<'w, MainWorld>, +} + +impl<'w, 's, P: SystemParam + 'static> Extract<'w, 's, P> +where + P::Fetch: ReadOnlySystemParamFetch, +{ + pub fn value(&mut self) -> SystemParamItem<'_, '_, P> { + self.state.0.get(&self.world) + } +} diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 5d7127c0ce7b1e..d237219573c12b 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -2,6 +2,7 @@ extern crate core; pub mod camera; pub mod color; +mod extract_param; pub mod mesh; pub mod primitives; pub mod render_asset; @@ -14,6 +15,8 @@ pub mod settings; pub mod texture; pub mod view; +pub use extract_param::Extract; + pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -80,11 +83,13 @@ pub enum RenderStage { Cleanup, } -/// The Render App World. This is only available as a resource during the Extract step. +/// The simulation [World] of the application, stored as a resource. +/// This resource is only available during [`RenderStage::Extract`]. +/// See [`Extract`] for more details. #[derive(Default)] -pub struct RenderWorld(World); +pub struct MainWorld(World); -impl Deref for RenderWorld { +impl Deref for MainWorld { type Target = World; fn deref(&self) -> &Self::Target { @@ -92,7 +97,7 @@ impl Deref for RenderWorld { } } -impl DerefMut for RenderWorld { +impl DerefMut for MainWorld { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -103,9 +108,9 @@ impl DerefMut for RenderWorld { pub struct RenderApp; /// A "scratch" world used to avoid allocating new worlds every frame when -/// swapping out the [`RenderWorld`]. +/// swapping out the [`MainWorld`] for [`RenderStage::Extract`]. #[derive(Default)] -struct ScratchRenderWorld(World); +struct ScratchMainWorld(World); impl Plugin for RenderPlugin { /// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app. @@ -145,7 +150,7 @@ impl Plugin for RenderPlugin { app.insert_resource(device.clone()) .insert_resource(queue.clone()) .insert_resource(adapter_info.clone()) - .init_resource::() + .init_resource::() .register_type::() .register_type::(); @@ -297,17 +302,17 @@ fn extract(app_world: &mut World, render_app: &mut App) { .get_stage_mut::(&RenderStage::Extract) .unwrap(); - // temporarily add the render world to the app world as a resource - let scratch_world = app_world.remove_resource::().unwrap(); - let render_world = std::mem::replace(&mut render_app.world, scratch_world.0); - app_world.insert_resource(RenderWorld(render_world)); - - extract.run(app_world); + // temporarily add the app world to the render world as a resource + let scratch_world = app_world.remove_resource::().unwrap(); + let inserted_world = std::mem::replace(app_world, scratch_world.0); + let running_world = &mut render_app.world; + running_world.insert_resource(MainWorld(inserted_world)); - // add the render world back to the render app - let render_world = app_world.remove_resource::().unwrap(); - let scratch_world = std::mem::replace(&mut render_app.world, render_world.0); - app_world.insert_resource(ScratchRenderWorld(scratch_world)); + extract.run(running_world); + extract.apply_buffers(running_world); - extract.apply_buffers(&mut render_app.world); + // move the app world back, as if nothing happened. + let inserted_world = running_world.remove_resource::().unwrap(); + let scratch_world = std::mem::replace(app_world, inserted_world.0); + app_world.insert_resource(ScratchMainWorld(scratch_world)); } diff --git a/crates/bevy_render/src/render_asset.rs b/crates/bevy_render/src/render_asset.rs index 3ee311ffda79e7..173ec40124afaf 100644 --- a/crates/bevy_render/src/render_asset.rs +++ b/crates/bevy_render/src/render_asset.rs @@ -1,4 +1,4 @@ -use crate::{RenderApp, RenderStage}; +use crate::{Extract, RenderApp, RenderStage}; use bevy_app::{App, Plugin}; use bevy_asset::{Asset, AssetEvent, Assets, Handle}; use bevy_ecs::{ @@ -128,9 +128,10 @@ pub type RenderAssets = HashMap, ::PreparedAsset> /// into the "render world". fn extract_render_asset( mut commands: Commands, - mut events: EventReader>, - assets: Res>, + mut events: Extract>>, + mut assets: Extract>>, ) { + let mut events = events.value(); let mut changed_assets = HashSet::default(); let mut removed = Vec::new(); for event in events.iter() { @@ -149,6 +150,7 @@ fn extract_render_asset( } let mut extracted_assets = Vec::new(); + let assets = assets.value(); for handle in changed_assets.drain() { if let Some(asset) = assets.get(handle) { extracted_assets.push((handle.clone_weak(), asset.extract_asset())); diff --git a/crates/bevy_render/src/render_component.rs b/crates/bevy_render/src/render_component.rs index f4e901587ee8a8..cf4260225daabe 100644 --- a/crates/bevy_render/src/render_component.rs +++ b/crates/bevy_render/src/render_component.rs @@ -1,15 +1,15 @@ use crate::{ render_resource::{std140::AsStd140, DynamicUniformVec}, renderer::{RenderDevice, RenderQueue}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_asset::{Asset, Handle}; use bevy_ecs::{ component::Component, prelude::*, - query::{FilterFetch, QueryItem, WorldQuery}, - system::{lifetimeless::Read, StaticSystemParam}, + query::{FilterFetch, QueryItem, ReadOnlyFetch, WorldQuery}, + system::lifetimeless::Read, }; use std::{marker::PhantomData, ops::Deref}; @@ -141,7 +141,8 @@ impl Default for ExtractComponentPlugin { impl Plugin for ExtractComponentPlugin where - ::Fetch: FilterFetch, + ::Fetch: FilterFetch + ReadOnlyFetch, + ::Fetch: ReadOnlyFetch, { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { @@ -164,12 +165,13 @@ impl ExtractComponent for Handle { fn extract_components( mut commands: Commands, mut previous_len: Local, - mut query: StaticSystemParam>, + mut query: Extract>, ) where - ::Fetch: FilterFetch, + ::Fetch: FilterFetch + ReadOnlyFetch, + ::Fetch: ReadOnlyFetch, { let mut values = Vec::with_capacity(*previous_len); - for (entity, query_item) in query.iter_mut() { + for (entity, query_item) in query.value().iter_mut() { values.push((entity, (C::extract_component(query_item),))); } *previous_len = values.len(); diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 559ff745fa314a..4b914642129c11 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -7,11 +7,13 @@ use crate::{ ShaderProcessor, ShaderReflectError, }, renderer::RenderDevice, - RenderWorld, + Extract, }; use bevy_asset::{AssetEvent, Assets, Handle}; -use bevy_ecs::event::EventReader; -use bevy_ecs::system::{Res, ResMut}; +use bevy_ecs::{ + event::EventReader, + system::{Res, ResMut}, +}; use bevy_utils::{default, tracing::error, Entry, HashMap, HashSet}; use std::{hash::Hash, mem, ops::Deref, sync::Arc}; use thiserror::Error; @@ -524,12 +526,12 @@ impl PipelineCache { } pub(crate) fn extract_shaders( - mut world: ResMut, - shaders: Res>, - mut events: EventReader>, + mut cache: ResMut, + mut shaders: Extract>>, + mut events: Extract>>, ) { - let mut cache = world.resource_mut::(); - for event in events.iter() { + let shaders = shaders.value(); + for event in events.value().iter() { match event { AssetEvent::Created { handle } | AssetEvent::Modified { handle } => { if let Some(shader) = shaders.get(handle) { diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index ba712a31943cde..740ab9cdf70b73 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -15,7 +15,7 @@ use crate::{ render_resource::{std140::AsStd140, DynamicUniformVec, Texture, TextureView}, renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, TextureCache}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; @@ -69,9 +69,9 @@ impl Default for Msaa { } } -pub fn extract_msaa(mut commands: Commands, msaa: Res) { +pub fn extract_msaa(mut commands: Commands, mut msaa: Extract>) { // NOTE: windows.is_changed() handles cases where a window was resized - commands.insert_resource(msaa.clone()); + commands.insert_resource(msaa.value().clone()); } #[derive(Component)] diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index c06776c54a8787..e1835865a3e2e4 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -2,7 +2,7 @@ use crate::{ render_resource::TextureView, renderer::{RenderDevice, RenderInstance}, texture::BevyDefault, - RenderApp, RenderStage, RenderWorld, + Extract, RenderApp, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; @@ -67,9 +67,11 @@ impl DerefMut for ExtractedWindows { } } -fn extract_windows(mut render_world: ResMut, windows: Res) { - let mut extracted_windows = render_world.resource_mut::(); - for window in windows.iter() { +fn extract_windows( + mut extracted_windows: ResMut, + mut windows: Extract>, +) { + for window in windows.value().iter() { let (new_width, new_height) = ( window.physical_width().max(1), window.physical_height().max(1), diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 4a804372b978a5..c24de04e0b2980 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -15,7 +15,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }; use bevy_transform::components::GlobalTransform; @@ -90,10 +90,10 @@ bitflags::bitflags! { pub fn extract_mesh2d( mut commands: Commands, mut previous_len: Local, - query: Query<(Entity, &ComputedVisibility, &GlobalTransform, &Mesh2dHandle)>, + mut query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); - for (entity, computed_visibility, transform, handle) in query.iter() { + for (entity, computed_visibility, transform, handle) in query.value().iter() { if !computed_visibility.is_visible { continue; } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 577f9da4d855fb..c4ddebcfe4054c 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -24,7 +24,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, Image}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, - RenderWorld, + Extract, }; use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; @@ -198,14 +198,13 @@ pub struct SpriteAssetEvents { } pub fn extract_sprite_events( - mut render_world: ResMut, - mut image_events: EventReader>, + mut events: ResMut, + mut image_events: Extract>>, ) { - let mut events = render_world.resource_mut::(); let SpriteAssetEvents { ref mut images } = *events; images.clear(); - for image in image_events.iter() { + for image in image_events.value().iter() { // AssetEvent: !Clone images.push(match image { AssetEvent::Created { handle } => AssetEvent::Created { @@ -222,19 +221,20 @@ pub fn extract_sprite_events( } pub fn extract_sprites( - mut render_world: ResMut, - texture_atlases: Res>, - sprite_query: Query<(&Visibility, &Sprite, &GlobalTransform, &Handle)>, - atlas_query: Query<( - &Visibility, - &TextureAtlasSprite, - &GlobalTransform, - &Handle, - )>, + mut extracted_sprites: ResMut, + mut texture_atlases: Extract>>, + mut sprite_query: Extract)>>, + mut atlas_query: Extract< + Query<( + &Visibility, + &TextureAtlasSprite, + &GlobalTransform, + &Handle, + )>, + >, ) { - let mut extracted_sprites = render_world.resource_mut::(); extracted_sprites.sprites.clear(); - for (visibility, sprite, transform, handle) in sprite_query.iter() { + for (visibility, sprite, transform, handle) in sprite_query.value().iter() { if !visibility.is_visible { continue; } @@ -252,7 +252,8 @@ pub fn extract_sprites( anchor: sprite.anchor.as_vec(), }); } - for (visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { + let texture_atlases = texture_atlases.value(); + for (visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.value().iter() { if !visibility.is_visible { continue; } diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 9bab65aa982970..4c95d9cd242f7e 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ }; use bevy_math::{Size, Vec3}; use bevy_reflect::Reflect; -use bevy_render::{texture::Image, view::Visibility, RenderWorld}; +use bevy_render::{texture::Image, view::Visibility, Extract}; use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_window::{WindowId, Windows}; @@ -59,17 +59,17 @@ pub struct Text2dBundle { } pub fn extract_text2d_sprite( - mut render_world: ResMut, - texture_atlases: Res>, - text_pipeline: Res, - windows: Res, - text2d_query: Query<(Entity, &Visibility, &Text, &GlobalTransform, &Text2dSize)>, + mut extracted_sprites: ResMut, + mut texture_atlases: Extract>>, + mut text_pipeline: Extract>, + mut windows: Extract>, + mut text2d_query: Extract>, ) { - let mut extracted_sprites = render_world.resource_mut::(); - - let scale_factor = windows.scale_factor(WindowId::primary()) as f32; + let scale_factor = windows.value().scale_factor(WindowId::primary()) as f32; - for (entity, visibility, text, transform, calculated_size) in text2d_query.iter() { + let texture_atlases = texture_atlases.value(); + let text_pipeline = text_pipeline.value(); + for (entity, visibility, text, transform, calculated_size) in text2d_query.value().iter() { if !visibility.is_visible { continue; } diff --git a/crates/bevy_ui/src/render/camera.rs b/crates/bevy_ui/src/render/camera.rs index d03c972951714a..f15305e33422b4 100644 --- a/crates/bevy_ui/src/render/camera.rs +++ b/crates/bevy_ui/src/render/camera.rs @@ -1,5 +1,5 @@ use bevy_ecs::prelude::*; -use bevy_render::{camera::ActiveCamera, render_phase::RenderPhase}; +use bevy_render::{camera::ActiveCamera, render_phase::RenderPhase, Extract}; use crate::prelude::CameraUi; @@ -8,9 +8,9 @@ use super::TransparentUi; /// Inserts the [`RenderPhase`] into the UI camera pub fn extract_ui_camera_phases( mut commands: Commands, - active_camera: Res>, + mut active_camera: Extract>>, ) { - if let Some(entity) = active_camera.get() { + if let Some(entity) = active_camera.value().get() { commands .get_or_spawn(entity) .insert(RenderPhase::::default()); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 554c3b3e7e681f..56b6bc9df18834 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -22,7 +22,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::Image, view::{ViewUniforms, Visibility}, - RenderApp, RenderStage, RenderWorld, + Extract, RenderApp, RenderStage, }; use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas}; use bevy_text::{DefaultTextPipeline, Text}; @@ -127,20 +127,22 @@ pub struct ExtractedUiNodes { } pub fn extract_uinodes( - mut render_world: ResMut, - images: Res>, - uinode_query: Query<( - &Node, - &GlobalTransform, - &UiColor, - &UiImage, - &Visibility, - Option<&CalculatedClip>, - )>, + mut extracted_uinodes: ResMut, + mut images: Extract>>, + mut uinode_query: Extract< + Query<( + &Node, + &GlobalTransform, + &UiColor, + &UiImage, + &Visibility, + Option<&CalculatedClip>, + )>, + >, ) { - let mut extracted_uinodes = render_world.resource_mut::(); extracted_uinodes.uinodes.clear(); - for (uinode, transform, color, image, visibility, clip) in uinode_query.iter() { + let images = images.value(); + for (uinode, transform, color, image, visibility, clip) in uinode_query.value().iter() { if !visibility.is_visible { continue; } @@ -164,24 +166,26 @@ pub fn extract_uinodes( } pub fn extract_text_uinodes( - mut render_world: ResMut, - texture_atlases: Res>, - text_pipeline: Res, - windows: Res, - uinode_query: Query<( - Entity, - &Node, - &GlobalTransform, - &Text, - &Visibility, - Option<&CalculatedClip>, - )>, + mut extracted_uinodes: ResMut, + mut texture_atlases: Extract>>, + mut text_pipeline: Extract>, + mut windows: Extract>, + mut uinode_query: Extract< + Query<( + Entity, + &Node, + &GlobalTransform, + &Text, + &Visibility, + Option<&CalculatedClip>, + )>, + >, ) { - let mut extracted_uinodes = render_world.resource_mut::(); - - let scale_factor = windows.scale_factor(WindowId::primary()) as f32; + let scale_factor = windows.value().scale_factor(WindowId::primary()) as f32; + let texture_atlases = texture_atlases.value(); + let text_pipeline = text_pipeline.value(); - for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() { + for (entity, uinode, transform, text, visibility, clip) in uinode_query.value().iter() { if !visibility.is_visible { continue; } diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index e4cc86d8861643..3408330f8dd4b9 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -15,7 +15,7 @@ use bevy::{ }, texture::BevyDefault, view::VisibleEntities, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }, sprite::{ DrawMesh2d, Mesh2dHandle, Mesh2dPipeline, Mesh2dPipelineKey, Mesh2dUniform, @@ -279,10 +279,10 @@ impl Plugin for ColoredMesh2dPlugin { pub fn extract_colored_mesh2d( mut commands: Commands, mut previous_len: Local, - query: Query<(Entity, &ComputedVisibility), With>, + mut query: Extract>>, ) { let mut values = Vec::with_capacity(*previous_len); - for (entity, computed_visibility) in query.iter() { + for (entity, computed_visibility) in query.value().iter() { if !computed_visibility.is_visible { continue; } diff --git a/examples/3d/render_to_texture.rs b/examples/3d/render_to_texture.rs index fb27722342d46c..e0020d9f8f9370 100644 --- a/examples/3d/render_to_texture.rs +++ b/examples/3d/render_to_texture.rs @@ -12,7 +12,7 @@ use bevy::{ }, renderer::RenderContext, view::RenderLayers, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }, }; @@ -59,9 +59,9 @@ fn main() { // Add 3D render phases for FIRST_PASS_CAMERA. fn extract_first_pass_camera_phases( mut commands: Commands, - active: Res>, + mut active: Extract>>, ) { - if let Some(entity) = active.get() { + if let Some(entity) = active.value().get() { commands.get_or_spawn(entity).insert_bundle(( RenderPhase::::default(), RenderPhase::::default(), diff --git a/examples/shader/animate_shader.rs b/examples/shader/animate_shader.rs index abdf5fafe69b9e..6f53b490e2a0d6 100644 --- a/examples/shader/animate_shader.rs +++ b/examples/shader/animate_shader.rs @@ -16,7 +16,7 @@ use bevy::{ render_resource::*, renderer::{RenderDevice, RenderQueue}, view::{ComputedVisibility, ExtractedView, Msaa, Visibility}, - RenderApp, RenderStage, + Extract, RenderApp, RenderStage, }, }; @@ -81,10 +81,10 @@ impl Plugin for CustomMaterialPlugin { fn extract_custom_material( mut commands: Commands, mut previous_len: Local, - mut query: Query>, + mut query: Extract>>, ) { let mut values = Vec::with_capacity(*previous_len); - for entity in query.iter_mut() { + for entity in query.value().iter() { values.push((entity, (CustomMaterial,))); } *previous_len = values.len(); @@ -136,9 +136,9 @@ struct ExtractedTime { } // extract the passed time into a resource in the render world -fn extract_time(mut commands: Commands, time: Res