Skip to content

Commit 2a5e9c1

Browse files
authored
Switch most examples to use RenderStartup instead of finish and FromWorld. (#20124)
# Objective - Progress towards #19887. - I am avoiding dealing with the `occlusion_culling` example since it is kinda annoying to resolve nicely (I will do so in another PR). ## Solution - Rewrite these examples to replace FromWorld implementations with systems and other resource changes with systems as well. ## Testing - All the changed examples have been tested and still work.
1 parent c85ab89 commit 2a5e9c1

8 files changed

+185
-207
lines changed

examples/2d/mesh2d_manual.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use bevy::{
2727
sync_component::SyncComponentPlugin,
2828
sync_world::{MainEntityHashMap, RenderEntity},
2929
view::{ExtractedView, RenderVisibleEntities, ViewTarget},
30-
Extract, Render, RenderApp, RenderSystems,
30+
Extract, Render, RenderApp, RenderStartup, RenderSystems,
3131
},
3232
sprite::{
3333
extract_mesh2d, DrawMesh2d, Material2dBindGroupId, Mesh2dPipeline, Mesh2dPipelineKey,
@@ -132,14 +132,16 @@ pub struct ColoredMesh2dPipeline {
132132
shader: Handle<Shader>,
133133
}
134134

135-
impl FromWorld for ColoredMesh2dPipeline {
136-
fn from_world(world: &mut World) -> Self {
137-
Self {
138-
mesh2d_pipeline: Mesh2dPipeline::from_world(world),
139-
// Get the shader from the shader resource we inserted in the plugin.
140-
shader: world.resource::<ColoredMesh2dShader>().0.clone(),
141-
}
142-
}
135+
fn init_colored_mesh_2d_pipeline(
136+
mut commands: Commands,
137+
mesh2d_pipeline: Res<Mesh2dPipeline>,
138+
colored_mesh2d_shader: Res<ColoredMesh2dShader>,
139+
) {
140+
commands.insert_resource(ColoredMesh2dPipeline {
141+
mesh2d_pipeline: mesh2d_pipeline.clone(),
142+
// Clone the shader from the shader resource we inserted in the plugin.
143+
shader: colored_mesh2d_shader.0.clone(),
144+
});
143145
}
144146

145147
// We implement `SpecializedPipeline` to customize the default rendering from `Mesh2dPipeline`
@@ -307,6 +309,7 @@ impl Plugin for ColoredMesh2dPlugin {
307309
.add_render_command::<Transparent2d, DrawColoredMesh2d>()
308310
.init_resource::<SpecializedRenderPipelines<ColoredMesh2dPipeline>>()
309311
.init_resource::<RenderColoredMesh2dInstances>()
312+
.add_systems(RenderStartup, init_colored_mesh_2d_pipeline)
310313
.add_systems(
311314
ExtractSchedule,
312315
extract_colored_mesh2d.after(extract_mesh2d),
@@ -316,13 +319,6 @@ impl Plugin for ColoredMesh2dPlugin {
316319
queue_colored_mesh2d.in_set(RenderSystems::QueueMeshes),
317320
);
318321
}
319-
320-
fn finish(&self, app: &mut App) {
321-
// Register our custom pipeline
322-
app.get_sub_app_mut(RenderApp)
323-
.unwrap()
324-
.init_resource::<ColoredMesh2dPipeline>();
325-
}
326322
}
327323

328324
/// Extract the [`ColoredMesh2d`] marker component into the render app

examples/3d/manual_material.rs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bevy::{
2929
sync_world::MainEntity,
3030
texture::GpuImage,
3131
view::ExtractedView,
32-
Extract, RenderApp,
32+
Extract, RenderApp, RenderStartup,
3333
},
3434
utils::Parallel,
3535
};
@@ -55,52 +55,46 @@ impl Plugin for ImageMaterialPlugin {
5555
check_entities_needing_specialization.after(AssetEventSystems),
5656
)
5757
.init_resource::<EntitiesNeedingSpecialization<ImageMaterial>>();
58-
}
5958

60-
fn finish(&self, app: &mut App) {
6159
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
6260
return;
6361
};
6462

65-
render_app.add_systems(
66-
ExtractSchedule,
63+
render_app
64+
.add_systems(RenderStartup, init_image_material_resources)
65+
.add_systems(
66+
ExtractSchedule,
67+
(
68+
extract_image_materials,
69+
extract_image_materials_needing_specialization,
70+
),
71+
);
72+
}
73+
}
74+
75+
fn init_image_material_resources(
76+
mut commands: Commands,
77+
render_device: Res<RenderDevice>,
78+
mut bind_group_allocators: ResMut<MaterialBindGroupAllocators>,
79+
) {
80+
let bind_group_layout = render_device.create_bind_group_layout(
81+
"image_material_layout",
82+
&BindGroupLayoutEntries::sequential(
83+
ShaderStages::FRAGMENT,
6784
(
68-
extract_image_materials,
69-
extract_image_materials_needing_specialization,
85+
texture_2d(TextureSampleType::Float { filterable: false }),
86+
sampler(SamplerBindingType::NonFiltering),
7087
),
71-
);
72-
73-
render_app.world_mut().resource_scope(
74-
|world: &mut World, mut bind_group_allocators: Mut<MaterialBindGroupAllocators>| {
75-
world.resource_scope(|world: &mut World, render_device: Mut<RenderDevice>| {
76-
let bind_group_layout = render_device.create_bind_group_layout(
77-
"image_material_layout",
78-
&BindGroupLayoutEntries::sequential(
79-
ShaderStages::FRAGMENT,
80-
(
81-
texture_2d(TextureSampleType::Float { filterable: false }),
82-
sampler(SamplerBindingType::NonFiltering),
83-
),
84-
),
85-
);
86-
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
87-
world.insert_resource(ImageMaterialBindGroupLayout(bind_group_layout.clone()));
88-
world.insert_resource(ImageMaterialBindGroupSampler(sampler));
88+
),
89+
);
90+
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
91+
commands.insert_resource(ImageMaterialBindGroupLayout(bind_group_layout.clone()));
92+
commands.insert_resource(ImageMaterialBindGroupSampler(sampler));
8993

90-
bind_group_allocators.insert(
91-
TypeId::of::<ImageMaterial>(),
92-
MaterialBindGroupAllocator::new(
93-
&render_device,
94-
None,
95-
None,
96-
bind_group_layout,
97-
None,
98-
),
99-
);
100-
});
101-
},
102-
);
103-
}
94+
bind_group_allocators.insert(
95+
TypeId::of::<ImageMaterial>(),
96+
MaterialBindGroupAllocator::new(&render_device, None, None, bind_group_layout, None),
97+
);
10498
}
10599

