From 5685ec30f4add7ab53851e4897f72597e7df1773 Mon Sep 17 00:00:00 2001 From: B_head Date: Tue, 27 Jun 2023 03:34:49 +0900 Subject: [PATCH 01/13] Relaxed runner type from `Fn` to `FnOnce` --- crates/bevy_app/src/app.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index aff7afe904c7c..62e1dbea1c3d8 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -64,7 +64,7 @@ pub struct App { /// the application's event loop and advancing the [`Schedule`]. /// Typically, it is not configured manually, but set by one of Bevy's built-in plugins. /// See `bevy::winit::WinitPlugin` and [`ScheduleRunnerPlugin`](crate::schedule_runner::ScheduleRunnerPlugin). - pub runner: Box, // Send bound is required to make App Send + pub runner: Box, // Send bound is required to make App Send /// The schedule that systems are added to by default. /// /// The schedule that runs the main loop of schedule execution. @@ -651,7 +651,7 @@ impl App { /// App::new() /// .set_runner(my_runner); /// ``` - pub fn set_runner(&mut self, run_fn: impl Fn(App) + 'static + Send) -> &mut Self { + pub fn set_runner(&mut self, run_fn: impl FnOnce(App) + 'static + Send) -> &mut Self { self.runner = Box::new(run_fn); self } From a919628bf2704c788f7bffd742df31f9d6249e23 Mon Sep 17 00:00:00 2001 From: B_head Date: Sun, 25 Jun 2023 20:02:41 +0900 Subject: [PATCH 02/13] Move `Render` label --- crates/bevy_app/src/lib.rs | 2 +- crates/bevy_app/src/main_schedule.rs | 4 ++++ crates/bevy_core_pipeline/src/bloom/mod.rs | 4 ++-- .../src/contrast_adaptive_sharpening/mod.rs | 2 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/core_3d/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/fxaa/mod.rs | 2 +- crates/bevy_core_pipeline/src/msaa_writeback.rs | 4 ++-- crates/bevy_core_pipeline/src/skybox/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/taa/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/tonemapping/mod.rs | 2 +- crates/bevy_core_pipeline/src/upscaling/mod.rs | 2 +- crates/bevy_gizmos/src/lib.rs | 4 ++-- crates/bevy_gizmos/src/pipeline_2d.rs | 4 ++-- crates/bevy_gizmos/src/pipeline_3d.rs | 4 ++-- crates/bevy_pbr/src/lib.rs | 2 +- crates/bevy_pbr/src/material.rs | 4 ++-- crates/bevy_pbr/src/prepass/mod.rs | 4 ++-- crates/bevy_pbr/src/render/fog.rs | 4 ++-- crates/bevy_pbr/src/render/mesh.rs | 4 ++-- crates/bevy_pbr/src/ssao/mod.rs | 4 ++-- crates/bevy_pbr/src/wireframe.rs | 3 +-- crates/bevy_render/src/lib.rs | 10 +++------- crates/bevy_render/src/pipelined_rendering.rs | 2 +- crates/bevy_sprite/src/lib.rs | 2 +- crates/bevy_sprite/src/mesh2d/material.rs | 4 ++-- crates/bevy_sprite/src/mesh2d/mesh.rs | 4 ++-- crates/bevy_ui/src/render/mod.rs | 2 +- crates/bevy_winit/src/lib.rs | 2 +- examples/2d/mesh2d_manual.rs | 2 +- examples/shader/compute_shader_game_of_life.rs | 2 +- examples/shader/shader_instancing.rs | 2 +- examples/stress_tests/many_lights.rs | 2 +- 33 files changed, 54 insertions(+), 55 deletions(-) diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index 1941392ee0194..26658f3b196f2 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -25,7 +25,7 @@ pub mod prelude { pub use crate::{ app::App, main_schedule::{ - First, FixedUpdate, Last, Main, PostStartup, PostUpdate, PreStartup, PreUpdate, + First, FixedUpdate, Last, Main, PostStartup, PostUpdate, PreStartup, PreUpdate, Render, Startup, StateTransition, Update, }, DynamicPlugin, Plugin, PluginGroup, diff --git a/crates/bevy_app/src/main_schedule.rs b/crates/bevy_app/src/main_schedule.rs index c940fda5337b9..2ef4336f74e87 100644 --- a/crates/bevy_app/src/main_schedule.rs +++ b/crates/bevy_app/src/main_schedule.rs @@ -95,6 +95,10 @@ pub struct PostUpdate; #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] pub struct Last; +/// The main render schedule. +#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)] +pub struct Render; + /// Defines the schedules to be run for the [`Main`] schedule, including /// their order. #[derive(Resource, Debug)] diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index e5271544e2d78..6f92849b170fe 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -8,7 +8,7 @@ use crate::{ core_2d::{self, CORE_2D}, core_3d::{self, CORE_3D}, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_ecs::{prelude::*, query::QueryItem}; use bevy_math::UVec2; @@ -24,7 +24,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice}, texture::{CachedTexture, TextureCache}, view::ViewTarget, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; use downsampling_pipeline::{ prepare_downsampling_pipeline, BloomDownsamplingPipeline, BloomDownsamplingPipelineIds, diff --git a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs index b26c02b54754b..c6d3264349c0f 100644 --- a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs +++ b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs @@ -15,7 +15,7 @@ use bevy_render::{ renderer::RenderDevice, texture::BevyDefault, view::{ExtractedView, ViewTarget}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; mod node; diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index d3d12130b393f..d8b52773b8691 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -22,7 +22,7 @@ pub const CORE_2D: &str = graph::NAME; pub use camera_2d::*; pub use main_pass_2d_node::*; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_ecs::prelude::*; use bevy_render::{ camera::Camera, @@ -33,7 +33,7 @@ use bevy_render::{ DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase, }, render_resource::CachedRenderPipelineId, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_utils::FloatOrd; use std::ops::Range; diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 29e7157165d13..c280f92b85f37 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -30,7 +30,7 @@ pub use camera_3d::*; pub use main_opaque_pass_3d_node::*; pub use main_transparent_pass_3d_node::*; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_ecs::prelude::*; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -48,7 +48,7 @@ use bevy_render::{ renderer::RenderDevice, texture::TextureCache, view::ViewDepthTexture, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_utils::{FloatOrd, HashMap}; diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index e153a77b623b0..c90ec78aa7278 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -19,7 +19,7 @@ use bevy_render::{ renderer::RenderDevice, texture::BevyDefault, view::{ExtractedView, ViewTarget}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; mod node; diff --git a/crates/bevy_core_pipeline/src/msaa_writeback.rs b/crates/bevy_core_pipeline/src/msaa_writeback.rs index cf881b07b608e..1bf23b9b0a411 100644 --- a/crates/bevy_core_pipeline/src/msaa_writeback.rs +++ b/crates/bevy_core_pipeline/src/msaa_writeback.rs @@ -3,14 +3,14 @@ use crate::{ core_2d::{self, CORE_2D}, core_3d::{self, CORE_3D}, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_ecs::prelude::*; use bevy_render::{ camera::ExtractedCamera, render_graph::{Node, NodeRunError, RenderGraphApp, RenderGraphContext}, renderer::RenderContext, view::{Msaa, ViewTarget}, - Render, RenderSet, + RenderSet, }; use bevy_render::{render_resource::*, RenderApp}; diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index ccf21334aa10a..0354630d996f3 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_ecs::{ prelude::{Component, Entity}, @@ -22,7 +22,7 @@ use bevy_render::{ renderer::RenderDevice, texture::{BevyDefault, Image}, view::{ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniforms}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; const SKYBOX_SHADER_HANDLE: HandleUntyped = diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 746f22ded9d66..dfb9417d76fd4 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -4,7 +4,7 @@ use crate::{ prelude::Camera3d, prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures}, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_core::FrameCount; use bevy_ecs::{ @@ -32,7 +32,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice}, texture::{BevyDefault, CachedTexture, TextureCache}, view::{prepare_view_uniforms, ExtractedView, Msaa, ViewTarget}, - ExtractSchedule, MainWorld, Render, RenderApp, RenderSet, + ExtractSchedule, MainWorld, RenderApp, RenderSet, }; mod draw_3d_graph { diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index 0896c37f3ec9b..d1720cb27989b 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -10,7 +10,7 @@ use bevy_render::render_asset::RenderAssets; use bevy_render::renderer::RenderDevice; use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType}; use bevy_render::view::{ViewTarget, ViewUniform}; -use bevy_render::{render_resource::*, Render, RenderApp, RenderSet}; +use bevy_render::{render_resource::*, RenderApp, RenderSet}; mod node; diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index f3594397d5120..acbb8476b3dc8 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -3,7 +3,7 @@ use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_render::camera::{CameraOutputMode, ExtractedCamera}; use bevy_render::view::ViewTarget; -use bevy_render::{render_resource::*, Render, RenderApp, RenderSet}; +use bevy_render::{render_resource::*, RenderApp, RenderSet}; mod node; diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 23c53c895d719..52d6ab6b0c4a8 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -18,7 +18,7 @@ use std::mem; -use bevy_app::{Last, Plugin, Update}; +use bevy_app::{Last, Plugin, Render, Update}; use bevy_asset::{load_internal_asset, AddAsset, Assets, Handle, HandleUntyped}; use bevy_core::cast_slice; use bevy_ecs::{ @@ -49,7 +49,7 @@ use bevy_render::{ VertexFormat, VertexStepMode, }, renderer::RenderDevice, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::components::{GlobalTransform, Transform}; diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 5e903b8e305da..99e9a341066ac 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -2,7 +2,7 @@ use crate::{ line_gizmo_vertex_buffer_layouts, DrawLineGizmo, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::Handle; use bevy_core_pipeline::core_2d::Transparent2d; @@ -18,7 +18,7 @@ use bevy_render::{ render_resource::*, texture::BevyDefault, view::{ExtractedView, Msaa, ViewTarget}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; use bevy_sprite::{Mesh2dPipeline, Mesh2dPipelineKey, SetMesh2dViewBindGroup}; use bevy_utils::FloatOrd; diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index bfd1ed1a4cd2f..6b536b8027e4b 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -2,7 +2,7 @@ use crate::{ line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::Handle; use bevy_core_pipeline::core_3d::Transparent3d; @@ -22,7 +22,7 @@ use bevy_render::{ render_resource::*, texture::BevyDefault, view::{ExtractedView, Msaa, ViewTarget}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; pub struct LineGizmo3dPlugin; diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 2460a0e0f67df..c56ab6f2bd58d 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -63,7 +63,7 @@ use bevy_render::{ render_phase::sort_phase_system, render_resource::Shader, view::{ViewSet, VisibilitySystems}, - ExtractSchedule, Render, RenderApp, RenderSet, + ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::TransformSystem; use environment_map::EnvironmentMapPlugin; diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index ec9e4364b9521..c9a5c9af171d8 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -3,7 +3,7 @@ use crate::{ MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, ScreenSpaceAmbientOcclusionSettings, SetMeshBindGroup, SetMeshViewBindGroup, Shadow, }; -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; use bevy_core_pipeline::{ core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, @@ -37,7 +37,7 @@ use bevy_render::{ renderer::RenderDevice, texture::FallbackImage, view::{ExtractedView, Msaa, VisibleEntities}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_utils::{tracing::error, HashMap, HashSet}; use std::hash::Hash; diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index af854b9c22860..b27d4eccc7704 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{Plugin, PreUpdate, Update}; +use bevy_app::{Plugin, PreUpdate, Render, Update}; use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped}; use bevy_core_pipeline::{ prelude::Camera3d, @@ -39,7 +39,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{FallbackImagesDepth, FallbackImagesMsaa}, view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::prelude::GlobalTransform; use bevy_utils::tracing::error; diff --git a/crates/bevy_pbr/src/render/fog.rs b/crates/bevy_pbr/src/render/fog.rs index 6c314ccd0495f..2fcba205e258c 100644 --- a/crates/bevy_pbr/src/render/fog.rs +++ b/crates/bevy_pbr/src/render/fog.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_ecs::prelude::*; use bevy_math::{Vec3, Vec4}; @@ -8,7 +8,7 @@ use bevy_render::{ render_resource::{DynamicUniformBuffer, Shader, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ExtractedView, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }; use crate::{FogFalloff, FogSettings}; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 26aeadb0517e5..3714e68e84e68 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -5,7 +5,7 @@ use crate::{ ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, }; -use bevy_app::Plugin; +use bevy_app::{Plugin, Render}; use bevy_asset::{load_internal_asset, Assets, Handle, HandleId, HandleUntyped}; use bevy_core_pipeline::{ prepass::ViewPrepassTextures, @@ -38,7 +38,7 @@ use bevy_render::{ FallbackImagesMsaa, GpuImage, Image, ImageSampler, TextureFormatPixelInfo, }, view::{ComputedVisibility, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::components::GlobalTransform; use bevy_utils::{tracing::error, HashMap, Hashed}; diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 276ee261a5e01..7d0c6af15adba 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_core_pipeline::{ core_3d::CORE_3D, @@ -33,7 +33,7 @@ use bevy_render::{ renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue}, texture::{CachedTexture, TextureCache}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_utils::{ prelude::default, diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index d3c8b3ba47509..4081e4c972577 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -1,13 +1,12 @@ use crate::MeshPipeline; use crate::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; -use bevy_app::Plugin; +use bevy_app::{Plugin, Render}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_core_pipeline::core_3d::Opaque3d; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect, TypeUuid}; use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin}; -use bevy_render::Render; use bevy_render::{ extract_resource::{ExtractResource, ExtractResourcePlugin}, mesh::{Mesh, MeshVertexBufferLayout}, diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index cb625bf49d9db..de977b24cadd1 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -55,7 +55,7 @@ use crate::{ settings::WgpuSettings, view::{ViewPlugin, WindowRenderPlugin}, }; -use bevy_app::{App, AppLabel, Plugin, SubApp}; +use bevy_app::{App, AppLabel, Plugin, Render, SubApp}; use bevy_asset::{AddAsset, AssetServer}; use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState}; use bevy_utils::tracing::debug; @@ -108,11 +108,7 @@ pub enum RenderSet { CleanupFlush, } -/// The main render schedule. -#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)] -pub struct Render; - -impl Render { +impl RenderSet { /// Sets up the base structure of the rendering [`Schedule`]. /// /// The sets defined in this enum are configured to run in order, @@ -273,7 +269,7 @@ impl Plugin for RenderPlugin { render_app .add_schedule(ExtractSchedule, extract_schedule) - .add_schedule(Render, Render::base_schedule()) + .add_schedule(Render, RenderSet::base_schedule()) .init_resource::() .insert_resource(app.world.resource::().clone()) .add_systems(ExtractSchedule, PipelineCache::extract_shaders) diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index c96d936b85bbe..b4f9acd73ca19 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -1,6 +1,6 @@ use async_channel::{Receiver, Sender}; -use bevy_app::{App, AppLabel, Main, Plugin, SubApp}; +use bevy_app::{App, Plugin, Render, SubApp}; use bevy_ecs::{ schedule::MainThreadExecutor, system::Resource, diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index fd63b19579cbd..e2ba3218900b2 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -40,7 +40,7 @@ use bevy_render::{ render_resource::{Shader, SpecializedRenderPipelines}, texture::Image, view::{NoFrustumCulling, VisibilitySystems}, - ExtractSchedule, Render, RenderApp, RenderSet, + ExtractSchedule, RenderApp, RenderSet, }; #[derive(Default)] diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 2ba6765e720df..75774eca852dc 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin}; +use bevy_app::{App, Plugin, Render}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; use bevy_core_pipeline::{ core_2d::Transparent2d, @@ -32,7 +32,7 @@ use bevy_render::{ renderer::RenderDevice, texture::FallbackImage, view::{ComputedVisibility, ExtractedView, Msaa, Visibility, VisibleEntities}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::{FloatOrd, HashMap, HashSet}; diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 137f412c38473..2cb1ea2d6478a 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -1,4 +1,4 @@ -use bevy_app::Plugin; +use bevy_app::{Plugin, Render}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_ecs::{ @@ -22,7 +22,7 @@ use bevy_render::{ view::{ ComputedVisibility, ExtractedView, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, }, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderSet, }; use bevy_transform::components::GlobalTransform; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 66fa5e15be7be..d7acdd5d75bb5 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -3,7 +3,7 @@ mod render_pass; use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; -use bevy_render::{ExtractSchedule, Render}; +use bevy_render::ExtractSchedule; use bevy_window::{PrimaryWindow, Window}; pub use pipeline::*; pub use render_pass::*; diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index ac4db6d29fb74..15f9254a5ad87 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -24,7 +24,7 @@ use system::{changed_window, create_window, despawn_window, CachedWindow}; pub use winit_config::*; pub use winit_windows::*; -use bevy_app::{App, AppExit, Last, Plugin}; +use bevy_app::{App, AppExit, Last, Main, Plugin, Render}; use bevy_ecs::event::{Events, ManualEventReader}; use bevy_ecs::prelude::*; use bevy_input::{ diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index 942d603483936..accf7bc6a77d1 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -21,7 +21,7 @@ use bevy::{ }, texture::BevyDefault, view::{ExtractedView, ViewTarget, VisibleEntities}, - Extract, Render, RenderApp, RenderSet, + Extract, RenderApp, RenderSet, }, sprite::{ DrawMesh2d, Mesh2dHandle, Mesh2dPipeline, Mesh2dPipelineKey, Mesh2dUniform, diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index d737fb029c339..9d83ec1dbe00f 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -11,7 +11,7 @@ use bevy::{ render_graph::{self, RenderGraph}, render_resource::*, renderer::{RenderContext, RenderDevice}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }, window::WindowPlugin, }; diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index a1cbde6d1825a..e355ba47b522e 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -19,7 +19,7 @@ use bevy::{ render_resource::*, renderer::RenderDevice, view::{ExtractedView, NoFrustumCulling}, - Render, RenderApp, RenderSet, + RenderApp, RenderSet, }, }; use bytemuck::{Pod, Zeroable}; diff --git a/examples/stress_tests/many_lights.rs b/examples/stress_tests/many_lights.rs index 66fe81ef43834..dd0733e750784 100644 --- a/examples/stress_tests/many_lights.rs +++ b/examples/stress_tests/many_lights.rs @@ -8,7 +8,7 @@ use bevy::{ math::{DVec2, DVec3}, pbr::{ExtractedPointLight, GlobalLightMeta}, prelude::*, - render::{camera::ScalingMode, Render, RenderApp, RenderSet}, + render::{camera::ScalingMode, RenderApp, RenderSet}, window::{PresentMode, WindowPlugin}, }; use rand::{thread_rng, Rng}; From e10458b73e6f928fb0cd15df97283ecca09c9ee4 Mon Sep 17 00:00:00 2001 From: B_head Date: Sun, 25 Jun 2023 20:09:45 +0900 Subject: [PATCH 03/13] Implement `Sync` to `App` Want to include `SubApp` in a system function, but `ExclusiveFunctionSystem` requires `Sync`. --- crates/bevy_app/src/app.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 62e1dbea1c3d8..6cf2df68eacc2 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -64,7 +64,7 @@ pub struct App { /// the application's event loop and advancing the [`Schedule`]. /// Typically, it is not configured manually, but set by one of Bevy's built-in plugins. /// See `bevy::winit::WinitPlugin` and [`ScheduleRunnerPlugin`](crate::schedule_runner::ScheduleRunnerPlugin). - pub runner: Box, // Send bound is required to make App Send + pub runner: Box, /// The schedule that systems are added to by default. /// /// The schedule that runs the main loop of schedule execution. @@ -137,7 +137,7 @@ pub struct SubApp { /// A function that allows access to both the main [`App`] [`World`] and the [`SubApp`]. This is /// useful for moving data between the sub app and the main app. - extract: Box, + extract: Box, } impl SubApp { @@ -147,7 +147,7 @@ impl SubApp { /// After extract is called, the [`Schedule`] of the sub app is run. The [`World`] /// parameter represents the main app world, while the [`App`] parameter is just a mutable /// reference to the `SubApp` itself. - pub fn new(app: App, extract: impl Fn(&mut World, &mut App) + Send + 'static) -> Self { + pub fn new(app: App, extract: impl Fn(&mut World, &mut App) + Send + Sync + 'static) -> Self { Self { app, extract: Box::new(extract), @@ -651,7 +651,7 @@ impl App { /// App::new() /// .set_runner(my_runner); /// ``` - pub fn set_runner(&mut self, run_fn: impl FnOnce(App) + 'static + Send) -> &mut Self { + pub fn set_runner(&mut self, run_fn: impl FnOnce(App) + 'static + Send + Sync) -> &mut Self { self.runner = Box::new(run_fn); self } From f210beda5f30fdbef0bc998e9cc0c888e1737971 Mon Sep 17 00:00:00 2001 From: B_head Date: Mon, 26 Jun 2023 07:41:11 +0900 Subject: [PATCH 04/13] Move render runs from `update()` to `Schedule` --- crates/bevy_render/src/lib.rs | 30 ++++++++++++++++++- crates/bevy_render/src/pipelined_rendering.rs | 23 ++++---------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index de977b24cadd1..8df96b7292259 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -57,7 +57,11 @@ use crate::{ }; use bevy_app::{App, AppLabel, Plugin, Render, SubApp}; use bevy_asset::{AddAsset, AssetServer}; -use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState}; +use bevy_ecs::{ + prelude::*, + schedule::{MainThreadExecutor, ScheduleLabel}, + system::SystemState, +}; use bevy_utils::tracing::debug; use std::{ ops::{Deref, DerefMut}, @@ -372,6 +376,30 @@ impl Plugin for RenderPlugin { .insert_resource(adapter_info); } } + + fn cleanup(&self, app: &mut App) { + // skip setting up when No backend is used + if self.wgpu_settings.backends.is_none() { + return; + } + + // skip setting up when using PipelinedRenderingPlugin + if app.world.get_resource::().is_some() { + return; + }; + + let mut render_app = app + .remove_sub_app(RenderApp) + .expect("Unable to get RenderApp. Another plugin may have removed the RenderApp before RenderPlugin"); + + app.add_systems(Render, move |world: &mut World| { + #[cfg(feature = "trace")] + let _sub_app_span = + bevy_utils::tracing::info_span!("sub app", name = ?RenderApp).entered(); + render_app.extract(world); + render_app.run(); + }); + } } /// A "scratch" world used to avoid allocating new worlds every frame when diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index b4f9acd73ca19..b604a03f0ac28 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -10,13 +10,6 @@ use bevy_tasks::ComputeTaskPool; use crate::RenderApp; -/// A Label for the sub app that runs the parts of pipelined rendering that need to run on the main thread. -/// -/// The Main schedule of this app can be used to run logic after the render schedule starts, but -/// before I/O processing. This can be useful for something like frame pacing. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)] -pub struct RenderExtractApp; - /// Channel to send the render app from the main thread to the rendering thread #[derive(Resource)] pub struct MainToRenderAppSender(pub Sender); @@ -70,18 +63,15 @@ impl Plugin for PipelinedRenderingPlugin { return; } app.insert_resource(MainThreadExecutor::new()); - - let mut sub_app = App::empty(); - sub_app.init_schedule(Main); - app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app, update_rendering)); } // Sets up the render thread and inserts resources into the main app used for controlling the render thread. fn cleanup(&self, app: &mut App) { // skip setting up when headless - if app.get_sub_app(RenderExtractApp).is_err() { + // clone main thread executor to render world + let Some(executor) = app.world.get_resource::().cloned() else { return; - } + }; let (app_to_render_sender, app_to_render_receiver) = async_channel::bounded::(1); let (render_to_app_sender, render_to_app_receiver) = async_channel::bounded::(1); @@ -90,14 +80,13 @@ impl Plugin for PipelinedRenderingPlugin { .remove_sub_app(RenderApp) .expect("Unable to get RenderApp. Another plugin may have removed the RenderApp before PipelinedRenderingPlugin"); - // clone main thread executor to render world - let executor = app.world.get_resource::().unwrap(); - render_app.app.world.insert_resource(executor.clone()); + render_app.app.world.insert_resource(executor); render_to_app_sender.send_blocking(render_app).unwrap(); app.insert_resource(MainToRenderAppSender(app_to_render_sender)); app.insert_resource(RenderToMainAppReceiver(render_to_app_receiver)); + app.add_systems(Render, update_rendering); std::thread::spawn(move || { #[cfg(feature = "trace")] @@ -124,7 +113,7 @@ impl Plugin for PipelinedRenderingPlugin { // This function waits for the rendering world to be received, // runs extract, and then sends the rendering world back to the render thread. -fn update_rendering(app_world: &mut World, _sub_app: &mut App) { +fn update_rendering(app_world: &mut World) { app_world.resource_scope(|world, main_thread_executor: Mut| { // we use a scope here to run any main thread tasks that the render world still needs to run // while we wait for the render world to be received. From 91bb64daf22128cca5620469403aa638e4eea36e Mon Sep 17 00:00:00 2001 From: B_head Date: Tue, 27 Jun 2023 06:58:13 +0900 Subject: [PATCH 05/13] Replace `App::update()` to `World::run_schedule()` Moved the responsibility for running top-level schedules from `App` struct to the runner function. --- .../benches/bevy_ecs/scheduling/schedule.rs | 4 +- crates/bevy_app/src/app.rs | 64 +++++++++---------- crates/bevy_app/src/main_schedule.rs | 2 +- crates/bevy_app/src/schedule_runner.rs | 46 +++++++++++-- crates/bevy_asset/src/asset_server.rs | 10 +-- crates/bevy_asset/src/debug_asset_server.rs | 4 +- crates/bevy_core/src/lib.rs | 2 +- crates/bevy_render/src/lib.rs | 13 ++-- crates/bevy_render/src/pipelined_rendering.rs | 2 - crates/bevy_render/src/view/visibility/mod.rs | 4 +- crates/bevy_transform/src/systems.rs | 6 +- crates/bevy_winit/src/lib.rs | 35 +++++++++- crates/bevy_winit/src/winit_config.rs | 13 +++- examples/app/custom_loop.rs | 2 +- tests/how_to_test_systems.rs | 10 +-- 15 files changed, 145 insertions(+), 72 deletions(-) diff --git a/benches/benches/bevy_ecs/scheduling/schedule.rs b/benches/benches/bevy_ecs/scheduling/schedule.rs index e670c23d74b37..1e8b01aae4576 100644 --- a/benches/benches/bevy_ecs/scheduling/schedule.rs +++ b/benches/benches/bevy_ecs/scheduling/schedule.rs @@ -85,7 +85,7 @@ pub fn build_schedule(criterion: &mut Criterion) { for _ in 0..graph_size { app.add_systems(Update, empty_system); } - app.update(); + app.world.run_schedule(Update); }); }); @@ -111,7 +111,7 @@ pub fn build_schedule(criterion: &mut Criterion) { // This is necessary since dependency resolution does not occur until the game runs. // FIXME: Running the game clutters up the benchmarks, so ideally we'd be // able to benchmark the dependency resolution directly. - app.update(); + app.world.run_schedule(Update); }); }); } diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 6cf2df68eacc2..2da273c8d5bc2 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -64,13 +64,12 @@ pub struct App { /// the application's event loop and advancing the [`Schedule`]. /// Typically, it is not configured manually, but set by one of Bevy's built-in plugins. /// See `bevy::winit::WinitPlugin` and [`ScheduleRunnerPlugin`](crate::schedule_runner::ScheduleRunnerPlugin). - pub runner: Box, - /// The schedule that systems are added to by default. /// - /// The schedule that runs the main loop of schedule execution. + /// # Note /// - /// This is initially set to [`Main`]. - pub main_schedule_label: BoxedScheduleLabel, + /// Inside the runner function, `World::clear_trackers()` must be called periodically. + /// If that isn't called on a world, it may lead to memory leaks in `RemovedComponents`. + pub runner: Box, sub_apps: HashMap, plugin_registry: Vec>, plugin_name_added: HashSet, @@ -135,6 +134,11 @@ pub struct SubApp { /// The [`SubApp`]'s instance of [`App`] pub app: App, + /// The schedule to run by default. + /// + /// This is initially set to [`Main`]. + pub main_schedule_label: BoxedScheduleLabel, + /// A function that allows access to both the main [`App`] [`World`] and the [`SubApp`]. This is /// useful for moving data between the sub app and the main app. extract: Box, @@ -143,20 +147,21 @@ pub struct SubApp { impl SubApp { /// Creates a new [`SubApp`]. /// - /// The provided function `extract` is normally called by the [`update`](App::update) method. + /// The provided function `extract` is normally called by the [`run_schedule`](World::run_schedule) method. /// After extract is called, the [`Schedule`] of the sub app is run. The [`World`] /// parameter represents the main app world, while the [`App`] parameter is just a mutable /// reference to the `SubApp` itself. pub fn new(app: App, extract: impl Fn(&mut World, &mut App) + Send + Sync + 'static) -> Self { Self { app, + main_schedule_label: Box::new(Main), extract: Box::new(extract), } } /// Runs the [`SubApp`]'s default schedule. pub fn run(&mut self) { - self.app.world.run_schedule(&*self.app.main_schedule_label); + self.app.world.run_schedule(&*self.main_schedule_label); self.app.world.clear_trackers(); } @@ -219,38 +224,19 @@ impl App { sub_apps: HashMap::default(), plugin_registry: Vec::default(), plugin_name_added: Default::default(), - main_schedule_label: Box::new(Main), building_plugin_depth: 0, } } - /// Advances the execution of the [`Schedule`] by one cycle. - /// - /// This method also updates sub apps. + /// Update sub apps. /// See [`insert_sub_app`](Self::insert_sub_app) for more details. - /// - /// The schedule run by this method is determined by the [`main_schedule_label`](App) field. - /// By default this is [`Main`]. - /// - /// # Panics - /// - /// The active schedule of the app must be set before this method is called. - pub fn update(&mut self) { - #[cfg(feature = "trace")] - let _bevy_update_span = info_span!("update").entered(); - { - #[cfg(feature = "trace")] - let _bevy_main_update_span = info_span!("main app").entered(); - self.world.run_schedule(&*self.main_schedule_label); - } + pub fn update_sub_apps(&mut self) { for (_label, sub_app) in self.sub_apps.iter_mut() { #[cfg(feature = "trace")] let _sub_app_span = info_span!("sub app", name = ?_label).entered(); sub_app.extract(&mut self.world); sub_app.run(); } - - self.world.clear_trackers(); } /// Starts the application by calling the app's [runner function](Self::set_runner). @@ -293,7 +279,7 @@ impl App { } /// Check that [`Plugin::ready`] of all plugins returns true. This is usually called by the - /// event loop, but can be useful for situations where you want to use [`App::update`] + /// event loop, but can be useful for situations where you want to no use [`App::run`] pub fn ready(&self) -> bool { for plugin in &self.plugin_registry { if !plugin.ready(self) { @@ -304,8 +290,8 @@ impl App { } /// Run [`Plugin::finish`] for each plugin. This is usually called by the event loop once all - /// plugins are [`App::ready`], but can be useful for situations where you want to use - /// [`App::update`]. + /// plugins are [`App::ready`], but can be useful for situations where you want to no use + /// [`App::run`]. pub fn finish(&mut self) { // temporarily remove the plugin registry to run each plugin's setup function on app. let plugin_registry = std::mem::take(&mut self.plugin_registry); @@ -316,7 +302,7 @@ impl App { } /// Run [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after - /// [`App::finish`], but can be useful for situations where you want to use [`App::update`]. + /// [`App::finish`], but can be useful for situations where you want to no use [`App::run`]. pub fn cleanup(&mut self) { // temporarily remove the plugin registry to run each plugin's setup function on app. let plugin_registry = std::mem::take(&mut self.plugin_registry); @@ -636,6 +622,11 @@ impl App { /// The runner function is usually not set manually, but by Bevy integrated plugins /// (e.g. `WinitPlugin`). /// + /// # Note + /// + /// Inside the runner function, `World::clear_trackers()` must be called periodically. + /// If that isn't called on a world, it may lead to memory leaks in `RemovedComponents`. + /// /// # Examples /// /// ``` @@ -644,7 +635,7 @@ impl App { /// fn my_runner(mut app: App) { /// loop { /// println!("In main loop"); - /// app.update(); + /// app.world.run_schedule(Main); /// } /// } /// @@ -970,7 +961,12 @@ fn run_once(mut app: App) { app.finish(); app.cleanup(); - app.update(); + { + #[cfg(feature = "trace")] + let _main_schedule_span = info_span!("main schedule", name = ?Main).entered(); + app.world.run_schedule(Main); + } + app.update_sub_apps(); } /// An event that indicates the [`App`] should exit. This will fully exit the app process at the diff --git a/crates/bevy_app/src/main_schedule.rs b/crates/bevy_app/src/main_schedule.rs index 2ef4336f74e87..06e9e3184c3d6 100644 --- a/crates/bevy_app/src/main_schedule.rs +++ b/crates/bevy_app/src/main_schedule.rs @@ -5,7 +5,7 @@ use bevy_ecs::{ world::{Mut, World}, }; -/// The schedule that contains the app logic that is evaluated each tick of [`App::update()`]. +/// The schedule that contains the app logic that is evaluated each tick of event loop. /// /// By default, it will run the following schedules in the given order: /// diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index c143f75c42f53..0faabde8b77de 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -1,10 +1,17 @@ use crate::{ app::{App, AppExit}, plugin::Plugin, + Main, +}; +use bevy_ecs::{ + event::{Events, ManualEventReader}, + schedule::BoxedScheduleLabel, }; -use bevy_ecs::event::{Events, ManualEventReader}; use bevy_utils::{Duration, Instant}; +#[cfg(feature = "trace")] +use bevy_utils::tracing::info_span; + #[cfg(target_arch = "wasm32")] use std::{cell::RefCell, rc::Rc}; #[cfg(target_arch = "wasm32")] @@ -43,10 +50,13 @@ impl Default for RunMode { /// typically, the `winit` event loop /// (see [`WinitPlugin`](https://docs.rs/bevy/latest/bevy/winit/struct.WinitPlugin.html)) /// executes the schedule making [`ScheduleRunnerPlugin`] unnecessary. -#[derive(Default)] pub struct ScheduleRunnerPlugin { /// Determines whether the [`Schedule`](bevy_ecs::schedule::Schedule) is run once or repeatedly. pub run_mode: RunMode, + /// The schedule to run by default. + /// + /// This is initially set to [`Main`]. + pub main_schedule_label: BoxedScheduleLabel, } impl ScheduleRunnerPlugin { @@ -54,6 +64,7 @@ impl ScheduleRunnerPlugin { pub fn run_once() -> Self { ScheduleRunnerPlugin { run_mode: RunMode::Once, + main_schedule_label: Box::new(Main), } } @@ -63,6 +74,16 @@ impl ScheduleRunnerPlugin { run_mode: RunMode::Loop { wait: Some(wait_duration), }, + main_schedule_label: Box::new(Main), + } + } +} + +impl Default for ScheduleRunnerPlugin { + fn default() -> Self { + ScheduleRunnerPlugin { + run_mode: RunMode::Loop { wait: None }, + main_schedule_label: Box::new(Main), } } } @@ -70,11 +91,21 @@ impl ScheduleRunnerPlugin { impl Plugin for ScheduleRunnerPlugin { fn build(&self, app: &mut App) { let run_mode = self.run_mode; + let main_schedule_label = self.main_schedule_label.clone(); app.set_runner(move |mut app: App| { + // Prevent panic when schedules do not exist + app.init_schedule(main_schedule_label.clone()); + let mut app_exit_event_reader = ManualEventReader::::default(); match run_mode { RunMode::Once => { - app.update(); + { + #[cfg(feature = "trace")] + let _main_schedule_span = + info_span!("main schedule", name = ?main_schedule_label).entered(); + app.world.run_schedule(main_schedule_label); + } + app.update_sub_apps(); } RunMode::Loop { wait } => { let mut tick = move |app: &mut App, @@ -91,7 +122,14 @@ impl Plugin for ScheduleRunnerPlugin { } } - app.update(); + { + #[cfg(feature = "trace")] + let _main_schedule_span = + info_span!("main schedule", name = ?main_schedule_label).entered(); + app.world.run_schedule(&main_schedule_label); + } + app.update_sub_apps(); + app.world.clear_trackers(); if let Some(app_exit_events) = app.world.get_resource_mut::>() diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index d97f206bbdc36..12b843424c68a 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -645,7 +645,7 @@ pub fn free_unused_assets_system(asset_server: Res) { mod test { use super::*; use crate::{loader::LoadedAsset, update_asset_storage_system}; - use bevy_app::{App, Update}; + use bevy_app::{App, Main, Update}; use bevy_ecs::prelude::*; use bevy_reflect::{TypePath, TypeUuid}; use bevy_utils::BoxedFuture; @@ -896,19 +896,19 @@ mod test { // asset is loading assert_eq!(LoadState::Loading, get_load_state(&handle, &app.world)); - app.update(); + app.world.run_schedule(Main); // asset should exist and be loaded at this point assert_eq!(LoadState::Loaded, get_load_state(&handle, &app.world)); assert!(get_asset(&handle, &app.world).is_some()); // after dropping the handle, next call to `tick` will prepare the assets for removal. drop(handle); - app.update(); + app.world.run_schedule(Main); assert_eq!(LoadState::Loaded, get_load_state(&weak_handle, &app.world)); assert!(get_asset(&weak_handle, &app.world).is_some()); // second call to tick will actually remove the asset. - app.update(); + app.world.run_schedule(Main); assert_eq!( LoadState::Unloaded, get_load_state(&weak_handle, &app.world) @@ -918,7 +918,7 @@ mod test { // finally, reload the asset let handle = load_asset(path.clone(), &app.world).typed(); assert_eq!(LoadState::Loading, get_load_state(&handle, &app.world)); - app.update(); + app.world.run_schedule(Main); assert_eq!(LoadState::Loaded, get_load_state(&handle, &app.world)); assert!(get_asset(&handle, &app.world).is_some()); } diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index 6c2e3d4815102..94330b7192ccb 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -2,7 +2,7 @@ //! //! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot //! reloaded using the conventional API. -use bevy_app::{App, Plugin, Update}; +use bevy_app::{App, Main, Plugin, Update}; use bevy_ecs::{prelude::*, system::SystemState}; use bevy_tasks::{IoTaskPool, TaskPoolBuilder}; use bevy_utils::{Duration, HashMap}; @@ -81,7 +81,7 @@ impl Plugin for DebugAssetServerPlugin { } fn run_debug_asset_app(mut debug_asset_app: NonSendMut) { - debug_asset_app.0.update(); + debug_asset_app.0.world.run_schedule(Main); } pub(crate) fn sync_debug_assets( diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index a9b10b1e81f2b..709a0173e59a1 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -203,7 +203,7 @@ mod tests { TypeRegistrationPlugin::default(), FrameCountPlugin::default(), )); - app.update(); + app.world.run_schedule(Main); let frame_count = app.world.resource::(); assert_eq!(1, frame_count.0); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 8df96b7292259..e2e39c248edd6 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -266,7 +266,6 @@ impl Plugin for RenderPlugin { app.init_resource::(); let mut render_app = App::empty(); - render_app.main_schedule_label = Box::new(Render); let mut extract_schedule = Schedule::new(); extract_schedule.set_apply_final_deferred(false); @@ -296,14 +295,14 @@ impl Plugin for RenderPlugin { app.insert_resource(receiver); render_app.insert_resource(sender); - app.insert_sub_app(RenderApp, SubApp::new(render_app, move |main_world, render_app| { + let mut sub_app = SubApp::new(render_app, move |main_world, render_app| { #[cfg(feature = "trace")] - let _render_span = bevy_utils::tracing::info_span!("extract main app to render subapp").entered(); + let _render_span = + bevy_utils::tracing::info_span!("extract main app to render subapp").entered(); { #[cfg(feature = "trace")] let _stage_span = - bevy_utils::tracing::info_span!("reserve_and_flush") - .entered(); + bevy_utils::tracing::info_span!("reserve_and_flush").entered(); // reserve all existing main world entities for use in render_app // they can only be spawned using `get_or_spawn()` @@ -326,7 +325,9 @@ impl Plugin for RenderPlugin { // run extract schedule extract(main_world, render_app); - })); + }); + sub_app.main_schedule_label = Box::new(Render); + app.insert_sub_app(RenderApp, sub_app); } app.add_plugins(( diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index b604a03f0ac28..8767938464bba 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -48,8 +48,6 @@ pub struct RenderToMainAppReceiver(pub Receiver); /// - On the render thread, we first apply the `extract commands`. This is not run during extract, so the /// main schedule can start sooner. /// - Then the `rendering schedule` is run. See [`RenderSet`](crate::RenderSet) for the standard steps in this process. -/// - In parallel to the rendering thread the [`RenderExtractApp`] schedule runs. By -/// default this schedule is empty. But it is useful if you need something to run before I/O processing. /// - Next all the `winit events` are processed. /// - And finally the `main app schedule` is run. /// - Once both the `main app schedule` and the `render schedule` are finished running, `extract` is run again. diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 4c72a5abb5f05..b28c84c775841 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -516,7 +516,7 @@ mod test { .entity_mut(root2_child2) .push_children(&[root2_child2_grandchild1]); - app.update(); + app.world.run_schedule(Main); let is_visible = |e: Entity| { app.world @@ -613,7 +613,7 @@ mod test { .entity_mut(root1_child2) .push_children(&[root1_child2_grandchild1]); - app.update(); + app.world.run_schedule(Main); let is_visible = |e: Entity| { app.world diff --git a/crates/bevy_transform/src/systems.rs b/crates/bevy_transform/src/systems.rs index 46629eca57db9..ca9a9edb913a6 100644 --- a/crates/bevy_transform/src/systems.rs +++ b/crates/bevy_transform/src/systems.rs @@ -424,13 +424,13 @@ mod test { }) .id(); - app.update(); + app.world.run_schedule(Main); // check the `Children` structure is spawned assert_eq!(&**app.world.get::(parent).unwrap(), &[child]); assert_eq!(&**app.world.get::(child).unwrap(), &[grandchild]); // Note that at this point, the `GlobalTransform`s will not have updated yet, due to `Commands` delay - app.update(); + app.world.run_schedule(Main); let mut state = app.world.query::<&GlobalTransform>(); for global in state.iter(&app.world) { @@ -474,6 +474,6 @@ mod test { &mut *temp.get_mut::(grandchild).unwrap(), ); - app.update(); + app.world.run_schedule(Main); } } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 15f9254a5ad87..82f182d952eb7 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -24,7 +24,7 @@ use system::{changed_window, create_window, despawn_window, CachedWindow}; pub use winit_config::*; pub use winit_windows::*; -use bevy_app::{App, AppExit, Last, Main, Plugin, Render}; +use bevy_app::{App, AppExit, Last, Plugin}; use bevy_ecs::event::{Events, ManualEventReader}; use bevy_ecs::prelude::*; use bevy_input::{ @@ -45,6 +45,9 @@ use bevy_window::{ WindowScaleFactorChanged, WindowThemeChanged, }; +#[cfg(feature = "trace")] +use bevy_utils::tracing::info_span; + #[cfg(target_os = "android")] pub use winit::platform::android::activity::AndroidApp; @@ -335,6 +338,16 @@ pub fn winit_runner(mut app: App) { ResMut, )> = SystemState::from_world(&mut app.world); + { + let (winit_config, _) = focused_window_state.get(&app.world); + let main_schedule_label = winit_config.main_schedule_label.clone(); + let render_schedule_label = winit_config.render_schedule_label.clone(); + + // Prevent panic when schedules do not exist + app.init_schedule(main_schedule_label); + app.init_schedule(render_schedule_label); + } + let mut finished_and_setup_done = false; let event_handler = move |event: Event<()>, @@ -690,7 +703,23 @@ pub fn winit_runner(mut app: App) { if update && finished_and_setup_done { winit_state.last_update = Instant::now(); - app.update(); + let main_schedule_label = winit_config.main_schedule_label.clone(); + let render_schedule_label = winit_config.render_schedule_label.clone(); + + { + #[cfg(feature = "trace")] + let _main_schedule_span = + info_span!("main schedule", name = ?main_schedule_label).entered(); + app.world.run_schedule(main_schedule_label); + } + { + #[cfg(feature = "trace")] + let _render_schedule_span = + info_span!("render schedule", name = ?render_schedule_label).entered(); + app.world.run_schedule(render_schedule_label); + } + app.update_sub_apps(); + app.world.clear_trackers(); } } Event::RedrawEventsCleared => { @@ -715,7 +744,7 @@ pub fn winit_runner(mut app: App) { }; } - // This block needs to run after `app.update()` in `MainEventsCleared`. Otherwise, + // This block needs to run after `app.world.run_schedule` in `MainEventsCleared`. Otherwise, // we won't be able to see redraw requests until the next event, defeating the // purpose of a redraw request! let mut redraw = false; diff --git a/crates/bevy_winit/src/winit_config.rs b/crates/bevy_winit/src/winit_config.rs index ec2ff83127488..cae89efa981df 100644 --- a/crates/bevy_winit/src/winit_config.rs +++ b/crates/bevy_winit/src/winit_config.rs @@ -1,4 +1,5 @@ -use bevy_ecs::system::Resource; +use bevy_app::{Main, Render}; +use bevy_ecs::{schedule::BoxedScheduleLabel, system::Resource}; use bevy_utils::Duration; /// A resource for configuring usage of the [`winit`] library. @@ -31,6 +32,14 @@ pub struct WinitSettings { pub focused_mode: UpdateMode, /// Configures how the winit event loop updates while the window is *not* focused. pub unfocused_mode: UpdateMode, + /// The main schedule to run by default. + /// + /// This is initially set to [`Main`]. + pub main_schedule_label: BoxedScheduleLabel, + /// The render schedule to run by default. + /// + /// This is initially set to [`Render`]. + pub render_schedule_label: BoxedScheduleLabel, } impl WinitSettings { /// Configure winit with common settings for a game. @@ -65,6 +74,8 @@ impl Default for WinitSettings { return_from_run: false, focused_mode: UpdateMode::Continuous, unfocused_mode: UpdateMode::Continuous, + main_schedule_label: Box::new(Main), + render_schedule_label: Box::new(Render), } } } diff --git a/examples/app/custom_loop.rs b/examples/app/custom_loop.rs index 17f70ae9f6d38..597befdd46c04 100644 --- a/examples/app/custom_loop.rs +++ b/examples/app/custom_loop.rs @@ -14,7 +14,7 @@ fn my_runner(mut app: App) { let mut input = app.world.resource_mut::(); input.0 = line.unwrap(); } - app.update(); + app.world.run_schedule(Main); } } diff --git a/tests/how_to_test_systems.rs b/tests/how_to_test_systems.rs index 192aff7cd2f39..3b65ac400b06e 100644 --- a/tests/how_to_test_systems.rs +++ b/tests/how_to_test_systems.rs @@ -70,7 +70,7 @@ fn did_hurt_enemy() { .id(); // Run systems - app.update(); + app.world.run_schedule(Main); // Check resulting changes assert!(app.world.get::(enemy_id).is_some()); @@ -101,7 +101,7 @@ fn did_despawn_enemy() { .id(); // Run systems - app.update(); + app.world.run_schedule(Main); // Check enemy was despawned assert!(app.world.get::(enemy_id).is_none()); @@ -129,7 +129,7 @@ fn spawn_enemy_using_input_resource() { app.insert_resource(input); // Run systems - app.update(); + app.world.run_schedule(Main); // Check resulting changes, one entity has been spawned with `Enemy` component assert_eq!(app.world.query::<&Enemy>().iter(&app.world).len(), 1); @@ -138,7 +138,7 @@ fn spawn_enemy_using_input_resource() { app.world.resource_mut::>().clear(); // Run systems - app.update(); + app.world.run_schedule(Main); // Check resulting changes, no new entity has been spawned assert_eq!(app.world.query::<&Enemy>().iter(&app.world).len(), 1); @@ -164,7 +164,7 @@ fn update_score_on_event() { .send(EnemyDied(3)); // Run systems - app.update(); + app.world.run_schedule(Main); // Check resulting changes assert_eq!(app.world.resource::().0, 3); From 28bcb95e3c8093480655295b21e71f467c586dd9 Mon Sep 17 00:00:00 2001 From: B_head Date: Mon, 3 Jul 2023 15:07:01 +0900 Subject: [PATCH 06/13] First aid bug fix --- crates/bevy_render/src/lib.rs | 6 +++--- crates/bevy_render/src/renderer/mod.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index e2e39c248edd6..d112e58294a48 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -291,9 +291,9 @@ impl Plugin for RenderPlugin { ), ); - let (sender, receiver) = bevy_time::create_time_channels(); - app.insert_resource(receiver); - render_app.insert_resource(sender); + // let (sender, receiver) = bevy_time::create_time_channels(); + // app.insert_resource(receiver); + // render_app.insert_resource(sender); let mut sub_app = SubApp::new(render_app, move |main_world, render_app| { #[cfg(feature = "trace")] diff --git a/crates/bevy_render/src/renderer/mod.rs b/crates/bevy_render/src/renderer/mod.rs index 6a9d9be6e162d..224fa9cfaaca2 100644 --- a/crates/bevy_render/src/renderer/mod.rs +++ b/crates/bevy_render/src/renderer/mod.rs @@ -14,8 +14,8 @@ use crate::{ view::{ExtractedWindows, ViewTarget}, }; use bevy_ecs::prelude::*; -use bevy_time::TimeSender; -use bevy_utils::Instant; +// use bevy_time::TimeSender; +// use bevy_utils::Instant; use std::sync::Arc; use wgpu::{ Adapter, AdapterInfo, CommandBuffer, CommandEncoder, Instance, Queue, RequestAdapterOptions, @@ -87,10 +87,10 @@ pub fn render_system(world: &mut World) { crate::view::screenshot::collect_screenshots(world); // update the time and send it to the app world - let time_sender = world.resource::(); - time_sender.0.try_send(Instant::now()).expect( - "The TimeSender channel should always be empty during render. You might need to add the bevy::core::time_system to your app.", - ); + // let time_sender = world.resource::(); + // time_sender.0.try_send(Instant::now()).expect( + // "The TimeSender channel should always be empty during render. You might need to add the bevy::core::time_system to your app.", + // ); } /// This queue is used to enqueue tasks for the GPU to execute asynchronously. From ede9e64578aeea8f485cb24b17408f513d8d5b0b Mon Sep 17 00:00:00 2001 From: B_head Date: Sat, 1 Jul 2023 13:31:30 +0900 Subject: [PATCH 07/13] Separate tick rate and frame rate Set `ControlFlow::WaitUntil` to the next tick update or redraw, whichever is closer. Prepare for changes in https://github.com/rust-windowing/winit/issues/2900. --- crates/bevy_winit/src/lib.rs | 331 +++++++++++++++----------- crates/bevy_winit/src/winit_config.rs | 135 +++++------ examples/window/low_power.rs | 9 +- 3 files changed, 256 insertions(+), 219 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 82f182d952eb7..02d3ca308046d 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -25,7 +25,7 @@ pub use winit_config::*; pub use winit_windows::*; use bevy_app::{App, AppExit, Last, Plugin}; -use bevy_ecs::event::{Events, ManualEventReader}; +use bevy_ecs::event::ManualEventReader; use bevy_ecs::prelude::*; use bevy_input::{ keyboard::KeyboardInput, @@ -35,12 +35,12 @@ use bevy_input::{ }; use bevy_math::{ivec2, DVec2, Vec2}; use bevy_utils::{ - tracing::{trace, warn}, - Instant, + tracing::{debug, warn}, + Duration, Instant, }; use bevy_window::{ exit_on_all_closed, CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, Ime, - ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged, + PrimaryWindow, ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged, WindowCloseRequested, WindowCreated, WindowFocused, WindowMoved, WindowResized, WindowScaleFactorChanged, WindowThemeChanged, }; @@ -62,6 +62,9 @@ use crate::converters::convert_winit_theme; #[cfg(target_arch = "wasm32")] use crate::web_resize::{CanvasParentResizeEventChannel, CanvasParentResizePlugin}; +// Does anyone know the safe value? +const FALLBACK_REFRESH_RATE: f64 = 30.; + /// [`AndroidApp`] provides an interface to query the application state as well as monitor events (for example lifecycle and input events) #[cfg(target_os = "android")] pub static ANDROID_APP: std::sync::OnceLock = std::sync::OnceLock::new(); @@ -266,28 +269,30 @@ struct CursorEvents<'w> { // winit_runner_with(app, EventLoop::new_any_thread()); // } -/// Stores state that must persist between frames. -struct WinitPersistentState { - /// Tracks whether or not the application is active or suspended. - active: bool, - /// Tracks whether or not an event has occurred this frame that would trigger an update in low - /// power mode. Should be reset at the end of every frame. - low_power_event: bool, - /// Tracks whether the event loop was started this frame because of a redraw request. - redraw_request_sent: bool, - /// Tracks if the event loop was started this frame because of a [`ControlFlow::WaitUntil`] - /// timeout. - timeout_reached: bool, - last_update: Instant, +enum TickMode { + Manual { + request_steps: u64, + }, + Periodic { + next_tick: Instant, + rate_multiplier: f64, + }, + Continuous, +} + +fn run_top_schedule(label: impl AsRef, world: &mut World) { + let label = label.as_ref(); + #[cfg(feature = "trace")] + let _ = info_span!("run top schedule", name = ?label).entered(); + world.run_schedule(label); } -impl Default for WinitPersistentState { - fn default() -> Self { - Self { - active: false, - low_power_event: false, - redraw_request_sent: false, - timeout_reached: false, - last_update: Instant::now(), + +fn update_next_time(next: &mut Instant, rate: f64, skip_would: Option) { + let interval = Duration::from_secs(1).div_f64(rate); + *next += interval; + if let Some(skip_would) = skip_would { + if *next <= skip_would { + *next = skip_would + interval; } } } @@ -301,19 +306,19 @@ pub fn winit_runner(mut app: App) { .world .remove_non_send_resource::>() .unwrap(); - - let mut app_exit_event_reader = ManualEventReader::::default(); - let mut redraw_event_reader = ManualEventReader::::default(); - let mut winit_state = WinitPersistentState::default(); app.world .insert_non_send_resource(event_loop.create_proxy()); - let return_from_run = app.world.resource::().return_from_run; + let mut app_exit_event_reader = ManualEventReader::::default(); + let mut redraw_event_reader = ManualEventReader::::default(); - trace!("Entering winit event loop"); + let mut settings_system_state = SystemState::>::from_world(&mut app.world); + let return_from_run = settings_system_state.get(&app.world).return_from_run; - let mut focused_window_state: SystemState<(Res, Query<&Window>)> = - SystemState::from_world(&mut app.world); + let mut primary_window_system_state = SystemState::<( + NonSend, + Query>, + )>::from_world(&mut app.world); #[cfg(not(target_arch = "wasm32"))] let mut create_window_system_state: SystemState<( @@ -339,69 +344,60 @@ pub fn winit_runner(mut app: App) { )> = SystemState::from_world(&mut app.world); { - let (winit_config, _) = focused_window_state.get(&app.world); - let main_schedule_label = winit_config.main_schedule_label.clone(); - let render_schedule_label = winit_config.render_schedule_label.clone(); + let settings = settings_system_state.get(&app.world); + let main_schedule_label = settings.main_schedule_label.clone(); + let render_schedule_label = settings.render_schedule_label.clone(); // Prevent panic when schedules do not exist app.init_schedule(main_schedule_label); app.init_schedule(render_schedule_label); } + let mut app_active = false; let mut finished_and_setup_done = false; + let mut tick_mode = TickMode::Periodic { + next_tick: Instant::now(), + rate_multiplier: 1., + }; + let mut request_redraw = true; + let mut next_frame = Instant::now(); + let event_handler = move |event: Event<()>, event_loop: &EventLoopWindowTarget<()>, control_flow: &mut ControlFlow| { #[cfg(feature = "trace")] let _span = bevy_utils::tracing::info_span!("winit event_handler").entered(); - if !finished_and_setup_done { - if !app.ready() { - #[cfg(not(target_arch = "wasm32"))] - tick_global_task_pools_on_main_thread(); - } else { - app.finish(); - app.cleanup(); - finished_and_setup_done = true; - } - } - - if let Some(app_exit_events) = app.world.get_resource::>() { - if app_exit_event_reader.iter(app_exit_events).last().is_some() { - *control_flow = ControlFlow::Exit; - return; - } - } - match event { - event::Event::NewEvents(start) => { - let (winit_config, window_focused_query) = focused_window_state.get(&app.world); - - let app_focused = window_focused_query.iter().any(|window| window.focused); + Event::NewEvents(start) => { + if let StartCause::Init = start { + debug!("Entering winit event loop"); + // Spin wait until plugins is ready. + *control_flow = ControlFlow::Poll; + } - // Check if either the `WaitUntil` timeout was triggered by winit, or that same - // amount of time has elapsed since the last app update. This manual check is needed - // because we don't know if the criteria for an app update were met until the end of - // the frame. - let auto_timeout_reached = matches!(start, StartCause::ResumeTimeReached { .. }); - let now = Instant::now(); - let manual_timeout_reached = match winit_config.update_mode(app_focused) { - UpdateMode::Continuous => false, - UpdateMode::Reactive { max_wait } - | UpdateMode::ReactiveLowPower { max_wait } => { - now.duration_since(winit_state.last_update) >= *max_wait + if !finished_and_setup_done { + if !app.ready() { + #[cfg(not(target_arch = "wasm32"))] + tick_global_task_pools_on_main_thread(); + } else { + app.finish(); + app.cleanup(); + finished_and_setup_done = true; } - }; - // The low_power_event state and timeout must be reset at the start of every frame. - winit_state.low_power_event = false; - winit_state.timeout_reached = auto_timeout_reached || manual_timeout_reached; + } } - event::Event::WindowEvent { + Event::WindowEvent { event, window_id: winit_window_id, .. } => { + let settings = settings_system_state.get(&app.world); + if settings.redraw_when_window_event { + request_redraw = true; + } + // Fetch and prepare details from the world let mut system_state: SystemState<( NonSend, @@ -443,8 +439,6 @@ pub fn winit_runner(mut app: App) { return; }; - winit_state.low_power_event = true; - match event { WindowEvent::Resized(size) => { window @@ -658,10 +652,15 @@ pub fn winit_runner(mut app: App) { cache.window = window.clone(); } } - event::Event::DeviceEvent { + Event::DeviceEvent { event: DeviceEvent::MouseMotion { delta: (x, y) }, .. } => { + let settings = settings_system_state.get(&app.world); + if settings.redraw_when_device_event { + request_redraw = true; + } + let mut system_state: SystemState> = SystemState::new(&mut app.world); let mut mouse_motion = system_state.get_mut(&mut app.world); @@ -670,8 +669,8 @@ pub fn winit_runner(mut app: App) { delta: Vec2::new(x as f32, y as f32), }); } - event::Event::Suspended => { - winit_state.active = false; + Event::Suspended => { + app_active = false; #[cfg(target_os = "android")] { // Bevy doesn't support suspend/resume so we just exit @@ -680,88 +679,142 @@ pub fn winit_runner(mut app: App) { *control_flow = ControlFlow::Exit; } } - event::Event::Resumed => { - winit_state.active = true; + Event::Resumed => { + app_active = true; } - event::Event::MainEventsCleared => { - let (winit_config, window_focused_query) = focused_window_state.get(&app.world); - - let update = if winit_state.active { - // True if _any_ windows are currently being focused - let app_focused = window_focused_query.iter().any(|window| window.focused); - match winit_config.update_mode(app_focused) { - UpdateMode::Continuous | UpdateMode::Reactive { .. } => true, - UpdateMode::ReactiveLowPower { .. } => { - winit_state.low_power_event - || winit_state.redraw_request_sent - || winit_state.timeout_reached + Event::MainEventsCleared => { + if !finished_and_setup_done { + return; + } + + let settings = settings_system_state.get(&app.world); + + let do_tick = match &mut tick_mode { + TickMode::Manual { request_steps } => { + if *request_steps > 0 { + *request_steps -= 1; + true + } else { + false + } + } + TickMode::Periodic { + next_tick, + rate_multiplier, + } => { + let now = Instant::now(); + if *next_tick <= now { + update_next_time( + next_tick, + settings.tick_rate * *rate_multiplier, + settings.allow_tick_skip.then_some(now), + ); + true + } else { + false } } - } else { - false + TickMode::Continuous => true, }; - if update && finished_and_setup_done { - winit_state.last_update = Instant::now(); - let main_schedule_label = winit_config.main_schedule_label.clone(); - let render_schedule_label = winit_config.render_schedule_label.clone(); - - { - #[cfg(feature = "trace")] - let _main_schedule_span = - info_span!("main schedule", name = ?main_schedule_label).entered(); - app.world.run_schedule(main_schedule_label); - } - { - #[cfg(feature = "trace")] - let _render_schedule_span = - info_span!("render schedule", name = ?render_schedule_label).entered(); - app.world.run_schedule(render_schedule_label); + if do_tick { + if settings.redraw_when_tick { + request_redraw = true; } + + run_top_schedule(settings.main_schedule_label.clone(), &mut app.world); app.update_sub_apps(); app.world.clear_trackers(); } - } - Event::RedrawEventsCleared => { - { - // Fetch from world - let (winit_config, window_focused_query) = focused_window_state.get(&app.world); - - // True if _any_ windows are currently being focused - let app_focused = window_focused_query.iter().any(|window| window.focused); + let (windows, query) = primary_window_system_state.get(&app.world); + if let Some(primary_window) = + query.get_single().ok().and_then(|e| windows.get_window(e)) + { let now = Instant::now(); - use UpdateMode::*; - *control_flow = match winit_config.update_mode(app_focused) { - Continuous => ControlFlow::Poll, - Reactive { max_wait } | ReactiveLowPower { max_wait } => { - if let Some(instant) = now.checked_add(*max_wait) { - ControlFlow::WaitUntil(instant) - } else { - ControlFlow::Wait + if next_frame <= now { + let settings = settings_system_state.get(&app.world); + let refresh_rate = primary_window + .current_monitor() + .and_then(|mh| mh.refresh_rate_millihertz()) + .map(|x| x as f64 / 1000.) + .unwrap_or(FALLBACK_REFRESH_RATE); + + // Ensure that the counter advances without redrawing + update_next_time( + &mut next_frame, + settings.frame_rate_limit.min(refresh_rate), + Some(now), + ); + + if let Some(app_redraw_events) = + app.world.get_resource::>() + { + if redraw_event_reader.iter(app_redraw_events).last().is_some() { + request_redraw = true; } } - }; - } - // This block needs to run after `app.world.run_schedule` in `MainEventsCleared`. Otherwise, - // we won't be able to see redraw requests until the next event, defeating the - // purpose of a redraw request! - let mut redraw = false; - if let Some(app_redraw_events) = app.world.get_resource::>() { - if redraw_event_reader.iter(app_redraw_events).last().is_some() { - *control_flow = ControlFlow::Poll; - redraw = true; + if request_redraw + && primary_window.is_visible().unwrap_or(true) + && !primary_window.is_minimized().unwrap_or(false) + { + primary_window.request_redraw(); + } + request_redraw = false; } } - winit_state.redraw_request_sent = redraw; + *control_flow = match &tick_mode { + TickMode::Manual { request_steps } => { + if *request_steps > 0 { + ControlFlow::Poll + } else { + ControlFlow::WaitUntil(next_frame) + } + } + TickMode::Periodic { next_tick, .. } => { + if request_redraw && next_frame < *next_tick { + ControlFlow::WaitUntil(next_frame) + } else { + ControlFlow::WaitUntil(*next_tick) + } + } + TickMode::Continuous => ControlFlow::Poll, + }; + + if let Some(app_exit_events) = app.world.get_resource::>() { + if app_exit_event_reader.iter(app_exit_events).last().is_some() { + *control_flow = ControlFlow::Exit; + } + } } + Event::RedrawRequested(window_id) => { + let (windows, query) = primary_window_system_state.get(&app.world); + let Some(primary_window) = query.get_single().ok().and_then(|e| windows.get_window(e)) else { + return; + }; + if primary_window.id() != window_id { + return; + } + + let settings = settings_system_state.get(&app.world); + let frame_rate = settings + .frame_rate_limit + .min(get_refresh_rate(primary_window)); + run_top_schedule(settings.render_schedule_label.clone(), &mut app.world); + + // Avoid waiting for VSync + let now = Instant::now(); + if next_frame <= now { + update_next_time(&mut next_frame, frame_rate, Some(now)); + } + } _ => (), } - if winit_state.active { + if app_active { #[cfg(not(target_arch = "wasm32"))] let ( commands, diff --git a/crates/bevy_winit/src/winit_config.rs b/crates/bevy_winit/src/winit_config.rs index cae89efa981df..083aec7a76cc7 100644 --- a/crates/bevy_winit/src/winit_config.rs +++ b/crates/bevy_winit/src/winit_config.rs @@ -1,6 +1,5 @@ use bevy_app::{Main, Render}; use bevy_ecs::{schedule::BoxedScheduleLabel, system::Resource}; -use bevy_utils::Duration; /// A resource for configuring usage of the [`winit`] library. #[derive(Debug, Resource)] @@ -28,97 +27,89 @@ pub struct WinitSettings { /// Setting [`return_from_run`](Self::return_from_run) to `true` on /// unsupported platforms will cause [`App::run()`](bevy_app::App::run()) to panic! pub return_from_run: bool, - /// Configures how the winit event loop updates while the window is focused. - pub focused_mode: UpdateMode, - /// Configures how the winit event loop updates while the window is *not* focused. - pub unfocused_mode: UpdateMode, - /// The main schedule to run by default. + /// The frequency at which schedule `main_schedule_label` runs per second. + /// Also, determines the virtual time that elapses for each tick. /// - /// This is initially set to [`Main`]. + /// The default is `125.`. + /// This value is consistent with polling rates for typical input devices, + /// thus optimizing input responsiveness. + pub tick_rate: f64, + /// Allow tick skipping if runs are overdue. + /// + /// If this is enabled, may slow down the game simulation, so it is recommended to disable this for action game. + /// + /// If this is disabled, may result in instantaneous game simulation when tick running load is variable, + /// so it is recommended to enable this for not action game. + /// + /// The default is `false`. + pub allow_tick_skip: bool, + /// Limit on the frequency at which schedule `render_schedule_label` runs per second. + /// Even if this is set to a higher value, the monitor refresh rate will be capped. + /// + /// Redrawing will not be performed unless requested for each frame. + /// Redraw requests are made when: + /// + /// - From the OS as necessary. + /// - Called `WinitHandler::redraw`. + /// - The events specified by `redraw_when_tick`, `redraw_when_window_event`, and `redraw_when_device_event` occurred. + /// + /// The default is `f64::INFINITY`. + pub frame_rate_limit: f64, + /// Request redraw after running ticks. + /// + /// The default is `true`. + pub redraw_when_tick: bool, + /// Request redraw after receiving window events. + /// + /// The default is `true`. + pub redraw_when_window_event: bool, + /// Request redraw after receiving device events. + /// + /// The default is `true`. + pub redraw_when_device_event: bool, + /// The main schedule to be run for each tick. + /// + /// The default is [`Main`]. pub main_schedule_label: BoxedScheduleLabel, - /// The render schedule to run by default. + /// The render schedule to be run for each frame. /// - /// This is initially set to [`Render`]. + /// The default is [`Render`]. pub render_schedule_label: BoxedScheduleLabel, } + impl WinitSettings { + /// Configure winit with basic settings. + pub fn new(tick_rate: f64, allow_tick_skip: bool) -> Self { + Self { + tick_rate, + allow_tick_skip, + ..Default::default() + } + } + /// Configure winit with common settings for a game. pub fn game() -> Self { - WinitSettings::default() + unimplemented!() } /// Configure winit with common settings for a desktop application. pub fn desktop_app() -> Self { - WinitSettings { - focused_mode: UpdateMode::Reactive { - max_wait: Duration::from_secs(5), - }, - unfocused_mode: UpdateMode::ReactiveLowPower { - max_wait: Duration::from_secs(60), - }, - ..Default::default() - } - } - - /// Gets the configured [`UpdateMode`] depending on whether the window is focused or not - pub fn update_mode(&self, focused: bool) -> &UpdateMode { - match focused { - true => &self.focused_mode, - false => &self.unfocused_mode, - } + unimplemented!() } } + impl Default for WinitSettings { fn default() -> Self { WinitSettings { return_from_run: false, - focused_mode: UpdateMode::Continuous, - unfocused_mode: UpdateMode::Continuous, + tick_rate: 125., + allow_tick_skip: false, + frame_rate_limit: f64::INFINITY, + redraw_when_tick: true, + redraw_when_window_event: true, + redraw_when_device_event: true, main_schedule_label: Box::new(Main), render_schedule_label: Box::new(Render), } } } - -/// Configure how the winit event loop should update. -#[derive(Debug)] -pub enum UpdateMode { - /// The event loop will update continuously, running as fast as possible. - Continuous, - /// The event loop will only update if there is a winit event, a redraw is requested, or the - /// maximum wait time has elapsed. - /// - /// ## Note - /// - /// Once the app has executed all bevy systems and reaches the end of the event loop, there is - /// no way to force the app to wake and update again, unless a `winit` event (such as user - /// input, or the window being resized) is received or the time limit is reached. - Reactive { - /// The maximum time to wait before the event loop runs again. - /// - /// Note that Bevy will wait indefinitely if the duration is too high (such as [`Duration::MAX`]). - max_wait: Duration, - }, - /// The event loop will only update if there is a winit event from direct interaction with the - /// window (e.g. mouseover), a redraw is requested, or the maximum wait time has elapsed. - /// - /// ## Note - /// - /// Once the app has executed all bevy systems and reaches the end of the event loop, there is - /// no way to force the app to wake and update again, unless a `winit` event (such as user - /// input, or the window being resized) is received or the time limit is reached. - /// - /// ## Differences from [`UpdateMode::Reactive`] - /// - /// Unlike [`UpdateMode::Reactive`], this mode will ignore winit events that aren't directly - /// caused by interaction with the window. For example, you might want to use this mode when the - /// window is not focused, to only re-draw your bevy app when the cursor is over the window, but - /// not when the mouse moves somewhere else on the screen. This helps to significantly reduce - /// power consumption by only updated the app when absolutely necessary. - ReactiveLowPower { - /// The maximum time to wait before the event loop runs again. - /// - /// Note that Bevy will wait indefinitely if the duration is too high (such as [`Duration::MAX`]). - max_wait: Duration, - }, -} diff --git a/examples/window/low_power.rs b/examples/window/low_power.rs index ba890e7ec9d4b..1cd7808987560 100644 --- a/examples/window/low_power.rs +++ b/examples/window/low_power.rs @@ -5,7 +5,6 @@ use bevy::{ prelude::*, - utils::Duration, window::{PresentMode, RequestRedraw, WindowPlugin}, winit::WinitSettings, }; @@ -17,13 +16,7 @@ fn main() { // Power-saving reactive rendering for applications. .insert_resource(WinitSettings::desktop_app()) // You can also customize update behavior with the fields of [`WinitConfig`] - .insert_resource(WinitSettings { - focused_mode: bevy::winit::UpdateMode::Continuous, - unfocused_mode: bevy::winit::UpdateMode::ReactiveLowPower { - max_wait: Duration::from_millis(10), - }, - ..default() - }) + .insert_resource(WinitSettings { ..default() }) .insert_resource(ExampleMode::Game) .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { From 0f21d9c8892e791dcdff1e3277be85c0ea14cb29 Mon Sep 17 00:00:00 2001 From: B_head Date: Sun, 2 Jul 2023 03:33:21 +0900 Subject: [PATCH 08/13] Add resource to control winit runner Send events for control from resource `WinitHandler`, which contains `EventLoopProxy`. --- crates/bevy_winit/src/lib.rs | 68 +++++++++++++---- crates/bevy_winit/src/system.rs | 4 +- crates/bevy_winit/src/winit_handler.rs | 100 +++++++++++++++++++++++++ crates/bevy_winit/src/winit_windows.rs | 4 +- 4 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 crates/bevy_winit/src/winit_handler.rs diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 02d3ca308046d..a44ade3b6da31 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -13,6 +13,7 @@ mod system; #[cfg(target_arch = "wasm32")] mod web_resize; mod winit_config; +mod winit_handler; mod winit_windows; use bevy_a11y::AccessibilityRequested; @@ -22,6 +23,7 @@ use bevy_tasks::tick_global_task_pools_on_main_thread; use system::{changed_window, create_window, despawn_window, CachedWindow}; pub use winit_config::*; +pub use winit_handler::*; pub use winit_windows::*; use bevy_app::{App, AppExit, Last, Plugin}; @@ -75,7 +77,7 @@ pub struct WinitPlugin; impl Plugin for WinitPlugin { fn build(&self, app: &mut App) { - let mut event_loop_builder = EventLoopBuilder::<()>::with_user_event(); + let mut event_loop_builder = EventLoopBuilder::::with_user_event(); #[cfg(target_os = "android")] { @@ -113,7 +115,7 @@ impl Plugin for WinitPlugin { #[cfg(not(target_arch = "wasm32"))] let mut create_window_system_state: SystemState<( Commands, - NonSendMut>, + NonSendMut>, Query<(Entity, &mut Window)>, EventWriter, NonSendMut, @@ -125,7 +127,7 @@ impl Plugin for WinitPlugin { #[cfg(target_arch = "wasm32")] let mut create_window_system_state: SystemState<( Commands, - NonSendMut>, + NonSendMut>, Query<(Entity, &mut Window)>, EventWriter, NonSendMut, @@ -185,9 +187,10 @@ impl Plugin for WinitPlugin { } } -fn run(event_loop: EventLoop<()>, event_handler: F) -> ! +fn run(event_loop: EventLoop, event_handler: F) -> ! where - F: 'static + FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow), + F: 'static + + FnMut(Event<'_, HandleEvent>, &EventLoopWindowTarget, &mut ControlFlow), { event_loop.run(event_handler) } @@ -204,9 +207,9 @@ where target_os = "netbsd", target_os = "openbsd" ))] -fn run_return(event_loop: &mut EventLoop<()>, event_handler: F) +fn run_return(event_loop: &mut EventLoop, event_handler: F) where - F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow), + F: FnMut(Event<'_, HandleEvent>, &EventLoopWindowTarget, &mut ControlFlow), { use winit::platform::run_return::EventLoopExtRunReturn; event_loop.run_return(event_handler); @@ -221,9 +224,9 @@ where target_os = "netbsd", target_os = "openbsd" )))] -fn run_return(_event_loop: &mut EventLoop<()>, _event_handler: F) +fn run_return(_event_loop: &mut EventLoop, _event_handler: F) where - F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow), + F: FnMut(Event<'_, HandleEvent>, &EventLoopWindowTarget, &mut ControlFlow), { panic!("Run return is not supported on this platform!") } @@ -304,10 +307,9 @@ pub fn winit_runner(mut app: App) { // We remove this so that we have ownership over it. let mut event_loop = app .world - .remove_non_send_resource::>() + .remove_non_send_resource::>() .unwrap(); - app.world - .insert_non_send_resource(event_loop.create_proxy()); + app.world.insert_resource(WinitHandler::new(&event_loop)); let mut app_exit_event_reader = ManualEventReader::::default(); let mut redraw_event_reader = ManualEventReader::::default(); @@ -363,8 +365,8 @@ pub fn winit_runner(mut app: App) { let mut request_redraw = true; let mut next_frame = Instant::now(); - let event_handler = move |event: Event<()>, - event_loop: &EventLoopWindowTarget<()>, + let event_handler = move |event: Event, + event_loop: &EventLoopWindowTarget, control_flow: &mut ControlFlow| { #[cfg(feature = "trace")] let _span = bevy_utils::tracing::info_span!("winit event_handler").entered(); @@ -669,6 +671,44 @@ pub fn winit_runner(mut app: App) { delta: Vec2::new(x as f32, y as f32), }); } + Event::UserEvent(event) => match event { + HandleEvent::Run(rate_multiplier) => { + tick_mode = if let TickMode::Periodic { next_tick, .. } = tick_mode { + TickMode::Periodic { + next_tick, + rate_multiplier, + } + } else { + TickMode::Periodic { + next_tick: Instant::now(), + rate_multiplier, + } + }; + } + HandleEvent::RunFullThrottle => { + tick_mode = TickMode::Continuous; + } + HandleEvent::Pause => { + tick_mode = TickMode::Manual { request_steps: 0 }; + } + HandleEvent::Step(additional_steps) => { + tick_mode = if let TickMode::Manual { request_steps } = tick_mode { + TickMode::Manual { + request_steps: request_steps + additional_steps, + } + } else { + TickMode::Manual { + request_steps: additional_steps, + } + }; + } + HandleEvent::Redraw => { + request_redraw = true; + } + HandleEvent::Exit(code) => { + *control_flow = ControlFlow::ExitWithCode(code); + } + }, Event::Suspended => { app_active = false; #[cfg(target_os = "android")] diff --git a/crates/bevy_winit/src/system.rs b/crates/bevy_winit/src/system.rs index 92a3ec2ca96b0..77a34670cdc5e 100644 --- a/crates/bevy_winit/src/system.rs +++ b/crates/bevy_winit/src/system.rs @@ -32,9 +32,9 @@ use crate::{ /// /// This will default any necessary components if they are not already added. #[allow(clippy::too_many_arguments)] -pub(crate) fn create_window<'a>( +pub(crate) fn create_window<'a, T: 'static>( mut commands: Commands, - event_loop: &EventLoopWindowTarget<()>, + event_loop: &EventLoopWindowTarget, created_windows: impl Iterator)>, mut event_writer: EventWriter, mut winit_windows: NonSendMut, diff --git a/crates/bevy_winit/src/winit_handler.rs b/crates/bevy_winit/src/winit_handler.rs new file mode 100644 index 0000000000000..dec4813986e95 --- /dev/null +++ b/crates/bevy_winit/src/winit_handler.rs @@ -0,0 +1,100 @@ +use bevy_ecs::system::Resource; +use bevy_utils::{synccell::SyncCell, tracing::warn}; +use winit::event_loop::{EventLoop, EventLoopProxy}; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum HandleEvent { + Run(f64), + RunFullThrottle, + Pause, + Step(u64), + Redraw, + Exit(i32), +} + +/// Controls the operation of the winit runner. +#[derive(Resource)] +pub struct WinitHandler { + proxy: SyncCell>, + is_running: bool, +} + +impl WinitHandler { + pub(crate) fn new(event_loop: &EventLoop) -> Self { + Self { + proxy: SyncCell::new(event_loop.create_proxy()), + is_running: false, + } + } + + /// Whether the ticks are automatically run or not. + pub fn is_running(&self) -> bool { + self.is_running + } + + /// Run game ticks in sync with real time. + pub fn run(&mut self) { + self.run_at(1.); + } + + /// Run game ticks in sync with real time with a specified speed. + pub fn run_at(&mut self, rate_multiplier: f64) { + self.is_running = true; + if let Err(e) = self + .proxy + .get() + .send_event(HandleEvent::Run(rate_multiplier)) + { + warn!(%e); + } + } + + /// Run game ticks as fast as possible. + pub fn run_full_throttle(&mut self) { + self.is_running = true; + if let Err(e) = self.proxy.get().send_event(HandleEvent::RunFullThrottle) { + warn!(%e); + } + } + + /// Stop automatic running of game ticks. + pub fn pause(&mut self) { + self.is_running = false; + if let Err(e) = self.proxy.get().send_event(HandleEvent::Pause) { + warn!(%e); + } + } + + /// Run a game tick only once. + pub fn step(&mut self) { + self.step_at(1); + } + + /// Run game ticks a specified number of times. + pub fn step_at(&mut self, request_steps: u64) { + self.is_running = false; + if let Err(e) = self + .proxy + .get() + .send_event(HandleEvent::Step(request_steps)) + { + warn!(%e); + } + } + + /// Requests frame redraw. + /// + /// If called during redrawing, the next redraw is reserved. + pub fn redraw(&mut self) { + if let Err(e) = self.proxy.get().send_event(HandleEvent::Redraw) { + warn!(%e); + } + } + + /// Exit the application. + pub fn exit(&mut self, code: i32) { + if let Err(e) = self.proxy.get().send_event(HandleEvent::Exit(code)) { + warn!(%e); + } + } +} diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 00c58706680a3..5cce9bf87bd1c 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -39,9 +39,9 @@ pub struct WinitWindows { impl WinitWindows { /// Creates a `winit` window and associates it with our entity. - pub fn create_window( + pub fn create_window( &mut self, - event_loop: &winit::event_loop::EventLoopWindowTarget<()>, + event_loop: &winit::event_loop::EventLoopWindowTarget, entity: Entity, window: &Window, adapters: &mut AccessKitAdapters, From 122a0d9c2a3f831aedd48a1cf877a57dac7549ee Mon Sep 17 00:00:00 2001 From: B_head Date: Sat, 8 Jul 2023 07:38:14 +0900 Subject: [PATCH 09/13] Add prelude to the winit module --- crates/bevy_internal/src/prelude.rs | 3 ++- crates/bevy_winit/src/lib.rs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index f9243382a11ef..3368a4f224425 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -2,7 +2,8 @@ pub use crate::{ app::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*, log::prelude::*, math::prelude::*, reflect::prelude::*, time::prelude::*, - transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins, + transform::prelude::*, utils::prelude::*, window::prelude::*, winit::prelude::*, + DefaultPlugins, MinimalPlugins, }; pub use bevy_derive::{bevy_main, Deref, DerefMut}; diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index a44ade3b6da31..e8475d39d9847 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -64,6 +64,12 @@ use crate::converters::convert_winit_theme; #[cfg(target_arch = "wasm32")] use crate::web_resize::{CanvasParentResizeEventChannel, CanvasParentResizePlugin}; +#[allow(missing_docs)] +pub mod prelude { + #[doc(hidden)] + pub use crate::{WinitHandler, WinitSettings}; +} + // Does anyone know the safe value? const FALLBACK_REFRESH_RATE: f64 = 30.; From 4b3b5b524e461cd64e79bc78435852d0bbbd656e Mon Sep 17 00:00:00 2001 From: B_head Date: Mon, 3 Jul 2023 10:50:48 +0900 Subject: [PATCH 10/13] Rename the main schedule label --- crates/bevy_app/src/app.rs | 18 +++++++------- crates/bevy_app/src/lib.rs | 2 +- crates/bevy_app/src/main_schedule.rs | 24 +++++++++---------- crates/bevy_app/src/schedule_runner.rs | 8 +++---- crates/bevy_asset/src/asset_server.rs | 10 ++++---- crates/bevy_asset/src/debug_asset_server.rs | 4 ++-- crates/bevy_asset/src/lib.rs | 4 ++-- crates/bevy_core/src/lib.rs | 2 +- crates/bevy_core_pipeline/src/bloom/mod.rs | 4 ++-- .../src/contrast_adaptive_sharpening/mod.rs | 2 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/core_3d/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/fxaa/mod.rs | 5 +++- .../bevy_core_pipeline/src/msaa_writeback.rs | 4 ++-- crates/bevy_core_pipeline/src/skybox/mod.rs | 4 ++-- crates/bevy_core_pipeline/src/taa/mod.rs | 4 ++-- .../bevy_core_pipeline/src/tonemapping/mod.rs | 2 +- .../bevy_core_pipeline/src/upscaling/mod.rs | 2 +- crates/bevy_gizmos/src/lib.rs | 7 ++++-- crates/bevy_gizmos/src/pipeline_2d.rs | 4 ++-- crates/bevy_gizmos/src/pipeline_3d.rs | 4 ++-- crates/bevy_pbr/src/lib.rs | 4 ++-- crates/bevy_pbr/src/material.rs | 4 ++-- crates/bevy_pbr/src/prepass/mod.rs | 8 +++---- crates/bevy_pbr/src/render/fog.rs | 6 ++--- crates/bevy_pbr/src/render/mesh.rs | 4 ++-- crates/bevy_pbr/src/ssao/mod.rs | 11 +++++---- crates/bevy_pbr/src/wireframe.rs | 4 ++-- crates/bevy_render/src/camera/mod.rs | 6 ++--- crates/bevy_render/src/extract_component.rs | 4 ++-- crates/bevy_render/src/globals.rs | 7 ++++-- crates/bevy_render/src/lib.rs | 10 ++++---- crates/bevy_render/src/pipelined_rendering.rs | 4 ++-- crates/bevy_render/src/render_asset.rs | 6 ++--- crates/bevy_render/src/texture/mod.rs | 4 ++-- crates/bevy_render/src/view/mod.rs | 9 ++++--- crates/bevy_render/src/view/visibility/mod.rs | 4 ++-- crates/bevy_render/src/view/window.rs | 6 ++--- crates/bevy_sprite/src/lib.rs | 2 +- crates/bevy_sprite/src/mesh2d/material.rs | 4 ++-- crates/bevy_sprite/src/mesh2d/mesh.rs | 4 ++-- crates/bevy_transform/src/systems.rs | 6 ++--- crates/bevy_ui/src/render/mod.rs | 2 +- crates/bevy_winit/src/winit_config.rs | 6 ++--- examples/2d/mesh2d_manual.rs | 2 +- examples/app/custom_loop.rs | 2 +- examples/ecs/nondeterministic_system_order.rs | 2 +- .../shader/compute_shader_game_of_life.rs | 2 +- examples/shader/shader_instancing.rs | 2 +- examples/stress_tests/many_lights.rs | 5 +++- tests/how_to_test_systems.rs | 10 ++++---- 51 files changed, 146 insertions(+), 126 deletions(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 2da273c8d5bc2..dca7e92dfc6b9 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,4 +1,6 @@ -use crate::{First, Main, MainSchedulePlugin, Plugin, Plugins, Startup, StateTransition, Update}; +use crate::{ + First, MainSchedulePlugin, Plugin, Plugins, Startup, StateTransition, Update, UpdateFlow, +}; pub use bevy_derive::AppLabel; use bevy_ecs::{ prelude::*, @@ -94,7 +96,7 @@ impl Debug for App { /// # Example /// /// ```rust -/// # use bevy_app::{App, AppLabel, SubApp, Main}; +/// # use bevy_app::{App, AppLabel, SubApp, UpdateFlow}; /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::schedule::ScheduleLabel; /// @@ -115,7 +117,7 @@ impl Debug for App { /// sub_app.insert_resource(Val(100)); /// /// // initialize main schedule -/// sub_app.add_systems(Main, |counter: Res| { +/// sub_app.add_systems(UpdateFlow, |counter: Res| { /// // since we assigned the value from the main world in extract /// // we see that value instead of 100 /// assert_eq!(counter.0, 10); @@ -136,7 +138,7 @@ pub struct SubApp { /// The schedule to run by default. /// - /// This is initially set to [`Main`]. + /// This is initially set to [`UpdateFlow`]. pub main_schedule_label: BoxedScheduleLabel, /// A function that allows access to both the main [`App`] [`World`] and the [`SubApp`]. This is @@ -154,7 +156,7 @@ impl SubApp { pub fn new(app: App, extract: impl Fn(&mut World, &mut App) + Send + Sync + 'static) -> Self { Self { app, - main_schedule_label: Box::new(Main), + main_schedule_label: Box::new(UpdateFlow), extract: Box::new(extract), } } @@ -635,7 +637,7 @@ impl App { /// fn my_runner(mut app: App) { /// loop { /// println!("In main loop"); - /// app.world.run_schedule(Main); + /// app.world.run_schedule(UpdateFlow); /// } /// } /// @@ -963,8 +965,8 @@ fn run_once(mut app: App) { { #[cfg(feature = "trace")] - let _main_schedule_span = info_span!("main schedule", name = ?Main).entered(); - app.world.run_schedule(Main); + let _ = info_span!("run top schedule", name = ?UpdateFlow).entered(); + app.world.run_schedule(UpdateFlow); } app.update_sub_apps(); } diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index 26658f3b196f2..ad0322e7fdb6c 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -25,7 +25,7 @@ pub mod prelude { pub use crate::{ app::App, main_schedule::{ - First, FixedUpdate, Last, Main, PostStartup, PostUpdate, PreStartup, PreUpdate, Render, + First, FixedUpdate, Last, UpdateFlow, PostStartup, PostUpdate, PreStartup, PreUpdate, RenderFlow, Startup, StateTransition, Update, }, DynamicPlugin, Plugin, PluginGroup, diff --git a/crates/bevy_app/src/main_schedule.rs b/crates/bevy_app/src/main_schedule.rs index 06e9e3184c3d6..5e627c28ca427 100644 --- a/crates/bevy_app/src/main_schedule.rs +++ b/crates/bevy_app/src/main_schedule.rs @@ -24,7 +24,7 @@ use bevy_ecs::{ /// * [`PostUpdate`] /// * [`Last`] #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Main; +pub struct UpdateFlow; /// The schedule that runs before [`Startup`]. /// This is run by the [`Main`] schedule. @@ -97,17 +97,17 @@ pub struct Last; /// The main render schedule. #[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)] -pub struct Render; +pub struct RenderFlow; -/// Defines the schedules to be run for the [`Main`] schedule, including +/// Defines the schedules to be run for the [`UpdateFlow`] schedule, including /// their order. #[derive(Resource, Debug)] -pub struct MainScheduleOrder { - /// The labels to run for the [`Main`] schedule (in the order they will be run). +pub struct UpdateFlowOrder { + /// The labels to run for the [`UpdateFlow`] schedule (in the order they will be run). pub labels: Vec>, } -impl Default for MainScheduleOrder { +impl Default for UpdateFlowOrder { fn default() -> Self { Self { labels: vec![ @@ -123,7 +123,7 @@ impl Default for MainScheduleOrder { } } -impl MainScheduleOrder { +impl UpdateFlowOrder { /// Adds the given `schedule` after the `after` schedule pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) { let index = self @@ -135,7 +135,7 @@ impl MainScheduleOrder { } } -impl Main { +impl UpdateFlow { /// A system that runs the "main schedule" pub fn run_main(world: &mut World, mut run_at_least_once: Local) { if !*run_at_least_once { @@ -145,7 +145,7 @@ impl Main { *run_at_least_once = true; } - world.resource_scope(|world, order: Mut| { + world.resource_scope(|world, order: Mut| { for label in &order.labels { let _ = world.try_run_schedule(&**label); } @@ -164,9 +164,9 @@ impl Plugin for MainSchedulePlugin { let mut fixed_update_loop_schedule = Schedule::new(); fixed_update_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded); - app.add_schedule(Main, main_schedule) + app.add_schedule(UpdateFlow, main_schedule) .add_schedule(RunFixedUpdateLoop, fixed_update_loop_schedule) - .init_resource::() - .add_systems(Main, Main::run_main); + .init_resource::() + .add_systems(UpdateFlow, UpdateFlow::run_main); } } diff --git a/crates/bevy_app/src/schedule_runner.rs b/crates/bevy_app/src/schedule_runner.rs index 0faabde8b77de..dd35b1b217019 100644 --- a/crates/bevy_app/src/schedule_runner.rs +++ b/crates/bevy_app/src/schedule_runner.rs @@ -1,7 +1,7 @@ use crate::{ app::{App, AppExit}, plugin::Plugin, - Main, + UpdateFlow, }; use bevy_ecs::{ event::{Events, ManualEventReader}, @@ -64,7 +64,7 @@ impl ScheduleRunnerPlugin { pub fn run_once() -> Self { ScheduleRunnerPlugin { run_mode: RunMode::Once, - main_schedule_label: Box::new(Main), + main_schedule_label: Box::new(UpdateFlow), } } @@ -74,7 +74,7 @@ impl ScheduleRunnerPlugin { run_mode: RunMode::Loop { wait: Some(wait_duration), }, - main_schedule_label: Box::new(Main), + main_schedule_label: Box::new(UpdateFlow), } } } @@ -83,7 +83,7 @@ impl Default for ScheduleRunnerPlugin { fn default() -> Self { ScheduleRunnerPlugin { run_mode: RunMode::Loop { wait: None }, - main_schedule_label: Box::new(Main), + main_schedule_label: Box::new(UpdateFlow), } } } diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 12b843424c68a..1faa501035186 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -645,7 +645,7 @@ pub fn free_unused_assets_system(asset_server: Res) { mod test { use super::*; use crate::{loader::LoadedAsset, update_asset_storage_system}; - use bevy_app::{App, Main, Update}; + use bevy_app::{App, Update, UpdateFlow}; use bevy_ecs::prelude::*; use bevy_reflect::{TypePath, TypeUuid}; use bevy_utils::BoxedFuture; @@ -896,19 +896,19 @@ mod test { // asset is loading assert_eq!(LoadState::Loading, get_load_state(&handle, &app.world)); - app.world.run_schedule(Main); + app.world.run_schedule(UpdateFlow); // asset should exist and be loaded at this point assert_eq!(LoadState::Loaded, get_load_state(&handle, &app.world)); assert!(get_asset(&handle, &app.world).is_some()); // after dropping the handle, next call to `tick` will prepare the assets for removal. drop(handle); - app.world.run_schedule(Main); + app.world.run_schedule(UpdateFlow); assert_eq!(LoadState::Loaded, get_load_state(&weak_handle, &app.world)); assert!(get_asset(&weak_handle, &app.world).is_some()); // second call to tick will actually remove the asset. - app.world.run_schedule(Main); + app.world.run_schedule(UpdateFlow); assert_eq!( LoadState::Unloaded, get_load_state(&weak_handle, &app.world) @@ -918,7 +918,7 @@ mod test { // finally, reload the asset let handle = load_asset(path.clone(), &app.world).typed(); assert_eq!(LoadState::Loading, get_load_state(&handle, &app.world)); - app.world.run_schedule(Main); + app.world.run_schedule(UpdateFlow); assert_eq!(LoadState::Loaded, get_load_state(&handle, &app.world)); assert!(get_asset(&handle, &app.world).is_some()); } diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index 94330b7192ccb..d858f083e3659 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -2,7 +2,7 @@ //! //! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot //! reloaded using the conventional API. -use bevy_app::{App, Main, Plugin, Update}; +use bevy_app::{App, Plugin, Update, UpdateFlow}; use bevy_ecs::{prelude::*, system::SystemState}; use bevy_tasks::{IoTaskPool, TaskPoolBuilder}; use bevy_utils::{Duration, HashMap}; @@ -81,7 +81,7 @@ impl Plugin for DebugAssetServerPlugin { } fn run_debug_asset_app(mut debug_asset_app: NonSendMut) { - debug_asset_app.0.world.run_schedule(Main); + debug_asset_app.0.world.run_schedule(UpdateFlow); } pub(crate) fn sync_debug_assets( diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index cc325d26c4dd5..4bf8448f602f6 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -47,7 +47,7 @@ pub use loader::*; pub use path::*; pub use reflect::*; -use bevy_app::{prelude::*, MainScheduleOrder}; +use bevy_app::{prelude::*, UpdateFlowOrder}; use bevy_ecs::schedule::ScheduleLabel; use bevy_utils::Duration; @@ -142,7 +142,7 @@ impl Plugin for AssetPlugin { ))] app.add_systems(LoadAssets, io::filesystem_watcher_system); - let mut order = app.world.resource_mut::(); + let mut order = app.world.resource_mut::(); order.insert_after(First, LoadAssets); order.insert_after(PostUpdate, AssetEvents); } diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 709a0173e59a1..d21b40d7a96c2 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -203,7 +203,7 @@ mod tests { TypeRegistrationPlugin::default(), FrameCountPlugin::default(), )); - app.world.run_schedule(Main); + app.world.run_schedule(UpdateFlow); let frame_count = app.world.resource::(); assert_eq!(1, frame_count.0); diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 6f92849b170fe..927e3c691744c 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -8,7 +8,7 @@ use crate::{ core_2d::{self, CORE_2D}, core_3d::{self, CORE_3D}, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_ecs::{prelude::*, query::QueryItem}; use bevy_math::UVec2; @@ -66,7 +66,7 @@ impl Plugin for BloomPlugin { .init_resource::>() .init_resource::>() .add_systems( - Render, + RenderFlow, ( prepare_bloom_textures.in_set(RenderSet::Prepare), prepare_downsampling_pipeline.in_set(RenderSet::Prepare), diff --git a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs index c6d3264349c0f..ae87e1f638bfa 100644 --- a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs +++ b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs @@ -119,7 +119,7 @@ impl Plugin for CASPlugin { }; render_app .init_resource::>() - .add_systems(Render, prepare_cas_pipelines.in_set(RenderSet::Prepare)); + .add_systems(RenderFlow, prepare_cas_pipelines.in_set(RenderSet::Prepare)); { use core_3d::graph::node::*; diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index d8b52773b8691..49b867519529c 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -22,7 +22,7 @@ pub const CORE_2D: &str = graph::NAME; pub use camera_2d::*; pub use main_pass_2d_node::*; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_ecs::prelude::*; use bevy_render::{ camera::Camera, @@ -56,7 +56,7 @@ impl Plugin for Core2dPlugin { .init_resource::>() .add_systems(ExtractSchedule, extract_core_2d_camera_phases) .add_systems( - Render, + RenderFlow, ( sort_phase_system::.in_set(RenderSet::PhaseSort), batch_phase_system:: diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index c280f92b85f37..227068bc9c522 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -30,7 +30,7 @@ pub use camera_3d::*; pub use main_opaque_pass_3d_node::*; pub use main_transparent_pass_3d_node::*; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_ecs::prelude::*; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -85,7 +85,7 @@ impl Plugin for Core3dPlugin { .add_systems(ExtractSchedule, extract_core_3d_camera_phases) .add_systems(ExtractSchedule, extract_camera_prepass_phase) .add_systems( - Render, + RenderFlow, ( prepare_core_3d_depth_textures .in_set(RenderSet::Prepare) diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index c90ec78aa7278..c6c4bcd0cf420 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -95,7 +95,10 @@ impl Plugin for FxaaPlugin { }; render_app .init_resource::>() - .add_systems(Render, prepare_fxaa_pipelines.in_set(RenderSet::Prepare)) + .add_systems( + RenderFlow, + prepare_fxaa_pipelines.in_set(RenderSet::Prepare), + ) .add_render_graph_node::>(CORE_3D, core_3d::graph::node::FXAA) .add_render_graph_edges( CORE_3D, diff --git a/crates/bevy_core_pipeline/src/msaa_writeback.rs b/crates/bevy_core_pipeline/src/msaa_writeback.rs index 1bf23b9b0a411..1f6488545926a 100644 --- a/crates/bevy_core_pipeline/src/msaa_writeback.rs +++ b/crates/bevy_core_pipeline/src/msaa_writeback.rs @@ -3,7 +3,7 @@ use crate::{ core_2d::{self, CORE_2D}, core_3d::{self, CORE_3D}, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_ecs::prelude::*; use bevy_render::{ camera::ExtractedCamera, @@ -25,7 +25,7 @@ impl Plugin for MsaaWritebackPlugin { }; render_app.add_systems( - Render, + RenderFlow, queue_msaa_writeback_pipelines.in_set(RenderSet::Queue), ); { diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index 0354630d996f3..7c6dd4b4552e4 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_ecs::{ prelude::{Component, Entity}, @@ -44,7 +44,7 @@ impl Plugin for SkyboxPlugin { render_app .init_resource::>() .add_systems( - Render, + RenderFlow, ( prepare_skybox_pipelines.in_set(RenderSet::Prepare), queue_skybox_bind_groups.in_set(RenderSet::Queue), diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index dfb9417d76fd4..4e3f6f7a384db 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -4,7 +4,7 @@ use crate::{ prelude::Camera3d, prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures}, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_core::FrameCount; use bevy_ecs::{ @@ -63,7 +63,7 @@ impl Plugin for TemporalAntiAliasPlugin { .init_resource::>() .add_systems(ExtractSchedule, extract_taa_settings) .add_systems( - Render, + RenderFlow, ( (prepare_taa_jitter_and_mip_bias, apply_deferred) .chain() diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index d1720cb27989b..ccdea0edcf8e8 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -96,7 +96,7 @@ impl Plugin for TonemappingPlugin { render_app .init_resource::>() .add_systems( - Render, + RenderFlow, queue_view_tonemapping_pipelines.in_set(RenderSet::Queue), ); } diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index acbb8476b3dc8..d8a6cc3d590dc 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -15,7 +15,7 @@ impl Plugin for UpscalingPlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app.add_systems( - Render, + RenderFlow, queue_view_upscaling_pipelines.in_set(RenderSet::Queue), ); } diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 52d6ab6b0c4a8..194341878ea0e 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -18,7 +18,7 @@ use std::mem; -use bevy_app::{Last, Plugin, Render, Update}; +use bevy_app::{Last, Plugin, RenderFlow, Update}; use bevy_asset::{load_internal_asset, AddAsset, Assets, Handle, HandleUntyped}; use bevy_core::cast_slice; use bevy_ecs::{ @@ -97,7 +97,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( + RenderFlow, + queue_line_gizmo_bind_group.in_set(RenderSet::Queue), + ); #[cfg(feature = "bevy_sprite")] app.add_plugins(pipeline_2d::LineGizmo2dPlugin); diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 99e9a341066ac..fe4f664d96cd0 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -2,7 +2,7 @@ use crate::{ line_gizmo_vertex_buffer_layouts, DrawLineGizmo, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::Handle; use bevy_core_pipeline::core_2d::Transparent2d; @@ -32,7 +32,7 @@ impl Plugin for LineGizmo2dPlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_line_gizmos_2d.in_set(RenderSet::Queue)); + .add_systems(RenderFlow, queue_line_gizmos_2d.in_set(RenderSet::Queue)); } fn finish(&self, app: &mut App) { diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 6b536b8027e4b..8189570dccb65 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -2,7 +2,7 @@ use crate::{ line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::Handle; use bevy_core_pipeline::core_3d::Transparent3d; @@ -33,7 +33,7 @@ impl Plugin for LineGizmo3dPlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_line_gizmos_3d.in_set(RenderSet::Queue)); + .add_systems(RenderFlow, queue_line_gizmos_3d.in_set(RenderSet::Queue)); } fn finish(&self, app: &mut App) { diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index c56ab6f2bd58d..dc3734bc769fa 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -269,7 +269,7 @@ impl Plugin for PbrPlugin { // Extract the required data from the main world render_app .configure_sets( - Render, + RenderFlow, ( RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare), RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare), @@ -284,7 +284,7 @@ impl Plugin for PbrPlugin { ), ) .add_systems( - Render, + RenderFlow, ( render::prepare_lights .before(ViewSet::PrepareUniforms) diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index c9a5c9af171d8..ec7e91a4ec470 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -3,7 +3,7 @@ use crate::{ MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, ScreenSpaceAmbientOcclusionSettings, SetMeshBindGroup, SetMeshViewBindGroup, Shadow, }; -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; use bevy_core_pipeline::{ core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, @@ -202,7 +202,7 @@ where .init_resource::>>() .add_systems(ExtractSchedule, extract_materials::) .add_systems( - Render, + RenderFlow, ( prepare_materials:: .in_set(RenderSet::Prepare) diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index b27d4eccc7704..2e9a2b15cb2d3 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{Plugin, PreUpdate, Render, Update}; +use bevy_app::{Plugin, PreUpdate, RenderFlow, Update}; use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped}; use bevy_core_pipeline::{ prelude::Camera3d, @@ -104,7 +104,7 @@ where render_app .add_systems( - Render, + RenderFlow, queue_prepass_view_bind_group::.in_set(RenderSet::Queue), ) .init_resource::() @@ -154,7 +154,7 @@ where render_app .add_systems(ExtractSchedule, extract_camera_previous_view_projection) .add_systems( - Render, + RenderFlow, ( prepare_previous_view_projection_uniforms .in_set(RenderSet::Prepare) @@ -171,7 +171,7 @@ where .add_render_command::>() .add_render_command::>() .add_systems( - Render, + RenderFlow, queue_prepass_material_meshes::.in_set(RenderSet::Queue), ); } diff --git a/crates/bevy_pbr/src/render/fog.rs b/crates/bevy_pbr/src/render/fog.rs index 2fcba205e258c..b03299fe680b7 100644 --- a/crates/bevy_pbr/src/render/fog.rs +++ b/crates/bevy_pbr/src/render/fog.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_ecs::prelude::*; use bevy_math::{Vec3, Vec4}; @@ -143,9 +143,9 @@ 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)) + .add_systems(RenderFlow, prepare_fog.in_set(RenderFogSystems::PrepareFog)) .configure_set( - Render, + RenderFlow, RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare), ); } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 3714e68e84e68..88a742d44f321 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -5,7 +5,7 @@ use crate::{ ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS, }; -use bevy_app::{Plugin, Render}; +use bevy_app::{Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, Assets, Handle, HandleId, HandleUntyped}; use bevy_core_pipeline::{ prepass::ViewPrepassTextures, @@ -123,7 +123,7 @@ impl Plugin for MeshRenderPlugin { (extract_meshes, extract_skinned_meshes, extract_morphs), ) .add_systems( - Render, + RenderFlow, ( prepare_skinned_meshes.in_set(RenderSet::Prepare), prepare_morphs.in_set(RenderSet::Prepare), diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 7d0c6af15adba..6ffcbb4a08ffc 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -1,4 +1,4 @@ -use bevy_app::{App, Plugin, Render}; +use bevy_app::{App, Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_core_pipeline::{ core_3d::CORE_3D, @@ -114,9 +114,12 @@ 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(RenderFlow, prepare_ssao_textures.in_set(RenderSet::Prepare)) + .add_systems( + RenderFlow, + prepare_ssao_pipelines.in_set(RenderSet::Prepare), + ) + .add_systems(RenderFlow, queue_ssao_bind_groups.in_set(RenderSet::Queue)) .add_render_graph_node::>( CORE_3D, draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION, diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 4081e4c972577..0ceac4d5139c2 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -1,6 +1,6 @@ use crate::MeshPipeline; use crate::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; -use bevy_app::{Plugin, Render}; +use bevy_app::{Plugin, RenderFlow}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_core_pipeline::core_3d::Opaque3d; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; @@ -48,7 +48,7 @@ impl Plugin for WireframePlugin { render_app .add_render_command::() .init_resource::>() - .add_systems(Render, queue_wireframes.in_set(RenderSet::Queue)); + .add_systems(RenderFlow, queue_wireframes.in_set(RenderSet::Queue)); } } diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index b57ae98dc7941..c543d28ace25f 100644 --- a/crates/bevy_render/src/camera/mod.rs +++ b/crates/bevy_render/src/camera/mod.rs @@ -10,8 +10,8 @@ pub use manual_texture_view::*; pub use projection::*; use crate::{ - extract_resource::ExtractResourcePlugin, render_graph::RenderGraph, ExtractSchedule, Render, - RenderApp, RenderSet, + extract_resource::ExtractResourcePlugin, render_graph::RenderGraph, ExtractSchedule, RenderApp, + RenderFlow, RenderSet, }; use bevy_app::{App, Plugin}; use bevy_ecs::schedule::IntoSystemConfigs; @@ -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(RenderFlow, sort_cameras.in_set(RenderSet::Prepare)); 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..25cfed0b73464 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -2,7 +2,7 @@ use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ComputedVisibility, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderFlow, RenderSet, }; use bevy_app::{App, Plugin}; use bevy_asset::{Asset, Handle}; @@ -84,7 +84,7 @@ impl Plugin for UniformComponentP render_app .insert_resource(ComponentUniforms::::default()) .add_systems( - Render, + RenderFlow, prepare_uniform_components::.in_set(RenderSet::Prepare), ); } diff --git a/crates/bevy_render/src/globals.rs b/crates/bevy_render/src/globals.rs index eb91d019f3cf6..3d1c9c7459ead 100644 --- a/crates/bevy_render/src/globals.rs +++ b/crates/bevy_render/src/globals.rs @@ -3,7 +3,7 @@ use crate::{ prelude::Shader, render_resource::{ShaderType, UniformBuffer}, renderer::{RenderDevice, RenderQueue}, - Extract, ExtractSchedule, Render, RenderApp, RenderSet, + Extract, ExtractSchedule, RenderApp, RenderFlow, RenderSet, }; use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, HandleUntyped}; @@ -27,7 +27,10 @@ impl Plugin for GlobalsPlugin { .init_resource::() .init_resource::