Skip to content

Commit 9a588d1

Browse files
committed
remove extract stage to run during extract
1 parent 2c72f9c commit 9a588d1

File tree

4 files changed

+65
-21
lines changed

4 files changed

+65
-21
lines changed

crates/bevy_app/src/app.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,14 @@ impl App {
189189
if app.is_building_plugin {
190190
panic!("App::run() was called from within Plugin::Build(), which is not allowed.");
191191
}
192+
193+
// temporarily remove the plugin registry to run each plugin's setup function on app.
194+
let mut plugin_registry = std::mem::take(&mut app.plugin_registry);
195+
for plugin in &plugin_registry {
196+
plugin.setup(&mut app);
197+
}
198+
std::mem::swap(&mut app.plugin_registry, &mut plugin_registry);
199+
192200
let runner = std::mem::replace(&mut app.runner, Box::new(run_once));
193201
(runner)(app);
194202
}

crates/bevy_app/src/plugin.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@ use std::any::Any;
1616
pub trait Plugin: Downcast + Any + Send + Sync {
1717
/// Configures the [`App`] to which this plugin is added.
1818
fn build(&self, app: &mut App);
19+
20+
/// Runs after all plugins are built, but before the app runner is called.
21+
/// This can be useful if you have some resource that other plugins need during their build step,
22+
/// but after build you want to remove it and send it to another thread.
23+
fn setup(&self, _app: &mut App) {
24+
// do nothing
25+
}
26+
1927
/// Configures a name for the [`Plugin`] which is primarily used for debugging.
2028
fn name(&self) -> &str {
2129
std::any::type_name::<Self>()
2230
}
31+
2332
/// If the plugin can be meaningfully instantiated several times in an [`App`](crate::App),
2433
/// override this method to return `false`.
2534
fn is_unique(&self) -> bool {

crates/bevy_ecs/src/schedule/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,17 @@ impl Schedule {
361361
.and_then(|stage| stage.downcast_mut::<T>())
362362
}
363363

364+
/// Remove a [`Stage`] from the schedule
365+
pub fn remove_stage(&mut self, stage_label: impl StageLabel) -> Option<Box<dyn Stage>> {
366+
let label = stage_label.as_label();
367+
368+
let Some(index) = self.stage_order.iter().position(|x| *x == label) else {
369+
return None;
370+
};
371+
self.stage_order.remove(index);
372+
self.stages.remove(&label)
373+
}
374+
364375
/// Executes each [`Stage`] contained in the schedule, one at a time.
365376
pub fn run_once(&mut self, world: &mut World) {
366377
for label in &self.stage_order {

crates/bevy_render/src/lib.rs

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ pub enum RenderStage {
9292
Cleanup,
9393
}
9494

95+
/// Resource for holding the extract stage of the rendering schedule
96+
#[derive(Resource)]
97+
pub struct ExtractStage(pub SystemStage);
98+
9599
/// The simulation [`World`] of the application, stored as a resource.
96100
/// This resource is only available during [`RenderStage::Extract`] and not
97101
/// during command application of that stage.
@@ -266,6 +270,20 @@ impl Plugin for RenderPlugin {
266270
.register_type::<primitives::CubemapFrusta>()
267271
.register_type::<primitives::Frustum>();
268272
}
273+
274+
fn setup(&self, app: &mut App) {
275+
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
276+
// move the extract stage to a resource so render_app.run() does not run it.
277+
let stage = render_app
278+
.schedule
279+
.remove_stage(RenderStage::Extract)
280+
.unwrap()
281+
.downcast::<SystemStage>()
282+
.unwrap();
283+
284+
render_app.world.insert_resource(ExtractStage(*stage));
285+
}
286+
}
269287
}
270288

271289
/// A "scratch" world used to avoid allocating new worlds every frame when
@@ -276,25 +294,23 @@ struct ScratchMainWorld(World);
276294
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
277295
/// This updates the render world with the extracted ECS data of the current frame.
278296
fn extract(app_world: &mut World, render_app: &mut App) {
279-
let extract = render_app
280-
.schedule
281-
.get_stage_mut::<SystemStage>(RenderStage::Extract)
282-
.unwrap();
283-
284-
// temporarily add the app world to the render world as a resource
285-
let scratch_world = app_world.remove_resource::<ScratchMainWorld>().unwrap();
286-
let inserted_world = std::mem::replace(app_world, scratch_world.0);
287-
let running_world = &mut render_app.world;
288-
running_world.insert_resource(MainWorld(inserted_world));
289-
290-
extract.run(running_world);
291-
// move the app world back, as if nothing happened.
292-
let inserted_world = running_world.remove_resource::<MainWorld>().unwrap();
293-
let scratch_world = std::mem::replace(app_world, inserted_world.0);
294-
app_world.insert_resource(ScratchMainWorld(scratch_world));
295-
296-
// Note: We apply buffers (read, Commands) after the `MainWorld` has been removed from the render app's world
297-
// so that in future, pipelining will be able to do this too without any code relying on it.
298-
// see <https://github.com/bevyengine/bevy/issues/5082>
299-
extract.apply_buffers(running_world);
297+
render_app
298+
.world
299+
.resource_scope(|render_world, mut extract_stage: Mut<ExtractStage>| {
300+
// temporarily add the app world to the render world as a resource
301+
let scratch_world = app_world.remove_resource::<ScratchMainWorld>().unwrap();
302+
let inserted_world = std::mem::replace(app_world, scratch_world.0);
303+
render_world.insert_resource(MainWorld(inserted_world));
304+
305+
extract_stage.0.run(render_world);
306+
// move the app world back, as if nothing happened.
307+
let inserted_world = render_world.remove_resource::<MainWorld>().unwrap();
308+
let scratch_world = std::mem::replace(app_world, inserted_world.0);
309+
app_world.insert_resource(ScratchMainWorld(scratch_world));
310+
311+
// Note: We apply buffers (read, Commands) after the `MainWorld` has been removed from the render app's world
312+
// so that in future, pipelining will be able to do this too without any code relying on it.
313+
// see <https://github.com/bevyengine/bevy/issues/5082>
314+
extract_stage.0.apply_buffers(render_world);
315+
});
300316
}

0 commit comments

Comments
 (0)