Skip to content

Commit 64d1f94

Browse files
superdumpProfLander
authored andcommitted
Fix performance regression with shadow mapping (bevyengine#7914)
# Objective - @mockersf identified a performance regression of about 25% longer frame times introduced by bevyengine#7784 in a complex scene with the Amazon Lumberyard bistro scene with both exterior and interior variants and a number of point lights with shadow mapping enabled - The additional time seemed to be spent in the `ShadowPassNode` - `ShadowPassNode` encodes the draw commands for the shadow phase. Roughly the same numbers of entities were having draw commands encoded, so something about the way they were being encoded had changed. - One thing that definitely changed was that the pipeline used will be different depending on the alpha mode, and the scene has lots entities with opaque and blend materials. This suggested that maybe the pipeline was changing a lot so I tried a quick hack to see if it was the problem. ## Solution - Sort the shadow phase items by their pipeline id - This groups phase items by their pipeline id, which significantly reduces pipeline rebinding required to the point that the performance regression was gone.
1 parent 6a30c78 commit 64d1f94

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

crates/bevy_pbr/src/render/light.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use bevy_render::{
2626
Extract,
2727
};
2828
use bevy_transform::{components::GlobalTransform, prelude::Transform};
29-
use bevy_utils::FloatOrd;
3029
use bevy_utils::{
3130
tracing::{error, warn},
3231
HashMap,
@@ -1653,7 +1652,7 @@ pub struct Shadow {
16531652
}
16541653

16551654
impl PhaseItem for Shadow {
1656-
type SortKey = FloatOrd;
1655+
type SortKey = usize;
16571656

16581657
#[inline]
16591658
fn entity(&self) -> Entity {
@@ -1662,7 +1661,7 @@ impl PhaseItem for Shadow {
16621661

16631662
#[inline]
16641663
fn sort_key(&self) -> Self::SortKey {
1665-
FloatOrd(self.distance)
1664+
self.pipeline.id()
16661665
}
16671666

16681667
#[inline]
@@ -1672,7 +1671,10 @@ impl PhaseItem for Shadow {
16721671

16731672
#[inline]
16741673
fn sort(items: &mut [Self]) {
1675-
radsort::sort_by_key(items, |item| item.distance);
1674+
// The shadow phase is sorted by pipeline id for performance reasons.
1675+
// Grouping all draw commands using the same pipeline together performs
1676+
// better than rebinding everything at a high rate.
1677+
radsort::sort_by_key(items, |item| item.pipeline.id());
16761678
}
16771679
}
16781680

crates/bevy_render/src/render_resource/pipeline_cache.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ pub struct CachedRenderPipelineId(CachedPipelineId);
5656
impl CachedRenderPipelineId {
5757
/// An invalid cached render pipeline index, often used to initialize a variable.
5858
pub const INVALID: Self = CachedRenderPipelineId(usize::MAX);
59+
60+
#[inline]
61+
pub fn id(&self) -> usize {
62+
self.0
63+
}
5964
}
6065

6166
/// Index of a cached compute pipeline in a [`PipelineCache`].
@@ -65,6 +70,11 @@ pub struct CachedComputePipelineId(CachedPipelineId);
6570
impl CachedComputePipelineId {
6671
/// An invalid cached compute pipeline index, often used to initialize a variable.
6772
pub const INVALID: Self = CachedComputePipelineId(usize::MAX);
73+
74+
#[inline]
75+
pub fn id(&self) -> usize {
76+
self.0
77+
}
6878
}
6979

7080
pub struct CachedPipeline {

0 commit comments

Comments
 (0)