@@ -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.
278296fn 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