Skip to content

Commit 9a4cc42

Browse files
committed
EntityRenderCommand and PhaseItemRenderCommand (#3111)
Adds new `EntityRenderCommand`, `EntityPhaseItem`, and `CachedPipelinePhaseItem` traits to make it possible to reuse RenderCommands across phases. This should be helpful for features like #3072 . It also makes the trait impls slightly less generic-ey in the common cases. This also fixes the custom shader examples to account for the recent Frustum Culling and MSAA changes (the UX for these things will be improved later).
1 parent 290b7dd commit 9a4cc42

File tree

8 files changed

+184
-150
lines changed

8 files changed

+184
-150
lines changed

assets/shaders/custom.wgsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var<uniform> view: View;
1111
struct Mesh {
1212
transform: mat4x4<f32>;
1313
};
14-
[[group(2), binding(0)]]
14+
[[group(1), binding(0)]]
1515
var<uniform> mesh: Mesh;
1616

1717
struct Vertex {
@@ -37,7 +37,7 @@ fn vertex(vertex: Vertex) -> VertexOutput {
3737
struct CustomMaterial {
3838
color: vec4<f32>;
3939
};
40-
[[group(1), binding(0)]]
40+
[[group(2), binding(0)]]
4141
var<uniform> material: CustomMaterial;
4242

4343
[[stage(fragment)]]

examples/shader/custom_shader_pipelined.rs

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bevy::{
2-
core_pipeline::{SetItemPipeline, Transparent3d},
2+
core_pipeline::Transparent3d,
33
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
44
ecs::{
55
prelude::*,
@@ -19,11 +19,12 @@ use bevy::{
1919
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
2020
render_component::ExtractComponentPlugin,
2121
render_phase::{
22-
AddRenderCommand, DrawFunctions, RenderCommand, RenderPhase, TrackedRenderPass,
22+
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderPhase, SetItemPipeline,
23+
TrackedRenderPass,
2324
},
2425
render_resource::*,
2526
renderer::RenderDevice,
26-
view::ExtractedView,
27+
view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
2728
RenderApp, RenderStage,
2829
},
2930
PipelinedDefaultPlugins,
@@ -51,6 +52,8 @@ fn setup(
5152
meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
5253
Transform::from_xyz(0.0, 0.5, 0.0),
5354
GlobalTransform::default(),
55+
Visibility::default(),
56+
ComputedVisibility::default(),
5457
materials.add(CustomMaterial {
5558
color: Color::GREEN,
5659
}),
@@ -118,21 +121,36 @@ impl Plugin for CustomMaterialPlugin {
118121
app.sub_app(RenderApp)
119122
.add_render_command::<Transparent3d, DrawCustom>()
120123
.init_resource::<CustomPipeline>()
124+
.init_resource::<SpecializedPipelines<CustomPipeline>>()
121125
.add_system_to_stage(RenderStage::Queue, queue_custom);
122126
}
123127
}
124128

125129
pub struct CustomPipeline {
126130
material_layout: BindGroupLayout,
127-
pipeline: CachedPipelineId,
131+
shader: Handle<Shader>,
132+
pbr_pipeline: PbrPipeline,
133+
}
134+
135+
impl SpecializedPipeline for CustomPipeline {
136+
type Key = PbrPipelineKey;
137+
138+
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
139+
let mut descriptor = self.pbr_pipeline.specialize(key);
140+
descriptor.vertex.shader = self.shader.clone();
141+
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
142+
descriptor.layout = Some(vec![
143+
self.pbr_pipeline.view_layout.clone(),
144+
self.pbr_pipeline.mesh_layout.clone(),
145+
self.material_layout.clone(),
146+
]);
147+
descriptor
148+
}
128149
}
129150

130151
impl FromWorld for CustomPipeline {
131152
fn from_world(world: &mut World) -> Self {
132-
let world = world.cell();
133153
let asset_server = world.get_resource::<AssetServer>().unwrap();
134-
let shader = asset_server.load("shaders/custom.wgsl");
135-
136154
let render_device = world.get_resource::<RenderDevice>().unwrap();
137155
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
138156
entries: &[BindGroupLayoutEntry {
@@ -148,43 +166,42 @@ impl FromWorld for CustomPipeline {
148166
label: None,
149167
});
150168

151-
let pbr_pipeline = world.get_resource::<PbrPipeline>().unwrap();
152-
let mut descriptor = pbr_pipeline.specialize(PbrPipelineKey::empty());
153-
descriptor.vertex.shader = shader.clone();
154-
descriptor.fragment.as_mut().unwrap().shader = shader;
155-
descriptor.layout = Some(vec![
156-
pbr_pipeline.view_layout.clone(),
157-
material_layout.clone(),
158-
pbr_pipeline.mesh_layout.clone(),
159-
]);
160-
161-
let mut pipeline_cache = world.get_resource_mut::<RenderPipelineCache>().unwrap();
162169
CustomPipeline {
163-
pipeline: pipeline_cache.queue(descriptor),
170+
pbr_pipeline: world.get_resource::<PbrPipeline>().unwrap().clone(),
171+
shader: asset_server.load("shaders/custom.wgsl"),
164172
material_layout,
165173
}
166174
}
167175
}
168176

177+
#[allow(clippy::too_many_arguments)]
169178
pub fn queue_custom(
170179
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
171180
materials: Res<RenderAssets<CustomMaterial>>,
172181
custom_pipeline: Res<CustomPipeline>,
182+
mut pipeline_cache: ResMut<RenderPipelineCache>,
183+
mut specialized_pipelines: ResMut<SpecializedPipelines<CustomPipeline>>,
184+
msaa: Res<Msaa>,
173185
material_meshes: Query<(Entity, &Handle<CustomMaterial>, &MeshUniform), With<Handle<Mesh>>>,
174186
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
175187
) {
176188
let draw_custom = transparent_3d_draw_functions
177189
.read()
178190
.get_id::<DrawCustom>()
179191
.unwrap();
192+
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
180193
for (view, mut transparent_phase) in views.iter_mut() {
181194
let view_matrix = view.transform.compute_matrix();
182195
let view_row_2 = view_matrix.row(2);
183196
for (entity, material_handle, mesh_uniform) in material_meshes.iter() {
184197
if materials.contains_key(material_handle) {
185198
transparent_phase.add(Transparent3d {
186199
entity,
187-
pipeline: custom_pipeline.pipeline,
200+
pipeline: specialized_pipelines.specialize(
201+
&mut pipeline_cache,
202+
&custom_pipeline,
203+
key,
204+
),
188205
draw_function: draw_custom,
189206
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
190207
});
@@ -196,25 +213,25 @@ pub fn queue_custom(
196213
type DrawCustom = (
197214
SetItemPipeline,
198215
SetMeshViewBindGroup<0>,
216+
SetTransformBindGroup<1>,
199217
SetCustomMaterialBindGroup,
200-
SetTransformBindGroup<2>,
201218
DrawMesh,
202219
);
203220

204221
struct SetCustomMaterialBindGroup;
205-
impl RenderCommand<Transparent3d> for SetCustomMaterialBindGroup {
222+
impl EntityRenderCommand for SetCustomMaterialBindGroup {
206223
type Param = (
207224
SRes<RenderAssets<CustomMaterial>>,
208225
SQuery<Read<Handle<CustomMaterial>>>,
209226
);
210227
fn render<'w>(
211228
_view: Entity,
212-
item: &Transparent3d,
229+
item: Entity,
213230
(materials, query): SystemParamItem<'w, '_, Self::Param>,
214231
pass: &mut TrackedRenderPass<'w>,
215232
) {
216-
let material_handle = query.get(item.entity).unwrap();
233+
let material_handle = query.get(item).unwrap();
217234
let material = materials.into_inner().get(material_handle).unwrap();
218-
pass.set_bind_group(1, &material.bind_group, &[]);
235+
pass.set_bind_group(2, &material.bind_group, &[]);
219236
}
220237
}

examples/shader/shader_defs_pipelined.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bevy::{
2-
core_pipeline::{SetItemPipeline, Transparent3d},
2+
core_pipeline::Transparent3d,
33
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
44
ecs::prelude::*,
55
math::Vec3,
@@ -12,9 +12,9 @@ use bevy::{
1212
camera::PerspectiveCameraBundle,
1313
mesh::{shape, Mesh},
1414
render_component::{ExtractComponent, ExtractComponentPlugin},
15-
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase},
15+
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
1616
render_resource::*,
17-
view::ExtractedView,
17+
view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
1818
RenderApp, RenderStage,
1919
},
2020
PipelinedDefaultPlugins,
@@ -64,6 +64,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
6464
IsRed(true),
6565
Transform::from_xyz(-1.0, 0.5, 0.0),
6666
GlobalTransform::default(),
67+
Visibility::default(),
68+
ComputedVisibility::default(),
6769
));
6870

6971
// blue cube
@@ -72,6 +74,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
7274
IsRed(false),
7375
Transform::from_xyz(1.0, 0.5, 0.0),
7476
GlobalTransform::default(),
77+
Visibility::default(),
78+
ComputedVisibility::default(),
7579
));
7680

7781
// camera
@@ -99,14 +103,14 @@ impl FromWorld for IsRedPipeline {
99103
}
100104

101105
impl SpecializedPipeline for IsRedPipeline {
102-
type Key = IsRed;
106+
type Key = (IsRed, PbrPipelineKey);
103107

104-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
108+
fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor {
105109
let mut shader_defs = Vec::new();
106-
if key.0 {
110+
if is_red.0 {
107111
shader_defs.push("IS_RED".to_string());
108112
}
109-
let mut descriptor = self.pbr_pipeline.specialize(PbrPipelineKey::empty());
113+
let mut descriptor = self.pbr_pipeline.specialize(pbr_pipeline_key);
110114
descriptor.vertex.shader = self.shader.clone();
111115
descriptor.vertex.shader_defs = shader_defs.clone();
112116
let fragment = descriptor.fragment.as_mut().unwrap();
@@ -130,6 +134,7 @@ type DrawIsRed = (
130134
fn queue_custom(
131135
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
132136
custom_pipeline: Res<IsRedPipeline>,
137+
msaa: Res<Msaa>,
133138
mut pipelines: ResMut<SpecializedPipelines<IsRedPipeline>>,
134139
mut pipeline_cache: ResMut<RenderPipelineCache>,
135140
material_meshes: Query<(Entity, &MeshUniform, &IsRed), With<Handle<Mesh>>>,
@@ -139,11 +144,13 @@ fn queue_custom(
139144
.read()
140145
.get_id::<DrawIsRed>()
141146
.unwrap();
147+
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
142148
for (view, mut transparent_phase) in views.iter_mut() {
143149
let view_matrix = view.transform.compute_matrix();
144150
let view_row_2 = view_matrix.row(2);
145151
for (entity, mesh_uniform, is_red) in material_meshes.iter() {
146-
let pipeline = pipelines.specialize(&mut pipeline_cache, &custom_pipeline, *is_red);
152+
let pipeline =
153+
pipelines.specialize(&mut pipeline_cache, &custom_pipeline, (*is_red, key));
147154
transparent_phase.add(Transparent3d {
148155
entity,
149156
pipeline,

pipelined/bevy_core_pipeline/src/lib.rs

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@ pub use main_pass_driver::*;
88

99
use bevy_app::{App, Plugin};
1010
use bevy_core::FloatOrd;
11-
use bevy_ecs::{
12-
prelude::*,
13-
system::{lifetimeless::SRes, SystemParamItem},
14-
};
11+
use bevy_ecs::prelude::*;
1512
use bevy_render2::{
1613
camera::{ActiveCameras, CameraPlugin},
1714
color::Color,
1815
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
1916
render_phase::{
20-
sort_phase_system, DrawFunctionId, DrawFunctions, PhaseItem, RenderCommand, RenderPhase,
21-
TrackedRenderPass,
17+
sort_phase_system, CachedPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
18+
PhaseItem, RenderPhase,
2219
},
2320
render_resource::*,
2421
renderer::RenderDevice,
@@ -171,38 +168,17 @@ impl PhaseItem for Transparent3d {
171168
}
172169
}
173170

174-
pub struct SetItemPipeline;
175-
impl RenderCommand<Transparent3d> for SetItemPipeline {
176-
type Param = SRes<RenderPipelineCache>;
171+
impl EntityPhaseItem for Transparent3d {
177172
#[inline]
178-
fn render<'w>(
179-
_view: Entity,
180-
item: &Transparent3d,
181-
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
182-
pass: &mut TrackedRenderPass<'w>,
183-
) {
184-
let pipeline = pipeline_cache
185-
.into_inner()
186-
.get_state(item.pipeline)
187-
.unwrap();
188-
pass.set_render_pipeline(pipeline);
173+
fn entity(&self) -> Entity {
174+
self.entity
189175
}
190176
}
191177

192-
impl RenderCommand<Transparent2d> for SetItemPipeline {
193-
type Param = SRes<RenderPipelineCache>;
178+
impl CachedPipelinePhaseItem for Transparent3d {
194179
#[inline]
195-
fn render<'w>(
196-
_view: Entity,
197-
item: &Transparent2d,
198-
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
199-
pass: &mut TrackedRenderPass<'w>,
200-
) {
201-
let pipeline = pipeline_cache
202-
.into_inner()
203-
.get_state(item.pipeline)
204-
.unwrap();
205-
pass.set_render_pipeline(pipeline);
180+
fn cached_pipeline(&self) -> CachedPipelineId {
181+
self.pipeline
206182
}
207183
}
208184

pipelined/bevy_pbr2/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,10 @@ impl Plugin for PbrPlugin {
108108
.init_resource::<SpecializedPipelines<PbrPipeline>>()
109109
.init_resource::<SpecializedPipelines<ShadowPipeline>>();
110110

111-
let draw_shadow_mesh = DrawShadowMesh::new(&mut render_app.world);
112111
let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);
113112
render_app.add_render_command::<Transparent3d, DrawPbr>();
114-
let render_world = render_app.world.cell();
115-
let draw_functions = render_world
116-
.get_resource::<DrawFunctions<Shadow>>()
117-
.unwrap();
118-
draw_functions.write().add(draw_shadow_mesh);
119-
let mut graph = render_world.get_resource_mut::<RenderGraph>().unwrap();
113+
render_app.add_render_command::<Shadow, DrawShadowMesh>();
114+
let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
120115
let draw_3d_graph = graph
121116
.get_sub_graph_mut(bevy_core_pipeline::draw_3d_graph::NAME)
122117
.unwrap();

0 commit comments

Comments
 (0)