106100
#[derive(Resource)]

examples/shader/compute_shader_game_of_life.rs

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use bevy::{
1212
render_resource::{binding_types::texture_storage_2d, *},
1313
renderer::{RenderContext, RenderDevice},
1414
texture::GpuImage,
15-
Render, RenderApp, RenderSystems,
15+
Render, RenderApp, RenderStartup, RenderSystems,
1616
},
1717
};
1818
use std::borrow::Cow;
@@ -103,20 +103,17 @@ impl Plugin for GameOfLifeComputePlugin {
103103
// for operation on by the compute shader and display on the sprite.
104104
app.add_plugins(ExtractResourcePlugin::<GameOfLifeImages>::default());
105105
let render_app = app.sub_app_mut(RenderApp);
106-
render_app.add_systems(
107-
Render,
108-
prepare_bind_group.in_set(RenderSystems::PrepareBindGroups),
109-
);
106+
render_app
107+
.add_systems(RenderStartup, init_game_of_life_pipeline)
108+
.add_systems(
109+
Render,
110+
prepare_bind_group.in_set(RenderSystems::PrepareBindGroups),
111+
);
110112

111113
let mut render_graph = render_app.world_mut().resource_mut::<RenderGraph>();
112114
render_graph.add_node(GameOfLifeLabel, GameOfLifeNode::default());
113115
render_graph.add_node_edge(GameOfLifeLabel, bevy::render::graph::CameraDriverLabel);
114116
}
115-
116-
fn finish(&self, app: &mut App) {
117-
let render_app = app.sub_app_mut(RenderApp);
118-
render_app.init_resource::<GameOfLifePipeline>();
119-
}
120117
}
121118

