Skip to content

Commit 3188e5a

Browse files
pcwaltonmockersf
andauthored
Batch skinned meshes on platforms where storage buffers are available. (#16599)
This commit makes skinned meshes batchable on platforms other than WebGL 2. On supported platforms, it replaces the two uniform buffers used for joint matrices with a pair of storage buffers containing all matrices for all skinned meshes packed together. The indices into the buffer are stored in the mesh uniform and mesh input uniform. The GPU mesh preprocessing step copies the indices in if that step is enabled. On the `many_foxes` demo, I observed a frame time decrease from 15.470ms to 11.935ms. This is the result of reducing the `submit_graph_commands` time from an average of 5.45ms to 0.489ms, an 11x speedup in that portion of rendering. ![Screenshot 2024-12-01 192838](https://github.com/user-attachments/assets/7d2db997-8939-466e-8b9e-050d4a6a78ee) This is what the profile looks like for `many_foxes` after these changes. ![Screenshot 2024-12-01 193026](https://github.com/user-attachments/assets/68983fc3-01b8-41fd-835e-3d93cb65d0fa) --------- Co-authored-by: François Mockers <[email protected]>
1 parent 7ed1f32 commit 3188e5a

File tree

11 files changed

+236
-72
lines changed

11 files changed

+236
-72
lines changed

crates/bevy_pbr/src/meshlet/instance_manager.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,14 @@ impl InstanceManager {
120120
return;
121121
};
122122

123-
let mesh_uniform = MeshUniform::new(&transforms, 0, mesh_material_binding_id.slot, None);
123+
let mesh_uniform = MeshUniform::new(
124+
&transforms,
125+
0,
126+
mesh_material_binding_id.slot,
127+
None,
128+
None,
129+
None,
130+
);
124131

125132
// Append instance data
126133
self.instances.push((

crates/bevy_pbr/src/prepass/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ pub struct PrepassPipeline<M: Material> {
253253
pub deferred_material_vertex_shader: Option<Handle<Shader>>,
254254
pub deferred_material_fragment_shader: Option<Handle<Shader>>,
255255
pub material_pipeline: MaterialPipeline<M>,
256+
257+
/// Whether skins will use uniform buffers on account of storage buffers
258+
/// being unavailable on this platform.
259+
pub skins_use_uniform_buffers: bool,
260+
256261
pub depth_clip_control_supported: bool,
257262
_marker: PhantomData<M>,
258263
}
@@ -345,6 +350,7 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
345350
},
346351
material_layout: M::bind_group_layout(render_device),
347352
material_pipeline: world.resource::<MaterialPipeline<M>>().clone(),
353+
skins_use_uniform_buffers: skin::skins_use_uniform_buffers(render_device),
348354
depth_clip_control_supported,
349355
_marker: PhantomData,
350356
}
@@ -521,6 +527,7 @@ where
521527
&key.mesh_key,
522528
&mut shader_defs,
523529
&mut vertex_attributes,
530+
self.skins_use_uniform_buffers,
524531
);
525532
bind_group_layouts.insert(1, bind_group);
526533

crates/bevy_pbr/src/prepass/prepass.wgsl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
6969
let mesh_world_from_local = mesh_functions::get_world_from_local(vertex_no_morph.instance_index);
7070

7171
#ifdef SKINNED
72-
var world_from_local = skinning::skin_model(vertex.joint_indices, vertex.joint_weights);
72+
var world_from_local = skinning::skin_model(
73+
vertex.joint_indices,
74+
vertex.joint_weights,
75+
vertex_no_morph.instance_index
76+
);
7377
#else // SKINNED
7478
// Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
7579
// See https://github.com/gfx-rs/naga/issues/2416
@@ -142,6 +146,7 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
142146
let prev_model = skinning::skin_prev_model(
143147
prev_vertex.joint_indices,
144148
prev_vertex.joint_weights,
149+
vertex_no_morph.instance_index
145150
);
146151
#else // HAS_PREVIOUS_SKIN
147152
let prev_model = mesh_functions::get_previous_world_from_local(prev_vertex.instance_index);

0 commit comments

Comments
 (0)