Skip to content

Commit 3a01381

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 converting the specialization key to a vertex layout key.. - `SpritePipeline` populates the vertex layout cache for itself. - `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 44ebcf8 commit 3a01381

File tree

11 files changed

+406
-223
lines changed

11 files changed

+406
-223
lines changed

examples/shader/custom_shader_pipelined.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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(),

examples/shader/shader_defs_pipelined.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
8686
}
8787

8888
struct IsRedPipeline {
89-
mesh_pipline: MeshPipeline,
89+
mesh_pipeline: MeshPipeline,
9090
shader: Handle<Shader>,
9191
}
9292

@@ -96,7 +96,7 @@ impl FromWorld for IsRedPipeline {
9696
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap();
9797
let shader = asset_server.load("shaders/shader_defs.wgsl");
9898
IsRedPipeline {
99-
mesh_pipline: mesh_pipeline.clone(),
99+
mesh_pipeline: mesh_pipeline.clone(),
100100
shader,
101101
}
102102
}
@@ -105,20 +105,24 @@ impl FromWorld for IsRedPipeline {
105105
impl SpecializedPipeline for IsRedPipeline {
106106
type Key = (IsRed, MeshPipelineKey);
107107

108-
fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor {
108+
fn specialize(
109+
&self,
110+
cache: &RenderPipelineCache,
111+
(is_red, pbr_pipeline_key): Self::Key,
112+
) -> RenderPipelineDescriptor {
109113
let mut shader_defs = Vec::new();
110114
if is_red.0 {
111115
shader_defs.push("IS_RED".to_string());
112116
}
113-
let mut descriptor = self.mesh_pipline.specialize(pbr_pipeline_key);
117+
let mut descriptor = self.mesh_pipeline.specialize(cache, pbr_pipeline_key);
114118
descriptor.vertex.shader = self.shader.clone();
115119
descriptor.vertex.shader_defs = shader_defs.clone();
116120
let fragment = descriptor.fragment.as_mut().unwrap();
117121
fragment.shader = self.shader.clone();
118122
fragment.shader_defs = shader_defs;
119123
descriptor.layout = Some(vec![
120-
self.mesh_pipline.view_layout.clone(),
121-
self.mesh_pipline.mesh_layout.clone(),
124+
self.mesh_pipeline.view_layout.clone(),
125+
self.mesh_pipeline.mesh_layout.clone(),
122126
]);
123127
descriptor
124128
}
@@ -131,6 +135,7 @@ type DrawIsRed = (
131135
DrawMesh,
132136
);
133137

138+
#[allow(clippy::too_many_arguments)]
134139
fn queue_custom(
135140
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
136141
custom_pipeline: Res<IsRedPipeline>,

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: 47 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
1414
use bevy_render2::{
1515
camera::CameraProjection,
1616
color::Color,
17-
mesh::Mesh,
17+
mesh::{Mesh, VertexLayoutKey, VertexLayoutMeshKey},
1818
render_asset::RenderAssets,
1919
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
2020
render_phase::{
@@ -201,79 +201,60 @@ bitflags::bitflags! {
201201
pub struct ShadowPipelineKey: u32 {
202202
const NONE = 0;
203203
const VERTEX_TANGENTS = (1 << 0);
204+
const VERTEX_JOINTS = (1 << 1);
205+
}
206+
}
207+
208+
impl From<ShadowPipelineKey> for VertexLayoutKey {
209+
fn from(value: ShadowPipelineKey) -> Self {
210+
let mut key = VertexLayoutMeshKey::empty();
211+
212+
if value.contains(ShadowPipelineKey::VERTEX_TANGENTS) {
213+
key |= VertexLayoutMeshKey::TANGENTS;
214+
}
215+
if value.contains(ShadowPipelineKey::VERTEX_JOINTS) {
216+
key |= VertexLayoutMeshKey::JOINTS;
217+
}
218+
219+
Self::Mesh(key)
220+
}
221+
}
222+
223+
impl From<VertexLayoutKey> for ShadowPipelineKey {
224+
fn from(value: VertexLayoutKey) -> Self {
225+
match value {
226+
VertexLayoutKey::Mesh(mesh_key) => {
227+
let mut key = Self::empty();
228+
229+
if mesh_key.contains(VertexLayoutMeshKey::TANGENTS) {
230+
key |= Self::VERTEX_TANGENTS;
231+
}
232+
if mesh_key.contains(VertexLayoutMeshKey::JOINTS) {
233+
key |= Self::VERTEX_JOINTS;
234+
}
235+
236+
key
237+
}
238+
_ => panic!("Invalid vertex layout key"),
239+
}
204240
}
205241
}
206242

207243
impl SpecializedPipeline for ShadowPipeline {
208244
type Key = ShadowPipelineKey;
209245

210-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
211-
let (vertex_array_stride, vertex_attributes) =
212-
if key.contains(ShadowPipelineKey::VERTEX_TANGENTS) {
213-
(
214-
48,
215-
vec![
216-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
217-
VertexAttribute {
218-
format: VertexFormat::Float32x3,
219-
offset: 12,
220-
shader_location: 0,
221-
},
222-
// Normal
223-
VertexAttribute {
224-
format: VertexFormat::Float32x3,
225-
offset: 0,
226-
shader_location: 1,
227-
},
228-
// Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically))
229-
VertexAttribute {
230-
format: VertexFormat::Float32x2,
231-
offset: 40,
232-
shader_location: 2,
233-
},
234-
// Tangent
235-
VertexAttribute {
236-
format: VertexFormat::Float32x4,
237-
offset: 24,
238-
shader_location: 3,
239-
},
240-
],
241-
)
242-
} else {
243-
(
244-
32,
245-
vec![
246-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
247-
VertexAttribute {
248-
format: VertexFormat::Float32x3,
249-
offset: 12,
250-
shader_location: 0,
251-
},
252-
// Normal
253-
VertexAttribute {
254-
format: VertexFormat::Float32x3,
255-
offset: 0,
256-
shader_location: 1,
257-
},
258-
// Uv
259-
VertexAttribute {
260-
format: VertexFormat::Float32x2,
261-
offset: 24,
262-
shader_location: 2,
263-
},
264-
],
265-
)
266-
};
246+
fn specialize(&self, cache: &RenderPipelineCache, key: Self::Key) -> RenderPipelineDescriptor {
247+
let vertex_layout = cache
248+
.vertex_layout_cache
249+
.get(&VertexLayoutKey::from(key))
250+
.unwrap();
251+
267252
RenderPipelineDescriptor {
268253
vertex: VertexState {
269254
shader: SHADOW_SHADER_HANDLE.typed::<Shader>(),
270255
entry_point: "vertex".into(),
271256
shader_defs: vec![],
272-
buffers: vec![VertexBufferLayout {
273-
array_stride: vertex_array_stride,
274-
step_mode: VertexStepMode::Vertex,
275-
attributes: vertex_attributes,
276-
}],
257+
buffers: vec![vertex_layout.clone()],
277258
},
278259
fragment: None,
279260
layout: Some(vec![self.view_layout.clone(), self.mesh_layout.clone()]),
@@ -815,13 +796,10 @@ pub fn queue_shadows(
815796
// NOTE: Lights with shadow mapping disabled will have no visible entities
816797
// so no meshes will be queued
817798
for VisibleEntity { entity, .. } in visible_entities.iter() {
818-
let mut key = ShadowPipelineKey::empty();
819799
if let Ok(mesh_handle) = casting_meshes.get(*entity) {
820-
if let Some(mesh) = render_meshes.get(mesh_handle) {
821-
if mesh.has_tangents {
822-
key |= ShadowPipelineKey::VERTEX_TANGENTS;
823-
}
824-
}
800+
let mesh = render_meshes.get(mesh_handle).unwrap();
801+
let key = ShadowPipelineKey::from(mesh.vertex_layout_key);
802+
825803
let pipeline_id =
826804
pipelines.specialize(&mut pipeline_cache, &shadow_pipeline, key);
827805

pipelined/bevy_pbr2/src/render/mesh.rs

Lines changed: 45 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use bevy_ecs::{
1111
use bevy_math::Mat4;
1212
use bevy_reflect::TypeUuid;
1313
use bevy_render2::{
14-
mesh::Mesh,
14+
mesh::{Mesh, VertexLayoutKey, VertexLayoutMeshKey},
1515
render_asset::RenderAssets,
1616
render_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
1717
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
@@ -328,11 +328,47 @@ bitflags::bitflags! {
328328
pub struct MeshPipelineKey: u32 {
329329
const NONE = 0;
330330
const VERTEX_TANGENTS = (1 << 0);
331-
const TRANSPARENT_MAIN_PASS = (1 << 1);
331+
const VERTEX_JOINTS = (1 << 1);
332+
const TRANSPARENT_MAIN_PASS = (1 << 2);
332333
const MSAA_RESERVED_BITS = MeshPipelineKey::MSAA_MASK_BITS << MeshPipelineKey::MSAA_SHIFT_BITS;
333334
}
334335
}
335336

337+
impl From<MeshPipelineKey> for VertexLayoutKey {
338+
fn from(value: MeshPipelineKey) -> Self {
339+
let mut key = VertexLayoutMeshKey::empty();
340+
341+
if value.contains(MeshPipelineKey::VERTEX_TANGENTS) {
342+
key |= VertexLayoutMeshKey::TANGENTS;
343+
}
344+
if value.contains(MeshPipelineKey::VERTEX_JOINTS) {
345+
key |= VertexLayoutMeshKey::JOINTS;
346+
}
347+
348+
Self::Mesh(key)
349+
}
350+
}
351+
352+
impl From<VertexLayoutKey> for MeshPipelineKey {
353+
fn from(value: VertexLayoutKey) -> Self {
354+
match value {
355+
VertexLayoutKey::Mesh(mesh_key) => {
356+
let mut key = Self::empty();
357+
358+
if mesh_key.contains(VertexLayoutMeshKey::TANGENTS) {
359+
key |= Self::VERTEX_TANGENTS;
360+
}
361+
if mesh_key.contains(VertexLayoutMeshKey::JOINTS) {
362+
key |= Self::VERTEX_JOINTS;
363+
}
364+
365+
key
366+
}
367+
_ => panic!("Invalid vertex layout key"),
368+
}
369+
}
370+
}
371+
336372
impl MeshPipelineKey {
337373
const MSAA_MASK_BITS: u32 = 0b111111;
338374
const MSAA_SHIFT_BITS: u32 = 32 - 6;
@@ -350,63 +386,12 @@ impl MeshPipelineKey {
350386
impl SpecializedPipeline for MeshPipeline {
351387
type Key = MeshPipelineKey;
352388

353-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
354-
let (vertex_array_stride, vertex_attributes) =
355-
if key.contains(MeshPipelineKey::VERTEX_TANGENTS) {
356-
(
357-
48,
358-
vec![
359-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
360-
VertexAttribute {
361-
format: VertexFormat::Float32x3,
362-
offset: 12,
363-
shader_location: 0,
364-
},
365-
// Normal
366-
VertexAttribute {
367-
format: VertexFormat::Float32x3,
368-
offset: 0,
369-
shader_location: 1,
370-
},
371-
// Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically))
372-
VertexAttribute {
373-
format: VertexFormat::Float32x2,
374-
offset: 40,
375-
shader_location: 2,
376-
},
377-
// Tangent
378-
VertexAttribute {
379-
format: VertexFormat::Float32x4,
380-
offset: 24,
381-
shader_location: 3,
382-
},
383-
],
384-
)
385-
} else {
386-
(
387-
32,
388-
vec![
389-
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
390-
VertexAttribute {
391-
format: VertexFormat::Float32x3,
392-
offset: 12,
393-
shader_location: 0,
394-
},
395-
// Normal
396-
VertexAttribute {
397-
format: VertexFormat::Float32x3,
398-
offset: 0,
399-
shader_location: 1,
400-
},
401-
// Uv
402-
VertexAttribute {
403-
format: VertexFormat::Float32x2,
404-
offset: 24,
405-
shader_location: 2,
406-
},
407-
],
408-
)
409-
};
389+
fn specialize(&self, cache: &RenderPipelineCache, key: Self::Key) -> RenderPipelineDescriptor {
390+
let vertex_layout = cache
391+
.vertex_layout_cache
392+
.get(&VertexLayoutKey::from(key))
393+
.unwrap();
394+
410395
let mut shader_defs = Vec::new();
411396
if key.contains(MeshPipelineKey::VERTEX_TANGENTS) {
412397
shader_defs.push(String::from("VERTEX_TANGENTS"));
@@ -433,11 +418,7 @@ impl SpecializedPipeline for MeshPipeline {
433418
shader: MESH_SHADER_HANDLE.typed::<Shader>(),
434419
entry_point: "vertex".into(),
435420
shader_defs: shader_defs.clone(),
436-
buffers: vec![VertexBufferLayout {
437-
array_stride: vertex_array_stride,
438-
step_mode: VertexStepMode::Vertex,
439-
attributes: vertex_attributes,
440-
}],
421+
buffers: vec![vertex_layout.clone()],
441422
},
442423
fragment: Some(FragmentState {
443424
shader: MESH_SHADER_HANDLE.typed::<Shader>(),

pipelined/bevy_pbr2/src/render/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,8 @@ pub struct PbrPipelineKey {
191191
impl SpecializedPipeline for PbrPipeline {
192192
type Key = PbrPipelineKey;
193193

194-
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
195-
let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key);
194+
fn specialize(&self, cache: &RenderPipelineCache, key: Self::Key) -> RenderPipelineDescriptor {
195+
let mut descriptor = self.mesh_pipeline.specialize(cache, key.mesh_key);
196196
descriptor.fragment.as_mut().unwrap().shader = PBR_SHADER_HANDLE.typed::<Shader>();
197197
descriptor.layout = Some(vec![
198198
self.mesh_pipeline.view_layout.clone(),
@@ -256,11 +256,8 @@ pub fn queue_meshes(
256256
mesh_key,
257257
normal_map: material.has_normal_map,
258258
};
259-
if let Some(mesh) = render_meshes.get(mesh_handle) {
260-
if mesh.has_tangents {
261-
pbr_key.mesh_key |= MeshPipelineKey::VERTEX_TANGENTS;
262-
}
263-
}
259+
let mesh = render_meshes.get(mesh_handle).unwrap();
260+
pbr_key.mesh_key |= MeshPipelineKey::from(mesh.vertex_layout_key);
264261

265262
if let AlphaMode::Blend = material.alpha_mode {
266263
pbr_key.mesh_key |= MeshPipelineKey::TRANSPARENT_MAIN_PASS

0 commit comments

Comments
 (0)