122119
#[derive(Resource, Clone, ExtractResource)]
@@ -157,40 +154,41 @@ struct GameOfLifePipeline {
157154
update_pipeline: CachedComputePipelineId,
158155
}
159156

160-
impl FromWorld for GameOfLifePipeline {
161-
fn from_world(world: &mut World) -> Self {
162-
let render_device = world.resource::<RenderDevice>();
163-
let texture_bind_group_layout = render_device.create_bind_group_layout(
164-
"GameOfLifeImages",
165-
&BindGroupLayoutEntries::sequential(
166-
ShaderStages::COMPUTE,
167-
(
168-
texture_storage_2d(TextureFormat::R32Float, StorageTextureAccess::ReadOnly),
169-
texture_storage_2d(TextureFormat::R32Float, StorageTextureAccess::WriteOnly),
170-
),
157+
fn init_game_of_life_pipeline(
158+
mut commands: Commands,
159+
render_device: Res<RenderDevice>,
160+
asset_server: Res<AssetServer>,
161+
pipeline_cache: Res<PipelineCache>,
162+
) {
163+
let texture_bind_group_layout = render_device.create_bind_group_layout(
164+
"GameOfLifeImages",
165+
&BindGroupLayoutEntries::sequential(
166+
ShaderStages::COMPUTE,
167+
(
168+
texture_storage_2d(TextureFormat::R32Float, StorageTextureAccess::ReadOnly),
169+
texture_storage_2d(TextureFormat::R32Float, StorageTextureAccess::WriteOnly),
171170
),
172-
);
173-
let shader = world.load_asset(SHADER_ASSET_PATH);
174-
let pipeline_cache = world.resource::<PipelineCache>();
175-
let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
176-
layout: vec![texture_bind_group_layout.clone()],
177-
shader: shader.clone(),
178-
entry_point: Some(Cow::from("init")),
179-
..default()
180-
});
181-
let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
182-
layout: vec![texture_bind_group_layout.clone()],
183-
shader,
184-
entry_point: Some(Cow::from("update")),
185-
..default()
186-
});
171+
),
172+
);
173+
let shader = asset_server.load(SHADER_ASSET_PATH);
174+
let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
175+
layout: vec![texture_bind_group_layout.clone()],
176+
shader: shader.clone(),
177+
entry_point: Some(Cow::from("init")),
178+
..default()
179+
});
180+
let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
181+
layout: vec![texture_bind_group_layout.clone()],
182+
shader,
183+
entry_point: Some(Cow::from("update")),
184+
..default()
185+
});
187186

188-
GameOfLifePipeline {
189-
texture_bind_group_layout,
190-
init_pipeline,
191-
update_pipeline,
192-
}
193-
}
187+
commands.insert_resource(GameOfLifePipeline {
188+
texture_bind_group_layout,
189+
init_pipeline,
190+
update_pipeline,
191+
});
194192
}
195193

