Skip to content

Commit d9ed5d3

Browse files
committed
Add dynamic vertex buffer layouts to resolve sorting issues
- Vertex buffer layouts are set on `Mesh` for shader specialization. `Mesh` knows how to specialize its own vertex buffer because it owns the vertex data. - The `RenderAsset` implementation for `Mesh` caches the vertex buffer layout and adds a cache key to the `GpuMesh` render asset. The `MeshPipeline` can lookup the vertex buffer layout by composing `VertexLayoutKey` within `MeshPipelineKey`. - `SpritePipeline` and `UiPipeline` populates the vertex layout cache for themselves.. - `SpecializedPipeline::specialize` now takes a reference to the `RenderPipelineCache`, which is the best way I could find to get a reference to the cache for vertex layout lookups. - Discussion: https://discord.com/channels/691052431525675048/743663924229963868/908484759833960489
1 parent 25b62f9 commit d9ed5d3

File tree

13 files changed

+424
-292
lines changed

13 files changed

+424
-292
lines changed

examples/shader/custom_shader_pipelined.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bevy::{
77
},
88
math::{Vec3, Vec4},
99
pbr2::{
10-
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
10+
DrawMesh, MeshPipeline, MeshPipelineFlags, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
1111
SetMeshViewBindGroup,
1212
},
1313
prelude::{AddAsset, App, AssetServer, Assets, GlobalTransform, Handle, Plugin, Transform},
@@ -135,8 +135,8 @@ pub struct CustomPipeline {
135135
impl SpecializedPipeline for CustomPipeline {
136136
type Key = MeshPipelineKey;
137137

138-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
139-
let mut descriptor = self.mesh_pipeline.specialize(key);
138+
fn specialize(&self, cache: &RenderPipelineCache, key: Self::Key) -> RenderPipelineDescriptor {
139+
let mut descriptor = self.mesh_pipeline.specialize(cache, key);
140140
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
141141
descriptor.layout = Some(vec![
142142
self.mesh_pipeline.view_layout.clone(),
@@ -177,22 +177,27 @@ impl FromWorld for CustomPipeline {
177177
pub fn queue_custom(
178178
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
179179
materials: Res<RenderAssets<CustomMaterial>>,
180+
render_meshes: Res<RenderAssets<Mesh>>,
180181
custom_pipeline: Res<CustomPipeline>,
181182
mut pipeline_cache: ResMut<RenderPipelineCache>,
182183
mut specialized_pipelines: ResMut<SpecializedPipelines<CustomPipeline>>,
183184
msaa: Res<Msaa>,
184-
material_meshes: Query<(Entity, &Handle<CustomMaterial>, &MeshUniform), With<Handle<Mesh>>>,
185+
material_meshes: Query<(Entity, &Handle<Mesh>, &Handle<CustomMaterial>, &MeshUniform)>,
185186
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
186187
) {
187188
let draw_custom = transparent_3d_draw_functions
188189
.read()
189190
.get_id::<DrawCustom>()
190191
.unwrap();
191-
let key = MeshPipelineKey::from_msaa_samples(msaa.samples);
192192
for (view, mut transparent_phase) in views.iter_mut() {
193193
let view_matrix = view.transform.compute_matrix();
194194
let view_row_2 = view_matrix.row(2);
195-
for (entity, material_handle, mesh_uniform) in material_meshes.iter() {
195+
for (entity, mesh_handle, material_handle, mesh_uniform) in material_meshes.iter() {
196+
let mesh = render_meshes.get(mesh_handle).unwrap();
197+
let key = MeshPipelineKey {
198+
vertex_layout_key: mesh.vertex_layout_key,
199+
flags: MeshPipelineFlags::from_msaa_samples(msaa.samples),
200+
};
196201
if materials.contains_key(material_handle) {
197202
transparent_phase.add(Transparent3d {
198203
entity,

examples/shader/shader_defs_pipelined.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use bevy::{
44
ecs::prelude::*,
55
math::Vec3,
66
pbr2::{
7-
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
7+
DrawMesh, MeshPipeline, MeshPipelineFlags, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
88
SetMeshViewBindGroup,
99
},
1010
prelude::{App, AssetServer, Assets, GlobalTransform, Handle, Plugin, Transform},
1111
render2::{
1212
camera::PerspectiveCameraBundle,
1313
mesh::{shape, Mesh},
14+
render_asset::RenderAssets,
1415
render_component::{ExtractComponent, ExtractComponentPlugin},
1516
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
1617
render_resource::*,
@@ -86,7 +87,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
8687
}
8788

8889
struct IsRedPipeline {
89-
mesh_pipline: MeshPipeline,
90+
mesh_pipeline: MeshPipeline,
9091
shader: Handle<Shader>,
9192
}
9293

@@ -96,7 +97,7 @@ impl FromWorld for IsRedPipeline {
9697
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap();
9798
let shader = asset_server.load("shaders/shader_defs.wgsl");
9899
IsRedPipeline {
99-
mesh_pipline: mesh_pipeline.clone(),
100+
mesh_pipeline: mesh_pipeline.clone(),
100101
shader,
101102
}
102103
}
@@ -105,20 +106,24 @@ impl FromWorld for IsRedPipeline {
105106
impl SpecializedPipeline for IsRedPipeline {
106107
type Key = (IsRed, MeshPipelineKey);
107108

108-
fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor {
109+
fn specialize(
110+
&self,
111+
cache: &RenderPipelineCache,
112+
(is_red, pbr_pipeline_key): Self::Key,
113+
) -> RenderPipelineDescriptor {
109114
let mut shader_defs = Vec::new();
110115
if is_red.0 {
111116
shader_defs.push("IS_RED".to_string());
112117
}
113-
let mut descriptor = self.mesh_pipline.specialize(pbr_pipeline_key);
118+
let mut descriptor = self.mesh_pipeline.specialize(cache, pbr_pipeline_key);
114119
descriptor.vertex.shader = self.shader.clone();
115120
descriptor.vertex.shader_defs = shader_defs.clone();
116121
let fragment = descriptor.fragment.as_mut().unwrap();
117122
fragment.shader = self.shader.clone();
118123
fragment.shader_defs = shader_defs;
119124
descriptor.layout = Some(vec![
120-
self.mesh_pipline.view_layout.clone(),
121-
self.mesh_pipline.mesh_layout.clone(),
125+
self.mesh_pipeline.view_layout.clone(),
126+
self.mesh_pipeline.mesh_layout.clone(),
122127
]);
123128
descriptor
124129
}
@@ -131,24 +136,30 @@ type DrawIsRed = (
131136
DrawMesh,
132137
);
133138

139+
#[allow(clippy::too_many_arguments)]
134140
fn queue_custom(
135141
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
142+
render_meshes: Res<RenderAssets<Mesh>>,
136143
custom_pipeline: Res<IsRedPipeline>,
137144
msaa: Res<Msaa>,
138145
mut pipelines: ResMut<SpecializedPipelines<IsRedPipeline>>,
139146
mut pipeline_cache: ResMut<RenderPipelineCache>,
140-
material_meshes: Query<(Entity, &MeshUniform, &IsRed), With<Handle<Mesh>>>,
147+
material_meshes: Query<(Entity, &Handle<Mesh>, &MeshUniform, &IsRed)>,
141148
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
142149
) {
143150
let draw_custom = transparent_3d_draw_functions
144151
.read()
145152
.get_id::<DrawIsRed>()
146153
.unwrap();
147-
let key = MeshPipelineKey::from_msaa_samples(msaa.samples);
148154
for (view, mut transparent_phase) in views.iter_mut() {
149155
let view_matrix = view.transform.compute_matrix();
150156
let view_row_2 = view_matrix.row(2);
151-
for (entity, mesh_uniform, is_red) in material_meshes.iter() {
157+
for (entity, mesh_handle, mesh_uniform, is_red) in material_meshes.iter() {
158+
let mesh = render_meshes.get(mesh_handle).unwrap();
159+
let key = MeshPipelineKey {
160+
vertex_layout_key: mesh.vertex_layout_key,
161+
flags: MeshPipelineFlags::from_msaa_samples(msaa.samples),
162+
};
152163
let pipeline =
153164
pipelines.specialize(&mut pipeline_cache, &custom_pipeline, (*is_red, key));
154165
transparent_phase.add(Transparent3d {

pipelined/bevy_gltf2/src/loader.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use bevy_render2::{
1414
color::Color,
1515
mesh::{Indices, Mesh, VertexAttributeValues},
1616
primitives::Aabb,
17+
render_resource::VertexFormat,
1718
texture::{Image, ImageType, TextureError},
1819
};
1920
use bevy_scene::Scene;
@@ -132,6 +133,8 @@ async fn load_gltf<'a, 'b>(
132133
.read_tangents()
133134
.map(|v| VertexAttributeValues::Float32x4(v.collect()))
134135
{
136+
mesh.vertex_layout_mut()
137+
.push(Mesh::ATTRIBUTE_TANGENT, VertexFormat::Float32x4);
135138
mesh.set_attribute(Mesh::ATTRIBUTE_TANGENT, vertex_attribute);
136139
}
137140

pipelined/bevy_pbr2/src/render/light.rs

Lines changed: 9 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bevy_math::{const_vec3, Mat4, UVec3, UVec4, Vec3, Vec4, Vec4Swizzles};
1414
use bevy_render2::{
1515
camera::{Camera, CameraProjection},
1616
color::Color,
17-
mesh::Mesh,
17+
mesh::{Mesh, VertexLayoutKey},
1818
render_asset::RenderAssets,
1919
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
2020
render_phase::{
@@ -207,84 +207,21 @@ impl FromWorld for ShadowPipeline {
207207
}
208208
}
209209

210-
bitflags::bitflags! {
211-
#[repr(transparent)]
212-
pub struct ShadowPipelineKey: u32 {
213-
const NONE = 0;
214-
const VERTEX_TANGENTS = (1 << 0);
215-
}
216-
}
210+
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
211+
pub struct ShadowPipelineKey(pub VertexLayoutKey);
217212

218213
impl SpecializedPipeline for ShadowPipeline {
219214
type Key = ShadowPipelineKey;
220215

221-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
222-
let (vertex_array_stride, vertex_attributes) =
223-
if key.contains(ShadowPipelineKey::VERTEX_TANGENTS) {
224-
(
225-
48,
226-
vec![
227-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
228-
VertexAttribute {
229-
format: VertexFormat::Float32x3,
230-
offset: 12,
231-
shader_location: 0,
232-
},
233-
// Normal
234-
VertexAttribute {
235-
format: VertexFormat::Float32x3,
236-
offset: 0,
237-
shader_location: 1,
238-
},
239-
// Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically))
240-
VertexAttribute {
241-
format: VertexFormat::Float32x2,
242-
offset: 40,
243-
shader_location: 2,
244-
},
245-
// Tangent
246-
VertexAttribute {
247-
format: VertexFormat::Float32x4,
248-
offset: 24,
249-
shader_location: 3,
250-
},
251-
],
252-
)
253-
} else {
254-
(
255-
32,
256-
vec![
257-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
258-
VertexAttribute {
259-
format: VertexFormat::Float32x3,
260-
offset: 12,
261-
shader_location: 0,
262-
},
263-
// Normal
264-
VertexAttribute {
265-
format: VertexFormat::Float32x3,
266-
offset: 0,
267-
shader_location: 1,
268-
},
269-
// Uv
270-
VertexAttribute {
271-
format: VertexFormat::Float32x2,
272-
offset: 24,
273-
shader_location: 2,
274-
},
275-
],
276-
)
277-
};
216+
fn specialize(&self, cache: &RenderPipelineCache, key: Self::Key) -> RenderPipelineDescriptor {
217+
let vertex_layout = cache.vertex_layout_cache.get(&key.0).unwrap();
218+
278219
RenderPipelineDescriptor {
279220
vertex: VertexState {
280221
shader: SHADOW_SHADER_HANDLE.typed::<Shader>(),
281222
entry_point: "vertex".into(),
282223
shader_defs: vec![],
283-
buffers: vec![VertexBufferLayout {
284-
array_stride: vertex_array_stride,
285-
step_mode: VertexStepMode::Vertex,
286-
attributes: vertex_attributes,
287-
}],
224+
buffers: vec![vertex_layout.clone()],
288225
},
289226
fragment: None,
290227
layout: Some(vec![self.view_layout.clone(), self.mesh_layout.clone()]),
@@ -1040,13 +977,9 @@ pub fn queue_shadows(
1040977
// NOTE: Lights with shadow mapping disabled will have no visible entities
1041978
// so no meshes will be queued
1042979
for entity in visible_entities.iter().copied() {
1043-
let mut key = ShadowPipelineKey::empty();
1044980
if let Ok(mesh_handle) = casting_meshes.get(entity) {
1045-
if let Some(mesh) = render_meshes.get(mesh_handle) {
1046-
if mesh.has_tangents {
1047-
key |= ShadowPipelineKey::VERTEX_TANGENTS;
1048-
}
1049-
}
981+
let mesh = render_meshes.get(mesh_handle).unwrap();
982+
let key = ShadowPipelineKey(mesh.vertex_layout_key);
1050983
let pipeline_id =
1051984
pipelines.specialize(&mut pipeline_cache, &shadow_pipeline, key);
1052985

0 commit comments

Comments
 (0)