@@ -26,15 +26,14 @@ use bevy::{
2626 prelude:: * ,
2727 render:: {
2828 batching:: gpu_preprocessing:: {
29- GpuPreprocessingMode , GpuPreprocessingSupport , IndirectParametersBuffers ,
30- IndirectParametersIndexed ,
29+ GpuPreprocessingSupport , IndirectParametersBuffers , IndirectParametersIndexed ,
3130 } ,
3231 experimental:: occlusion_culling:: OcclusionCulling ,
3332 render_graph:: { self , NodeRunError , RenderGraphContext , RenderGraphExt , RenderLabel } ,
3433 render_resource:: { Buffer , BufferDescriptor , BufferUsages , MapMode } ,
3534 renderer:: { RenderContext , RenderDevice } ,
3635 settings:: WgpuFeatures ,
37- Render , RenderApp , RenderDebugFlags , RenderPlugin , RenderSystems ,
36+ Render , RenderApp , RenderDebugFlags , RenderPlugin , RenderStartup , RenderSystems ,
3837 } ,
3938} ;
4039use bytemuck:: Pod ;
@@ -111,7 +110,7 @@ struct IndirectParametersStagingBuffers {
111110/// really care how up-to-date the counter of culled meshes is. If it's off by a
112111/// few frames, that's no big deal.
113112#[ derive( Clone , Resource , Deref , DerefMut ) ]
114- struct SavedIndirectParameters ( Arc < Mutex < SavedIndirectParametersData > > ) ;
113+ struct SavedIndirectParameters ( Arc < Mutex < Option < SavedIndirectParametersData > > > ) ;
115114
116115/// A CPU-side copy of the GPU buffer that stores the indirect draw parameters.
117116///
@@ -138,27 +137,31 @@ struct SavedIndirectParametersData {
138137 occlusion_culling_introspection_supported : bool ,
139138}
140139
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 ) ) )
159143 }
160144}
161145
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+
162165/// The demo's current settings.
163166#[ derive( Resource ) ]
164167struct AppStatus {
@@ -210,12 +213,25 @@ fn main() {
210213
211214impl Plugin for ReadbackIndirectParametersPlugin {
212215 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+
213225 // Fetch the render app.
214226 let Some ( render_app) = app. get_sub_app_mut ( RenderApp ) else {
215227 return ;
216228 } ;
217229
218230 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)
219235 . init_resource :: < IndirectParametersStagingBuffers > ( )
220236 . add_systems ( ExtractSchedule , readback_indirect_parameters)
221237 . add_systems (
@@ -245,26 +261,6 @@ impl Plugin for ReadbackIndirectParametersPlugin {
245261 ) ,
246262 ) ;
247263 }
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- }
268264}
269265
270266/// Spawns all the objects in the scene.
@@ -550,6 +546,10 @@ fn update_status_text(
550546 occlusion_culling_introspection_supported,
551547 ) : ( u32 , bool , bool ) = {
552548 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+ } ;
553553 (
554554 saved_indirect_parameters
555555 . data
@@ -597,14 +597,15 @@ fn update_status_text(
597597fn readback_indirect_parameters (
598598 mut indirect_parameters_staging_buffers : ResMut < IndirectParametersStagingBuffers > ,
599599 saved_indirect_parameters : Res < SavedIndirectParameters > ,
600- gpu_preprocessing_support : Res < GpuPreprocessingSupport > ,
601600) {
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+ {
608609 return ;
609610 }
610611
@@ -620,10 +621,20 @@ fn readback_indirect_parameters(
620621 let saved_indirect_parameters_0 = ( * * saved_indirect_parameters) . clone ( ) ;
621622 let saved_indirect_parameters_1 = ( * * saved_indirect_parameters) . clone ( ) ;
622623 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 ( ) ;
624630 } ) ;
625631 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 ] ;
627638 } ) ;
628639}
629640
0 commit comments