Skip to content

Commit ed16ddc

Browse files
committed
Use RenderStartup for occlusion_culling example.
1 parent 877d278 commit ed16ddc

File tree

1 file changed

+62
-50
lines changed

1 file changed

+62
-50
lines changed

examples/3d/occlusion_culling.rs

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ 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},
@@ -37,6 +36,7 @@ use bevy::{
3736
Render, RenderApp, RenderDebugFlags, RenderPlugin, RenderSystems,
3837
},
3938
};
39+
use bevy_render::RenderStartup;
4040
use bytemuck::Pod;
4141

4242
/// The radius of the spinning sphere of cubes.
@@ -111,7 +111,7 @@ struct IndirectParametersStagingBuffers {
111111
/// really care how up-to-date the counter of culled meshes is. If it's off by a
112112
/// few frames, that's no big deal.
113113
#[derive(Clone, Resource, Deref, DerefMut)]
114-
struct SavedIndirectParameters(Arc<Mutex<SavedIndirectParametersData>>);
114+
struct SavedIndirectParameters(Arc<Mutex<Option<SavedIndirectParametersData>>>);
115115

116116
/// A CPU-side copy of the GPU buffer that stores the indirect draw parameters.
117117
///
@@ -138,27 +138,31 @@ struct SavedIndirectParametersData {
138138
occlusion_culling_introspection_supported: bool,
139139
}
140140

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)))
159144
}
160145
}
161146

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+
162166
/// The demo's current settings.
163167
#[derive(Resource)]
164168
struct AppStatus {
@@ -210,12 +214,25 @@ fn main() {
210214

211215
impl Plugin for ReadbackIndirectParametersPlugin {
212216
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+
213226
// Fetch the render app.
214227
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
215228
return;
216229
};
217230

218231
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)
219236
.init_resource::<IndirectParametersStagingBuffers>()
220237
.add_systems(ExtractSchedule, readback_indirect_parameters)
221238
.add_systems(
@@ -245,26 +262,6 @@ impl Plugin for ReadbackIndirectParametersPlugin {
245262
),
246263
);
247264
}
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-
}
268265
}
269266

270267
/// Spawns all the objects in the scene.
@@ -550,6 +547,10 @@ fn update_status_text(
550547
occlusion_culling_introspection_supported,
551548
): (u32, bool, bool) = {
552549
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+
};
553554
(
554555
saved_indirect_parameters
555556
.data
@@ -597,14 +598,15 @@ fn update_status_text(
597598
fn readback_indirect_parameters(
598599
mut indirect_parameters_staging_buffers: ResMut<IndirectParametersStagingBuffers>,
599600
saved_indirect_parameters: Res<SavedIndirectParameters>,
600-
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
601601
) {
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+
{
608610
return;
609611
}
610612

@@ -620,10 +622,20 @@ fn readback_indirect_parameters(
620622
let saved_indirect_parameters_0 = (**saved_indirect_parameters).clone();
621623
let saved_indirect_parameters_1 = (**saved_indirect_parameters).clone();
622624
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();
624631
});
625632
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];
627639
});
628640
}
629641

0 commit comments

Comments
 (0)