Skip to content

Commit 0973d40

Browse files
committed
Add RenderWorld to Extract step (#2555)
Makes the "Render App World" directly available to Extract step systems as a `RenderWorld` resource. Prior to this, there was no way to directly read / write render world state during the Extract step. The only way to make changes was through Commands (which were applied at the end of the stage). ```rust // `thing` is an "app world resource". fn extract_thing(thing: Res<Thing>, mut render_world: ResMut<RenderWorld>) { render_world.insert_resource(ExtractedThing::from(thing)); } ``` RenderWorld makes a number of scenarios possible: * When an extract system does big allocations, it is now possible to reuse them across frames by retrieving old values from RenderWorld (at the cost of reduced parallelism from unique RenderWorld borrows). * Enables inserting into the same resource across multiple extract systems * Enables using past RenderWorld state to inform future extract state (this should generally be avoided) Ultimately this is just a subset of the functionality we want. In the future, it would be great to have "multi-world schedules" to enable fine grained parallelism on the render world during the extract step. But that is a research project that almost certainly won't make it into 0.6. This is a good interim solution that should easily port over to multi-world schedules if/when they land.
1 parent 2e99d84 commit 0973d40

File tree

1 file changed

+41
-2
lines changed
  • pipelined/bevy_render2/src

1 file changed

+41
-2
lines changed

pipelined/bevy_render2/src/lib.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub mod shader;
1111
pub mod texture;
1212
pub mod view;
1313

14+
use std::ops::{Deref, DerefMut};
15+
1416
pub use once_cell;
1517
use wgpu::BackendBit;
1618

@@ -54,6 +56,29 @@ pub enum RenderStage {
5456
Cleanup,
5557
}
5658

59+
/// The Render App World. This is only available as a resource during the Extract step.
60+
#[derive(Default)]
61+
pub struct RenderWorld(World);
62+
63+
impl Deref for RenderWorld {
64+
type Target = World;
65+
66+
fn deref(&self) -> &Self::Target {
67+
&self.0
68+
}
69+
}
70+
71+
impl DerefMut for RenderWorld {
72+
fn deref_mut(&mut self) -> &mut Self::Target {
73+
&mut self.0
74+
}
75+
}
76+
77+
/// A "scratch" world used to avoid allocating new worlds every frame when
78+
// swapping out the Render World.
79+
#[derive(Default)]
80+
struct ScratchRenderWorld(World);
81+
5782
impl Plugin for RenderPlugin {
5883
fn build(&self, app: &mut App) {
5984
let (instance, device, queue) =
@@ -66,7 +91,8 @@ impl Plugin for RenderPlugin {
6691
&wgpu::DeviceDescriptor::default(),
6792
));
6893
app.insert_resource(device.clone())
69-
.insert_resource(queue.clone());
94+
.insert_resource(queue.clone())
95+
.init_resource::<ScratchRenderWorld>();
7096

7197
let mut render_app = App::empty();
7298
let mut extract_stage = SystemStage::parallel();
@@ -89,14 +115,15 @@ impl Plugin for RenderPlugin {
89115
.init_resource::<RenderGraph>()
90116
.init_resource::<DrawFunctions>();
91117

92-
app.add_sub_app(render_app, |app_world, render_app| {
118+
app.add_sub_app(render_app, move |app_world, render_app| {
93119
// reserve all existing app entities for use in render_app
94120
// they can only be spawned using `get_or_spawn()`
95121
let meta_len = app_world.entities().meta.len();
96122
render_app
97123
.world
98124
.entities()
99125
.reserve_entities(meta_len as u32);
126+
100127
// flushing as "invalid" ensures that app world entities aren't added as "empty archetype" entities by default
101128
// these entities cannot be accessed without spawning directly onto them
102129
// this _only_ works as expected because clear_entities() is called at the end of every frame.
@@ -156,6 +183,18 @@ fn extract(app_world: &mut World, render_app: &mut App) {
156183
.schedule
157184
.get_stage_mut::<SystemStage>(&RenderStage::Extract)
158185
.unwrap();
186+
187+
// temporarily add the render world to the app world as a resource
188+
let scratch_world = app_world.remove_resource::<ScratchRenderWorld>().unwrap();
189+
let render_world = std::mem::replace(&mut render_app.world, scratch_world.0);
190+
app_world.insert_resource(RenderWorld(render_world));
191+
159192
extract.run(app_world);
193+
194+
// add the render world back to the render app
195+
let render_world = app_world.remove_resource::<RenderWorld>().unwrap();
196+
let scratch_world = std::mem::replace(&mut render_app.world, render_world.0);
197+
app_world.insert_resource(ScratchRenderWorld(scratch_world));
198+
160199
extract.apply_buffers(&mut render_app.world);
161200
}

0 commit comments

Comments
 (0)