@@ -26,15 +26,14 @@ use bevy::{
26
26
prelude:: * ,
27
27
render:: {
28
28
batching:: gpu_preprocessing:: {
29
- GpuPreprocessingMode , GpuPreprocessingSupport , IndirectParametersBuffers ,
30
- IndirectParametersIndexed ,
29
+ GpuPreprocessingSupport , IndirectParametersBuffers , IndirectParametersIndexed ,
31
30
} ,
32
31
experimental:: occlusion_culling:: OcclusionCulling ,
33
32
render_graph:: { self , NodeRunError , RenderGraphContext , RenderGraphExt , RenderLabel } ,
34
33
render_resource:: { Buffer , BufferDescriptor , BufferUsages , MapMode } ,
35
34
renderer:: { RenderContext , RenderDevice } ,
36
35
settings:: WgpuFeatures ,
37
- Render , RenderApp , RenderDebugFlags , RenderPlugin , RenderSystems ,
36
+ Render , RenderApp , RenderDebugFlags , RenderPlugin , RenderStartup , RenderSystems ,
38
37
} ,
39
38
} ;
40
39
use bytemuck:: Pod ;
@@ -111,7 +110,7 @@ struct IndirectParametersStagingBuffers {
111
110
/// really care how up-to-date the counter of culled meshes is. If it's off by a
112
111
/// few frames, that's no big deal.
113
112
#[ derive( Clone , Resource , Deref , DerefMut ) ]
114
- struct SavedIndirectParameters ( Arc < Mutex < SavedIndirectParametersData > > ) ;
113
+ struct SavedIndirectParameters ( Arc < Mutex < Option < SavedIndirectParametersData > > > ) ;
115
114
116
115
/// A CPU-side copy of the GPU buffer that stores the indirect draw parameters.
117
116
///
@@ -138,27 +137,31 @@ struct SavedIndirectParametersData {
138
137
occlusion_culling_introspection_supported : bool ,
139
138
}
140
139
141
- impl FromWorld for SavedIndirectParameters {
142
- fn from_world ( world : & mut World ) -> SavedIndirectParameters {
143
- let render_device = world. resource :: < RenderDevice > ( ) ;
144
- SavedIndirectParameters ( Arc :: new ( Mutex :: new ( SavedIndirectParametersData {
145
- data : vec ! [ ] ,
146
- count : 0 ,
147
- // This gets set to false in `readback_indirect_buffers` if we don't
148
- // support GPU preprocessing.
149
- occlusion_culling_supported : true ,
150
- // In order to determine how many meshes were culled, we look at the
151
- // indirect count buffer that Bevy only populates if the platform
152
- // supports `multi_draw_indirect_count`. So, if we don't have that
153
- // feature, then we don't bother to display how many meshes were
154
- // culled.
155
- occlusion_culling_introspection_supported : render_device
156
- . features ( )
157
- . contains ( WgpuFeatures :: MULTI_DRAW_INDIRECT_COUNT ) ,
158
- } ) ) )
140
+ impl SavedIndirectParameters {
141
+ fn new ( ) -> Self {
142
+ Self ( Arc :: new ( Mutex :: new ( None ) ) )
159
143
}
160
144
}
161
145
146
+ fn init_saved_indirect_parameters (
147
+ render_device : Res < RenderDevice > ,
148
+ gpu_preprocessing_support : Res < GpuPreprocessingSupport > ,
149
+ saved_indirect_parameters : Res < SavedIndirectParameters > ,
150
+ ) {
151
+ let mut saved_indirect_parameters = saved_indirect_parameters. 0 . lock ( ) . unwrap ( ) ;
152
+ * saved_indirect_parameters = Some ( SavedIndirectParametersData {
153
+ data : vec ! [ ] ,
154
+ count : 0 ,
155
+ occlusion_culling_supported : gpu_preprocessing_support. is_culling_supported ( ) ,
156
+ // In order to determine how many meshes were culled, we look at the indirect count buffer
157
+ // that Bevy only populates if the platform supports `multi_draw_indirect_count`. So, if we
158
+ // don't have that feature, then we don't bother to display how many meshes were culled.
159
+ occlusion_culling_introspection_supported : render_device
160
+ . features ( )
161
+ . contains ( WgpuFeatures :: MULTI_DRAW_INDIRECT_COUNT ) ,
162
+ } ) ;
163
+ }
164
+
162
165
/// The demo's current settings.
163
166
#[ derive( Resource ) ]
164
167
struct AppStatus {
@@ -210,12 +213,25 @@ fn main() {
210
213
211
214
impl Plugin for ReadbackIndirectParametersPlugin {
212
215
fn build ( & self , app : & mut App ) {
216
+ // Create the `SavedIndirectParameters` resource that we're going to use
217
+ // to communicate between the thread that the GPU-to-CPU readback
218
+ // callback runs on and the main application threads. This resource is
219
+ // atomically reference counted. We store one reference to the
220
+ // `SavedIndirectParameters` in the main app and another reference in
221
+ // the render app.
222
+ let saved_indirect_parameters = SavedIndirectParameters :: new ( ) ;
223
+ app. insert_resource ( saved_indirect_parameters. clone ( ) ) ;
224
+
213
225
// Fetch the render app.
214
226
let Some ( render_app) = app. get_sub_app_mut ( RenderApp ) else {
215
227
return ;
216
228
} ;
217
229
218
230
render_app
231
+ // Insert another reference to the `SavedIndirectParameters`.
232
+ . insert_resource ( saved_indirect_parameters)
233
+ // Setup the parameters in RenderStartup.
234
+ . add_systems ( RenderStartup , init_saved_indirect_parameters)
219
235
. init_resource :: < IndirectParametersStagingBuffers > ( )
220
236
. add_systems ( ExtractSchedule , readback_indirect_parameters)
221
237
. add_systems (
@@ -245,26 +261,6 @@ impl Plugin for ReadbackIndirectParametersPlugin {
245
261
) ,
246
262
) ;
247
263
}
248
-
249
- fn finish ( & self , app : & mut App ) {
250
- // Create the `SavedIndirectParameters` resource that we're going to use
251
- // to communicate between the thread that the GPU-to-CPU readback
252
- // callback runs on and the main application threads. This resource is
253
- // atomically reference counted. We store one reference to the
254
- // `SavedIndirectParameters` in the main app and another reference in
255
- // the render app.
256
- let saved_indirect_parameters = SavedIndirectParameters :: from_world ( app. world_mut ( ) ) ;
257
- app. insert_resource ( saved_indirect_parameters. clone ( ) ) ;
258
-
259
- // Fetch the render app.
260
- let Some ( render_app) = app. get_sub_app_mut ( RenderApp ) else {
261
- return ;
262
- } ;
263
-
264
- render_app
265
- // Insert another reference to the `SavedIndirectParameters`.
266
- . insert_resource ( saved_indirect_parameters) ;
267
- }
268
264
}
269
265
270
266
/// Spawns all the objects in the scene.
@@ -550,6 +546,10 @@ fn update_status_text(
550
546
occlusion_culling_introspection_supported,
551
547
) : ( u32 , bool , bool ) = {
552
548
let saved_indirect_parameters = saved_indirect_parameters. lock ( ) . unwrap ( ) ;
549
+ let Some ( saved_indirect_parameters) = saved_indirect_parameters. as_ref ( ) else {
550
+ // Bail out early if the resource isn't initialized yet.
551
+ return ;
552
+ } ;
553
553
(
554
554
saved_indirect_parameters
555
555
. data
@@ -597,14 +597,15 @@ fn update_status_text(
597
597
fn readback_indirect_parameters (
598
598
mut indirect_parameters_staging_buffers : ResMut < IndirectParametersStagingBuffers > ,
599
599
saved_indirect_parameters : Res < SavedIndirectParameters > ,
600
- gpu_preprocessing_support : Res < GpuPreprocessingSupport > ,
601
600
) {
602
- // If culling isn't supported on this platform, note that, and bail.
603
- if gpu_preprocessing_support. max_supported_mode != GpuPreprocessingMode :: Culling {
604
- saved_indirect_parameters
605
- . lock ( )
606
- . unwrap ( )
607
- . occlusion_culling_supported = false ;
601
+ // If culling isn't supported on this platform, bail.
602
+ if !saved_indirect_parameters
603
+ . lock ( )
604
+ . unwrap ( )
605
+ . as_ref ( )
606
+ . unwrap ( )
607
+ . occlusion_culling_supported
608
+ {
608
609
return ;
609
610
}
610
611
@@ -620,10 +621,20 @@ fn readback_indirect_parameters(
620
621
let saved_indirect_parameters_0 = ( * * saved_indirect_parameters) . clone ( ) ;
621
622
let saved_indirect_parameters_1 = ( * * saved_indirect_parameters) . clone ( ) ;
622
623
readback_buffer :: < IndirectParametersIndexed > ( data_buffer, move |indirect_parameters| {
623
- saved_indirect_parameters_0. lock ( ) . unwrap ( ) . data = indirect_parameters. to_vec ( ) ;
624
+ saved_indirect_parameters_0
625
+ . lock ( )
626
+ . unwrap ( )
627
+ . as_mut ( )
628
+ . unwrap ( )
629
+ . data = indirect_parameters. to_vec ( ) ;
624
630
} ) ;
625
631
readback_buffer :: < u32 > ( batch_sets_buffer, move |indirect_parameters_count| {
626
- saved_indirect_parameters_1. lock ( ) . unwrap ( ) . count = indirect_parameters_count[ 0 ] ;
632
+ saved_indirect_parameters_1
633
+ . lock ( )
634
+ . unwrap ( )
635
+ . as_mut ( )
636
+ . unwrap ( )
637
+ . count = indirect_parameters_count[ 0 ] ;
627
638
} ) ;
628
639
}
629
640
0 commit comments