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