Skip to content

Commit 5f05e75

Browse files
authored
Fix 2D BatchedInstanceBuffer clear (#12922)
# Objective - `cargo run --release --example bevymark -- --benchmark --waves 160 --per-wave 1000 --mode mesh2d` runs slower and slower over time due to `no_gpu_preprocessing::write_batched_instance_buffer<bevy_sprite::mesh2d::mesh::Mesh2dPipeline>` taking longer and longer because the `BatchedInstanceBuffer` is not cleared ## Solution - Split the `clear_batched_instance_buffers` system into CPU and GPU versions - Use the CPU version for 2D meshes
1 parent 62f2a73 commit 5f05e75

File tree

5 files changed

+49
-31
lines changed

5 files changed

+49
-31
lines changed

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use bevy_ecs::{
1515
use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4};
1616
use bevy_render::{
1717
batching::{
18-
clear_batched_instance_buffers, gpu_preprocessing, no_gpu_preprocessing, GetBatchData,
19-
GetFullBatchData, NoAutomaticBatching,
18+
gpu_preprocessing, no_gpu_preprocessing, GetBatchData, GetFullBatchData,
19+
NoAutomaticBatching,
2020
},
2121
mesh::*,
2222
render_asset::RenderAssets,
@@ -139,10 +139,14 @@ impl Plugin for MeshRenderPlugin {
139139
.init_resource::<SkinIndices>()
140140
.init_resource::<MorphUniform>()
141141
.init_resource::<MorphIndices>()
142-
.add_systems(ExtractSchedule, (extract_skins, extract_morphs))
143142
.add_systems(
144143
ExtractSchedule,
145-
clear_batched_instance_buffers::<MeshPipeline>.before(ExtractMeshesSet),
144+
(
145+
extract_skins,
146+
extract_morphs,
147+
gpu_preprocessing::clear_batched_gpu_instance_buffers::<MeshPipeline>
148+
.before(ExtractMeshesSet),
149+
),
146150
)
147151
.add_systems(
148152
Render,
@@ -151,6 +155,9 @@ impl Plugin for MeshRenderPlugin {
151155
prepare_morphs.in_set(RenderSet::PrepareResources),
152156
prepare_mesh_bind_group.in_set(RenderSet::PrepareBindGroups),
153157
prepare_mesh_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
158+
no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<MeshPipeline>
159+
.in_set(RenderSet::Cleanup)
160+
.after(RenderSet::Render),
154161
),
155162
);
156163
}

crates/bevy_render/src/batching/gpu_preprocessing.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,28 @@ where
125125
}
126126
}
127127

128+
/// A system that runs early in extraction and clears out all the
129+
/// [`BatchedInstanceBuffers`] for the frame.
130+
///
131+
/// We have to run this during extraction because, if GPU preprocessing is in
132+
/// use, the extraction phase will write to the mesh input uniform buffers
133+
/// directly, so the buffers need to be cleared before then.
134+
pub fn clear_batched_gpu_instance_buffers<GFBD>(
135+
gpu_batched_instance_buffers: Option<
136+
ResMut<BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
137+
>,
138+
) where
139+
GFBD: GetFullBatchData,
140+
{
141+
if let Some(mut gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
142+
gpu_batched_instance_buffers.clear();
143+
}
144+
}
145+
128146
/// A system that removes GPU preprocessing work item buffers that correspond to
129147
/// deleted [`ViewTarget`]s.
130148
///
131-
/// This is a separate system from [`super::clear_batched_instance_buffers`]
149+
/// This is a separate system from [`clear_batched_gpu_instance_buffers`]
132150
/// because [`ViewTarget`]s aren't created until after the extraction phase is
133151
/// completed.
134152
pub fn delete_old_work_item_buffers<GFBD>(

crates/bevy_render/src/batching/mod.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bevy_ecs::{
22
component::Component,
33
entity::Entity,
4-
system::{Query, ResMut, SystemParam, SystemParamItem},
4+
system::{Query, SystemParam, SystemParamItem},
55
};
66
use bytemuck::Pod;
77
use nonmax::NonMaxU32;
@@ -135,30 +135,6 @@ pub trait GetFullBatchData: GetBatchData {
135135
) -> Option<NonMaxU32>;
136136
}
137137

138-
/// A system that runs early in extraction and clears out all the
139-
/// [`gpu_preprocessing::BatchedInstanceBuffers`] for the frame.
140-
///
141-
/// We have to run this during extraction because, if GPU preprocessing is in
142-
/// use, the extraction phase will write to the mesh input uniform buffers
143-
/// directly, so the buffers need to be cleared before then.
144-
pub fn clear_batched_instance_buffers<GFBD>(
145-
cpu_batched_instance_buffer: Option<
146-
ResMut<no_gpu_preprocessing::BatchedInstanceBuffer<GFBD::BufferData>>,
147-
>,
148-
gpu_batched_instance_buffers: Option<
149-
ResMut<gpu_preprocessing::BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
150-
>,
151-
) where
152-
GFBD: GetFullBatchData,
153-
{
154-
if let Some(mut cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
155-
cpu_batched_instance_buffer.clear();
156-
}
157-
if let Some(mut gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
158-
gpu_batched_instance_buffers.clear();
159-
}
160-
}
161-
162138
/// Sorts a render phase that uses bins.
163139
pub fn sort_binned_render_phase<BPI>(mut views: Query<&mut BinnedRenderPhase<BPI>>)
164140
where

crates/bevy_render/src/batching/no_gpu_preprocessing.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ where
4343
}
4444
}
4545

46+
/// A system that clears out the [`BatchedInstanceBuffer`] for the frame.
47+
///
48+
/// This needs to run before the CPU batched instance buffers are used.
49+
pub fn clear_batched_cpu_instance_buffers<GBD>(
50+
cpu_batched_instance_buffer: Option<ResMut<BatchedInstanceBuffer<GBD::BufferData>>>,
51+
) where
52+
GBD: GetBatchData,
53+
{
54+
if let Some(mut cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
55+
cpu_batched_instance_buffer.clear();
56+
}
57+
}
58+
4659
/// Batch the items in a sorted render phase, when GPU instance buffer building
4760
/// isn't in use. This means comparing metadata needed to draw each phase item
4861
/// and trying to combine the draws into a batch.

crates/bevy_sprite/src/mesh2d/mesh.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use bevy_ecs::{
1212
use bevy_math::{Affine3, Vec4};
1313
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
1414
use bevy_render::batching::no_gpu_preprocessing::{
15-
batch_and_prepare_sorted_render_phase, write_batched_instance_buffer, BatchedInstanceBuffer,
15+
self, batch_and_prepare_sorted_render_phase, write_batched_instance_buffer,
16+
BatchedInstanceBuffer,
1617
};
1718
use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef};
1819
use bevy_render::{
@@ -107,6 +108,9 @@ impl Plugin for Mesh2dRenderPlugin {
107108
.in_set(RenderSet::PrepareResourcesFlush),
108109
prepare_mesh2d_bind_group.in_set(RenderSet::PrepareBindGroups),
109110
prepare_mesh2d_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
111+
no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<Mesh2dPipeline>
112+
.in_set(RenderSet::Cleanup)
113+
.after(RenderSet::Render),
110114
),
111115
);
112116
}

0 commit comments

Comments
 (0)