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