Skip to content

Commit 04aedf1

Browse files
authored
optimize batch_and_prepare_render_phase (#11323)
# Objective - since #9685 ,bevy introduce automatic batching of draw commands, - `batch_and_prepare_render_phase` take the responsibility for batching `phaseItem`, - `GetBatchData` trait is used for indentify each phaseitem how to batch. it defines a associated type `Data `used for Query to fetch data from world. - however,the impl of `GetBatchData ` in bevy always set ` type Data=Entity` then we acually get following code `let entity:Entity =query.get(item.entity())` that cause unnecessary overhead . ## Solution - remove associated type `Data ` and `Filter` from `GetBatchData `, - change the type of the `query_item ` parameter in get_batch_data from` Self::Data` to `Entity`. - `batch_and_prepare_render_phase ` no longer takes a query using `F::Data, F::Filter` - `get_batch_data `now returns `Option<(Self::BufferData, Option<Self::CompareData>)>` --- ## Performance based in main merged with #11290 Window 11 ,Intel 13400kf, NV 4070Ti ![image](https://github.com/bevyengine/bevy/assets/45868716/f63b9d98-6aee-4057-a2c7-a2162b2db765) frame time from 3.34ms to 3 ms, ~ 10% ![image](https://github.com/bevyengine/bevy/assets/45868716/a06eea9c-f79e-4324-8392-8d321560c5ba) `batch_and_prepare_render_phase` from 800us ~ 400 us ## Migration Guide trait `GetBatchData` no longer hold associated type `Data `and `Filter` `get_batch_data` `query_item `type from `Self::Data` to `Entity` and return `Option<(Self::BufferData, Option<Self::CompareData>)>` `batch_and_prepare_render_phase` should not have a query
1 parent 11e4386 commit 04aedf1

File tree

3 files changed

+17
-31
lines changed

3 files changed

+17
-31
lines changed

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use bevy_core_pipeline::{
1212
use bevy_derive::{Deref, DerefMut};
1313
use bevy_ecs::{
1414
prelude::*,
15-
query::{QueryItem, ROQueryItem},
15+
query::ROQueryItem,
1616
system::{lifetimeless::*, SystemParamItem, SystemState},
1717
};
1818
use bevy_math::{Affine3, Rect, UVec2, Vec4};
@@ -476,9 +476,6 @@ impl MeshPipeline {
476476

477477
impl GetBatchData for MeshPipeline {
478478
type Param = (SRes<RenderMeshInstances>, SRes<RenderLightmaps>);
479-
type Data = Entity;
480-
type Filter = With<Mesh3d>;
481-
482479
// The material bind group ID, the mesh ID, and the lightmap ID,
483480
// respectively.
484481
type CompareData = (MaterialBindGroupId, AssetId<Mesh>, Option<AssetId<Image>>);
@@ -487,14 +484,12 @@ impl GetBatchData for MeshPipeline {
487484

488485
fn get_batch_data(
489486
(mesh_instances, lightmaps): &SystemParamItem<Self::Param>,
490-
entity: &QueryItem<Self::Data>,
491-
) -> (Self::BufferData, Option<Self::CompareData>) {
492-
let mesh_instance = mesh_instances
493-
.get(entity)
494-
.expect("Failed to find render mesh instance");
495-
let maybe_lightmap = lightmaps.render_lightmaps.get(entity);
487+
entity: Entity,
488+
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
489+
let mesh_instance = mesh_instances.get(&entity)?;
490+
let maybe_lightmap = lightmaps.render_lightmaps.get(&entity);
496491

497-
(
492+
Some((
498493
MeshUniform::new(
499494
&mesh_instance.transforms,
500495
maybe_lightmap.map(|lightmap| lightmap.uv_rect),
@@ -504,7 +499,7 @@ impl GetBatchData for MeshPipeline {
504499
mesh_instance.mesh_asset_id,
505500
maybe_lightmap.map(|lightmap| lightmap.image),
506501
)),
507-
)
502+
))
508503
}
509504
}
510505

crates/bevy_render/src/batching/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bevy_ecs::{
22
component::Component,
3+
entity::Entity,
34
prelude::Res,
4-
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
55
system::{Query, ResMut, StaticSystemParam, SystemParam, SystemParamItem},
66
};
77
use bevy_utils::nonmax::NonMaxU32;
@@ -57,8 +57,6 @@ impl<T: PartialEq> BatchMeta<T> {
5757
/// items.
5858
pub trait GetBatchData {
5959
type Param: SystemParam + 'static;
60-
type Data: ReadOnlyQueryData;
61-
type Filter: QueryFilter;
6260
/// Data used for comparison between phase items. If the pipeline id, draw
6361
/// function id, per-instance data buffer dynamic offset and this data
6462
/// matches, the draws can be batched.
@@ -72,25 +70,22 @@ pub trait GetBatchData {
7270
/// for the `CompareData`.
7371
fn get_batch_data(
7472
param: &SystemParamItem<Self::Param>,
75-
query_item: &QueryItem<Self::Data>,
76-
) -> (Self::BufferData, Option<Self::CompareData>);
73+
query_item: Entity,
74+
) -> Option<(Self::BufferData, Option<Self::CompareData>)>;
7775
}
7876

7977
/// Batch the items in a render phase. This means comparing metadata needed to draw each phase item
8078
/// and trying to combine the draws into a batch.
8179
pub fn batch_and_prepare_render_phase<I: CachedRenderPipelinePhaseItem, F: GetBatchData>(
8280
gpu_array_buffer: ResMut<GpuArrayBuffer<F::BufferData>>,
8381
mut views: Query<&mut RenderPhase<I>>,
84-
query: Query<F::Data, F::Filter>,
8582
param: StaticSystemParam<F::Param>,
8683
) {
8784
let gpu_array_buffer = gpu_array_buffer.into_inner();
8885
let system_param_item = param.into_inner();
8986

9087
let mut process_item = |item: &mut I| {
91-
let batch_query_item = query.get(item.entity()).ok()?;
92-
93-
let (buffer_data, compare_data) = F::get_batch_data(&system_param_item, &batch_query_item);
88+
let (buffer_data, compare_data) = F::get_batch_data(&system_param_item, item.entity())?;
9489
let buffer_index = gpu_array_buffer.push(buffer_data);
9590

9691
let index = buffer_index.index.get();

crates/bevy_sprite/src/mesh2d/mesh.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bevy_core_pipeline::core_2d::Transparent2d;
55
use bevy_derive::{Deref, DerefMut};
66
use bevy_ecs::{
77
prelude::*,
8-
query::{QueryItem, ROQueryItem},
8+
query::ROQueryItem,
99
system::{lifetimeless::*, SystemParamItem, SystemState},
1010
};
1111
use bevy_math::{Affine3, Vec4};
@@ -339,25 +339,21 @@ impl Mesh2dPipeline {
339339

340340
impl GetBatchData for Mesh2dPipeline {
341341
type Param = SRes<RenderMesh2dInstances>;
342-
type Data = Entity;
343-
type Filter = With<Mesh2d>;
344342
type CompareData = (Material2dBindGroupId, AssetId<Mesh>);
345343
type BufferData = Mesh2dUniform;
346344

347345
fn get_batch_data(
348346
mesh_instances: &SystemParamItem<Self::Param>,
349-
entity: &QueryItem<Self::Data>,
350-
) -> (Self::BufferData, Option<Self::CompareData>) {
351-
let mesh_instance = mesh_instances
352-
.get(entity)
353-
.expect("Failed to find render mesh2d instance");
354-
(
347+
entity: Entity,
348+
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
349+
let mesh_instance = mesh_instances.get(&entity)?;
350+
Some((
355351
(&mesh_instance.transforms).into(),
356352
mesh_instance.automatic_batching.then_some((
357353
mesh_instance.material_bind_group_id,
358354
mesh_instance.mesh_asset_id,
359355
)),
360-
)
356+
))
361357
}
362358
}
363359

0 commit comments

Comments
 (0)