@@ -92,6 +92,10 @@ pub enum RenderStage {
92
92
Cleanup ,
93
93
}
94
94
95
+ /// Resource for holding the extract stage of the rendering schedule
96
+ #[ derive( Resource ) ]
97
+ pub struct ExtractStage ( pub SystemStage ) ;
98
+
95
99
/// The simulation [`World`] of the application, stored as a resource.
96
100
/// This resource is only available during [`RenderStage::Extract`] and not
97
101
/// during command application of that stage.
@@ -266,6 +270,20 @@ impl Plugin for RenderPlugin {
266
270
. register_type :: < primitives:: CubemapFrusta > ( )
267
271
. register_type :: < primitives:: Frustum > ( ) ;
268
272
}
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
+ }
269
287
}
270
288
271
289
/// A "scratch" world used to avoid allocating new worlds every frame when
@@ -276,25 +294,23 @@ struct ScratchMainWorld(World);
276
294
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
277
295
/// This updates the render world with the extracted ECS data of the current frame.
278
296
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
+ } ) ;
300
316
}
0 commit comments