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
This commit is contained in:
parent
62f2a73cac
commit
5f05e75a70
@ -15,8 +15,8 @@ use bevy_ecs::{
|
|||||||
use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4};
|
use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
batching::{
|
batching::{
|
||||||
clear_batched_instance_buffers, gpu_preprocessing, no_gpu_preprocessing, GetBatchData,
|
gpu_preprocessing, no_gpu_preprocessing, GetBatchData, GetFullBatchData,
|
||||||
GetFullBatchData, NoAutomaticBatching,
|
NoAutomaticBatching,
|
||||||
},
|
},
|
||||||
mesh::*,
|
mesh::*,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
@ -139,10 +139,14 @@ impl Plugin for MeshRenderPlugin {
|
|||||||
.init_resource::<SkinIndices>()
|
.init_resource::<SkinIndices>()
|
||||||
.init_resource::<MorphUniform>()
|
.init_resource::<MorphUniform>()
|
||||||
.init_resource::<MorphIndices>()
|
.init_resource::<MorphIndices>()
|
||||||
.add_systems(ExtractSchedule, (extract_skins, extract_morphs))
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
ExtractSchedule,
|
ExtractSchedule,
|
||||||
clear_batched_instance_buffers::<MeshPipeline>.before(ExtractMeshesSet),
|
(
|
||||||
|
extract_skins,
|
||||||
|
extract_morphs,
|
||||||
|
gpu_preprocessing::clear_batched_gpu_instance_buffers::<MeshPipeline>
|
||||||
|
.before(ExtractMeshesSet),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
@ -151,6 +155,9 @@ impl Plugin for MeshRenderPlugin {
|
|||||||
prepare_morphs.in_set(RenderSet::PrepareResources),
|
prepare_morphs.in_set(RenderSet::PrepareResources),
|
||||||
prepare_mesh_bind_group.in_set(RenderSet::PrepareBindGroups),
|
prepare_mesh_bind_group.in_set(RenderSet::PrepareBindGroups),
|
||||||
prepare_mesh_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
|
prepare_mesh_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
|
||||||
|
no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<MeshPipeline>
|
||||||
|
.in_set(RenderSet::Cleanup)
|
||||||
|
.after(RenderSet::Render),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -125,10 +125,28 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A system that runs early in extraction and clears out all the
|
||||||
|
/// [`BatchedInstanceBuffers`] for the frame.
|
||||||
|
///
|
||||||
|
/// We have to run this during extraction because, if GPU preprocessing is in
|
||||||
|
/// use, the extraction phase will write to the mesh input uniform buffers
|
||||||
|
/// directly, so the buffers need to be cleared before then.
|
||||||
|
pub fn clear_batched_gpu_instance_buffers<GFBD>(
|
||||||
|
gpu_batched_instance_buffers: Option<
|
||||||
|
ResMut<BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
|
||||||
|
>,
|
||||||
|
) where
|
||||||
|
GFBD: GetFullBatchData,
|
||||||
|
{
|
||||||
|
if let Some(mut gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
|
||||||
|
gpu_batched_instance_buffers.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A system that removes GPU preprocessing work item buffers that correspond to
|
/// A system that removes GPU preprocessing work item buffers that correspond to
|
||||||
/// deleted [`ViewTarget`]s.
|
/// deleted [`ViewTarget`]s.
|
||||||
///
|
///
|
||||||
/// This is a separate system from [`super::clear_batched_instance_buffers`]
|
/// This is a separate system from [`clear_batched_gpu_instance_buffers`]
|
||||||
/// because [`ViewTarget`]s aren't created until after the extraction phase is
|
/// because [`ViewTarget`]s aren't created until after the extraction phase is
|
||||||
/// completed.
|
/// completed.
|
||||||
pub fn delete_old_work_item_buffers<GFBD>(
|
pub fn delete_old_work_item_buffers<GFBD>(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
system::{Query, ResMut, SystemParam, SystemParamItem},
|
system::{Query, SystemParam, SystemParamItem},
|
||||||
};
|
};
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
use nonmax::NonMaxU32;
|
use nonmax::NonMaxU32;
|
||||||
@ -135,30 +135,6 @@ pub trait GetFullBatchData: GetBatchData {
|
|||||||
) -> Option<NonMaxU32>;
|
) -> Option<NonMaxU32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A system that runs early in extraction and clears out all the
|
|
||||||
/// [`gpu_preprocessing::BatchedInstanceBuffers`] for the frame.
|
|
||||||
///
|
|
||||||
/// We have to run this during extraction because, if GPU preprocessing is in
|
|
||||||
/// use, the extraction phase will write to the mesh input uniform buffers
|
|
||||||
/// directly, so the buffers need to be cleared before then.
|
|
||||||
pub fn clear_batched_instance_buffers<GFBD>(
|
|
||||||
cpu_batched_instance_buffer: Option<
|
|
||||||
ResMut<no_gpu_preprocessing::BatchedInstanceBuffer<GFBD::BufferData>>,
|
|
||||||
>,
|
|
||||||
gpu_batched_instance_buffers: Option<
|
|
||||||
ResMut<gpu_preprocessing::BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
|
|
||||||
>,
|
|
||||||
) where
|
|
||||||
GFBD: GetFullBatchData,
|
|
||||||
{
|
|
||||||
if let Some(mut cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
|
|
||||||
cpu_batched_instance_buffer.clear();
|
|
||||||
}
|
|
||||||
if let Some(mut gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
|
|
||||||
gpu_batched_instance_buffers.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sorts a render phase that uses bins.
|
/// Sorts a render phase that uses bins.
|
||||||
pub fn sort_binned_render_phase<BPI>(mut views: Query<&mut BinnedRenderPhase<BPI>>)
|
pub fn sort_binned_render_phase<BPI>(mut views: Query<&mut BinnedRenderPhase<BPI>>)
|
||||||
where
|
where
|
||||||
|
@ -43,6 +43,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A system that clears out the [`BatchedInstanceBuffer`] for the frame.
|
||||||
|
///
|
||||||
|
/// This needs to run before the CPU batched instance buffers are used.
|
||||||
|
pub fn clear_batched_cpu_instance_buffers<GBD>(
|
||||||
|
cpu_batched_instance_buffer: Option<ResMut<BatchedInstanceBuffer<GBD::BufferData>>>,
|
||||||
|
) where
|
||||||
|
GBD: GetBatchData,
|
||||||
|
{
|
||||||
|
if let Some(mut cpu_batched_instance_buffer) = cpu_batched_instance_buffer {
|
||||||
|
cpu_batched_instance_buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Batch the items in a sorted render phase, when GPU instance buffer building
|
/// Batch the items in a sorted render phase, when GPU instance buffer building
|
||||||
/// isn't in use. This means comparing metadata needed to draw each phase item
|
/// isn't in use. This means comparing metadata needed to draw each phase item
|
||||||
/// and trying to combine the draws into a batch.
|
/// and trying to combine the draws into a batch.
|
||||||
|
@ -12,7 +12,8 @@ use bevy_ecs::{
|
|||||||
use bevy_math::{Affine3, Vec4};
|
use bevy_math::{Affine3, Vec4};
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
use bevy_render::batching::no_gpu_preprocessing::{
|
use bevy_render::batching::no_gpu_preprocessing::{
|
||||||
batch_and_prepare_sorted_render_phase, write_batched_instance_buffer, BatchedInstanceBuffer,
|
self, batch_and_prepare_sorted_render_phase, write_batched_instance_buffer,
|
||||||
|
BatchedInstanceBuffer,
|
||||||
};
|
};
|
||||||
use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef};
|
use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
@ -107,6 +108,9 @@ impl Plugin for Mesh2dRenderPlugin {
|
|||||||
.in_set(RenderSet::PrepareResourcesFlush),
|
.in_set(RenderSet::PrepareResourcesFlush),
|
||||||
prepare_mesh2d_bind_group.in_set(RenderSet::PrepareBindGroups),
|
prepare_mesh2d_bind_group.in_set(RenderSet::PrepareBindGroups),
|
||||||
prepare_mesh2d_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
|
prepare_mesh2d_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
|
||||||
|
no_gpu_preprocessing::clear_batched_cpu_instance_buffers::<Mesh2dPipeline>
|
||||||
|
.in_set(RenderSet::Cleanup)
|
||||||
|
.after(RenderSet::Render),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user