196194
enum GameOfLifeState {

examples/shader/custom_render_phase.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use bevy::{
5555
renderer::RenderContext,
5656
sync_world::MainEntity,
5757
view::{ExtractedView, RenderVisibleEntities, RetainedViewEntity, ViewTarget},
58-
Extract, Render, RenderApp, RenderDebugFlags, RenderSystems,
58+
Extract, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
5959
},
6060
};
6161
use nonmax::NonMaxU32;
@@ -127,6 +127,7 @@ impl Plugin for MeshStencilPhasePlugin {
127127
.init_resource::<DrawFunctions<Stencil3d>>()
128128
.add_render_command::<Stencil3d, DrawMesh3dStencil>()
129129
.init_resource::<ViewSortedRenderPhases<Stencil3d>>()
130+
.add_systems(RenderStartup, init_stencil_pipeline)
130131
.add_systems(ExtractSchedule, extract_camera_phases)
131132
.add_systems(
132133
Render,
@@ -143,16 +144,6 @@ impl Plugin for MeshStencilPhasePlugin {
143144
// Tell the node to run after the main pass
144145
.add_render_graph_edges(Core3d, (Node3d::MainOpaquePass, CustomDrawPassLabel));
145146
}
146-
147-
fn finish(&self, app: &mut App) {
148-
// We need to get the render app from the main app
149-
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
150-
return;
151-
};
152-
// The pipeline needs the RenderDevice to be created and it's only available once plugins
153-
// are initialized
154-
render_app.init_resource::<StencilPipeline>();
155-
}
156147
}
157148

158149
#[derive(Resource)]
@@ -167,13 +158,15 @@ struct StencilPipeline {
167158
shader_handle: Handle<Shader>,
168159
}
169160

170-
impl FromWorld for StencilPipeline {
171-
fn from_world(world: &mut World) -> Self {
172-
Self {
173-
mesh_pipeline: MeshPipeline::from_world(world),
174-
shader_handle: world.resource::<AssetServer>().load(SHADER_ASSET_PATH),
175-
}
176-
}
161+
fn init_stencil_pipeline(
162+
mut commands: Commands,
163+
mesh_pipeline: Res<MeshPipeline>,
164+
asset_server: Res<AssetServer>,
165+
) {
166+
commands.insert_resource(StencilPipeline {
167+
mesh_pipeline: mesh_pipeline.clone(),
168+
shader_handle: asset_server.load(SHADER_ASSET_PATH),
169+
});
177170
}
178171

179172
// For more information on how SpecializedMeshPipeline work, please look at the

examples/shader/custom_shader_instancing.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use bevy::{
3232
renderer::RenderDevice,
3333
sync_world::MainEntity,
3434
view::{ExtractedView, NoFrustumCulling, NoIndirectDrawing},
35-
Render, RenderApp, RenderSystems,
35+
Render, RenderApp, RenderStartup, RenderSystems,
3636
},
3737
};
3838
use bytemuck::{Pod, Zeroable};
@@ -102,6 +102,7 @@ impl Plugin for CustomMaterialPlugin {
102102
app.sub_app_mut(RenderApp)
103103
.add_render_command::<Transparent3d, DrawCustom>()
104104
.init_resource::<SpecializedMeshPipelines<CustomPipeline>>()
105+
.add_systems(RenderStartup, init_custom_pipeline)
105106
.add_systems(
106107
Render,
107108
(
@@ -110,10 +111,6 @@ impl Plugin for CustomMaterialPlugin {
110111
),
111112
);
112113
}
113-
114-
fn finish(&self, app: &mut App) {
115-
app.sub_app_mut(RenderApp).init_resource::<CustomPipeline>();
116-
}
117114
}
118115

119116
#[derive(Clone, Copy, Pod, Zeroable)]
@@ -203,15 +200,15 @@ struct CustomPipeline {
203200
mesh_pipeline: MeshPipeline,
204201
}
205202

206-
impl FromWorld for CustomPipeline {
207-
fn from_world(world: &mut World) -> Self {
208-
let mesh_pipeline = world.resource::<MeshPipeline>();
209-
210-
CustomPipeline {
211-
shader: world.load_asset(SHADER_ASSET_PATH),
212-
mesh_pipeline: mesh_pipeline.clone(),
213-
}
214-
}
203+
fn init_custom_pipeline(
204+
mut commands: Commands,
205+
asset_server: Res<AssetServer>,
206+
mesh_pipeline: Res<MeshPipeline>,
207+
) {
208+
commands.insert_resource(CustomPipeline {
209+
shader: asset_server.load(SHADER_ASSET_PATH),
210+
mesh_pipeline: mesh_pipeline.clone(),
211+
});
215212
}
216213

217214
impl SpecializedMeshPipeline for CustomPipeline {

0 commit comments

Comments
 (0)