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  frame time from 3.34ms to 3 ms, ~ 10%  `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
This commit is contained in:
parent
11e43860d8
commit
04aedf12fa
@ -12,7 +12,7 @@ use bevy_core_pipeline::{
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::{QueryItem, ROQueryItem},
|
||||
query::ROQueryItem,
|
||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||
};
|
||||
use bevy_math::{Affine3, Rect, UVec2, Vec4};
|
||||
@ -476,9 +476,6 @@ impl MeshPipeline {
|
||||
|
||||
impl GetBatchData for MeshPipeline {
|
||||
type Param = (SRes<RenderMeshInstances>, SRes<RenderLightmaps>);
|
||||
type Data = Entity;
|
||||
type Filter = With<Mesh3d>;
|
||||
|
||||
// The material bind group ID, the mesh ID, and the lightmap ID,
|
||||
// respectively.
|
||||
type CompareData = (MaterialBindGroupId, AssetId<Mesh>, Option<AssetId<Image>>);
|
||||
@ -487,14 +484,12 @@ impl GetBatchData for MeshPipeline {
|
||||
|
||||
fn get_batch_data(
|
||||
(mesh_instances, lightmaps): &SystemParamItem<Self::Param>,
|
||||
entity: &QueryItem<Self::Data>,
|
||||
) -> (Self::BufferData, Option<Self::CompareData>) {
|
||||
let mesh_instance = mesh_instances
|
||||
.get(entity)
|
||||
.expect("Failed to find render mesh instance");
|
||||
let maybe_lightmap = lightmaps.render_lightmaps.get(entity);
|
||||
entity: Entity,
|
||||
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
|
||||
let mesh_instance = mesh_instances.get(&entity)?;
|
||||
let maybe_lightmap = lightmaps.render_lightmaps.get(&entity);
|
||||
|
||||
(
|
||||
Some((
|
||||
MeshUniform::new(
|
||||
&mesh_instance.transforms,
|
||||
maybe_lightmap.map(|lightmap| lightmap.uv_rect),
|
||||
@ -504,7 +499,7 @@ impl GetBatchData for MeshPipeline {
|
||||
mesh_instance.mesh_asset_id,
|
||||
maybe_lightmap.map(|lightmap| lightmap.image),
|
||||
)),
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
prelude::Res,
|
||||
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
||||
system::{Query, ResMut, StaticSystemParam, SystemParam, SystemParamItem},
|
||||
};
|
||||
use bevy_utils::nonmax::NonMaxU32;
|
||||
@ -57,8 +57,6 @@ impl<T: PartialEq> BatchMeta<T> {
|
||||
/// items.
|
||||
pub trait GetBatchData {
|
||||
type Param: SystemParam + 'static;
|
||||
type Data: ReadOnlyQueryData;
|
||||
type Filter: QueryFilter;
|
||||
/// Data used for comparison between phase items. If the pipeline id, draw
|
||||
/// function id, per-instance data buffer dynamic offset and this data
|
||||
/// matches, the draws can be batched.
|
||||
@ -72,8 +70,8 @@ pub trait GetBatchData {
|
||||
/// for the `CompareData`.
|
||||
fn get_batch_data(
|
||||
param: &SystemParamItem<Self::Param>,
|
||||
query_item: &QueryItem<Self::Data>,
|
||||
) -> (Self::BufferData, Option<Self::CompareData>);
|
||||
query_item: Entity,
|
||||
) -> Option<(Self::BufferData, Option<Self::CompareData>)>;
|
||||
}
|
||||
|
||||
/// Batch the items in a render phase. This means comparing metadata needed to draw each phase item
|
||||
@ -81,16 +79,13 @@ pub trait GetBatchData {
|
||||
pub fn batch_and_prepare_render_phase<I: CachedRenderPipelinePhaseItem, F: GetBatchData>(
|
||||
gpu_array_buffer: ResMut<GpuArrayBuffer<F::BufferData>>,
|
||||
mut views: Query<&mut RenderPhase<I>>,
|
||||
query: Query<F::Data, F::Filter>,
|
||||
param: StaticSystemParam<F::Param>,
|
||||
) {
|
||||
let gpu_array_buffer = gpu_array_buffer.into_inner();
|
||||
let system_param_item = param.into_inner();
|
||||
|
||||
let mut process_item = |item: &mut I| {
|
||||
let batch_query_item = query.get(item.entity()).ok()?;
|
||||
|
||||
let (buffer_data, compare_data) = F::get_batch_data(&system_param_item, &batch_query_item);
|
||||
let (buffer_data, compare_data) = F::get_batch_data(&system_param_item, item.entity())?;
|
||||
let buffer_index = gpu_array_buffer.push(buffer_data);
|
||||
|
||||
let index = buffer_index.index.get();
|
||||
|
||||
@ -5,7 +5,7 @@ use bevy_core_pipeline::core_2d::Transparent2d;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::{QueryItem, ROQueryItem},
|
||||
query::ROQueryItem,
|
||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||
};
|
||||
use bevy_math::{Affine3, Vec4};
|
||||
@ -339,25 +339,21 @@ impl Mesh2dPipeline {
|
||||
|
||||
impl GetBatchData for Mesh2dPipeline {
|
||||
type Param = SRes<RenderMesh2dInstances>;
|
||||
type Data = Entity;
|
||||
type Filter = With<Mesh2d>;
|
||||
type CompareData = (Material2dBindGroupId, AssetId<Mesh>);
|
||||
type BufferData = Mesh2dUniform;
|
||||
|
||||
fn get_batch_data(
|
||||
mesh_instances: &SystemParamItem<Self::Param>,
|
||||
entity: &QueryItem<Self::Data>,
|
||||
) -> (Self::BufferData, Option<Self::CompareData>) {
|
||||
let mesh_instance = mesh_instances
|
||||
.get(entity)
|
||||
.expect("Failed to find render mesh2d instance");
|
||||
(
|
||||
entity: Entity,
|
||||
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
|
||||
let mesh_instance = mesh_instances.get(&entity)?;
|
||||
Some((
|
||||
(&mesh_instance.transforms).into(),
|
||||
mesh_instance.automatic_batching.then_some((
|
||||
mesh_instance.material_bind_group_id,
|
||||
mesh_instance.mesh_asset_id,
|
||||
)),
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user