Cache opaque deferred entities so we don't have to continuously re-queue them. (#18007)
Even though opaque deferred entities aren't placed into the `Opaque3d` bin, we still want to cache them as though they were, so that we don't have to re-queue them every frame. This commit implements that logic, reducing the time of `queue_material_meshes` to near-zero on Caldera.
This commit is contained in:
parent
5d7a60592d
commit
172c020b60
@ -1036,6 +1036,11 @@ pub fn queue_material_meshes<M: Material>(
|
|||||||
}
|
}
|
||||||
RenderPhaseType::Opaque => {
|
RenderPhaseType::Opaque => {
|
||||||
if material.properties.render_method == OpaqueRendererMethod::Deferred {
|
if material.properties.render_method == OpaqueRendererMethod::Deferred {
|
||||||
|
// Even though we aren't going to insert the entity into
|
||||||
|
// a bin, we still want to update its cache entry. That
|
||||||
|
// way, we know we don't need to re-examine it in future
|
||||||
|
// frames.
|
||||||
|
opaque_phase.update_cache(*visible_entity, None, current_change_tick);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let batch_set_key = Opaque3dBatchSetKey {
|
let batch_set_key = Opaque3dBatchSetKey {
|
||||||
|
@ -148,7 +148,7 @@ where
|
|||||||
/// We retain these so that, when the entity changes,
|
/// We retain these so that, when the entity changes,
|
||||||
/// [`Self::sweep_old_entities`] can quickly find the bin it was located in
|
/// [`Self::sweep_old_entities`] can quickly find the bin it was located in
|
||||||
/// and remove it.
|
/// and remove it.
|
||||||
cached_entity_bin_keys: IndexMap<MainEntity, CachedBinKey<BPI>, EntityHash>,
|
cached_entity_bin_keys: IndexMap<MainEntity, CachedBinnedEntity<BPI>, EntityHash>,
|
||||||
|
|
||||||
/// The set of indices in [`Self::cached_entity_bin_keys`] that are
|
/// The set of indices in [`Self::cached_entity_bin_keys`] that are
|
||||||
/// confirmed to be up to date.
|
/// confirmed to be up to date.
|
||||||
@ -185,10 +185,23 @@ where
|
|||||||
/// The entity.
|
/// The entity.
|
||||||
main_entity: MainEntity,
|
main_entity: MainEntity,
|
||||||
/// The key that identifies the bin that this entity used to be in.
|
/// The key that identifies the bin that this entity used to be in.
|
||||||
old_bin_key: CachedBinKey<BPI>,
|
old_cached_binned_entity: CachedBinnedEntity<BPI>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information that we keep about an entity currently within a bin.
|
/// Information that we keep about an entity currently within a bin.
|
||||||
|
pub struct CachedBinnedEntity<BPI>
|
||||||
|
where
|
||||||
|
BPI: BinnedPhaseItem,
|
||||||
|
{
|
||||||
|
/// Information that we use to identify a cached entity in a bin.
|
||||||
|
pub cached_bin_key: Option<CachedBinKey<BPI>>,
|
||||||
|
/// The last modified tick of the entity.
|
||||||
|
///
|
||||||
|
/// We use this to detect when the entity needs to be invalidated.
|
||||||
|
pub change_tick: Tick,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information that we use to identify a cached entity in a bin.
|
||||||
pub struct CachedBinKey<BPI>
|
pub struct CachedBinKey<BPI>
|
||||||
where
|
where
|
||||||
BPI: BinnedPhaseItem,
|
BPI: BinnedPhaseItem,
|
||||||
@ -200,10 +213,18 @@ where
|
|||||||
/// The type of render phase that we use to render the entity: multidraw,
|
/// The type of render phase that we use to render the entity: multidraw,
|
||||||
/// plain batch, etc.
|
/// plain batch, etc.
|
||||||
pub phase_type: BinnedRenderPhaseType,
|
pub phase_type: BinnedRenderPhaseType,
|
||||||
/// The last modified tick of the entity.
|
}
|
||||||
///
|
|
||||||
/// We use this to detect when the entity needs to be invalidated.
|
impl<BPI> Clone for CachedBinnedEntity<BPI>
|
||||||
pub change_tick: Tick,
|
where
|
||||||
|
BPI: BinnedPhaseItem,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
CachedBinnedEntity {
|
||||||
|
cached_bin_key: self.cached_bin_key.clone(),
|
||||||
|
change_tick: self.change_tick,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BPI> Clone for CachedBinKey<BPI>
|
impl<BPI> Clone for CachedBinKey<BPI>
|
||||||
@ -215,11 +236,21 @@ where
|
|||||||
batch_set_key: self.batch_set_key.clone(),
|
batch_set_key: self.batch_set_key.clone(),
|
||||||
bin_key: self.bin_key.clone(),
|
bin_key: self.bin_key.clone(),
|
||||||
phase_type: self.phase_type,
|
phase_type: self.phase_type,
|
||||||
change_tick: self.change_tick,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<BPI> PartialEq for CachedBinKey<BPI>
|
||||||
|
where
|
||||||
|
BPI: BinnedPhaseItem,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.batch_set_key == other.batch_set_key
|
||||||
|
&& self.bin_key == other.bin_key
|
||||||
|
&& self.phase_type == other.phase_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// How we store and render the batch sets.
|
/// How we store and render the batch sets.
|
||||||
///
|
///
|
||||||
/// Each one of these corresponds to a [`GpuPreprocessingMode`].
|
/// Each one of these corresponds to a [`GpuPreprocessingMode`].
|
||||||
@ -504,27 +535,41 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_bin_key = CachedBinKey {
|
// Update the cache.
|
||||||
batch_set_key,
|
self.update_cache(
|
||||||
bin_key,
|
main_entity,
|
||||||
phase_type,
|
Some(CachedBinKey {
|
||||||
|
batch_set_key,
|
||||||
|
bin_key,
|
||||||
|
phase_type,
|
||||||
|
}),
|
||||||
|
change_tick,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts an entity into the cache with the given change tick.
|
||||||
|
pub fn update_cache(
|
||||||
|
&mut self,
|
||||||
|
main_entity: MainEntity,
|
||||||
|
cached_bin_key: Option<CachedBinKey<BPI>>,
|
||||||
|
change_tick: Tick,
|
||||||
|
) {
|
||||||
|
let new_cached_binned_entity = CachedBinnedEntity {
|
||||||
|
cached_bin_key,
|
||||||
change_tick,
|
change_tick,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (index, old_bin_key) = self
|
let (index, old_cached_binned_entity) = self
|
||||||
.cached_entity_bin_keys
|
.cached_entity_bin_keys
|
||||||
.insert_full(main_entity, new_bin_key.clone());
|
.insert_full(main_entity, new_cached_binned_entity.clone());
|
||||||
|
|
||||||
// If the entity changed bins, record its old bin so that we can remove
|
// If the entity changed bins, record its old bin so that we can remove
|
||||||
// the entity from it.
|
// the entity from it.
|
||||||
if let Some(old_bin_key) = old_bin_key {
|
if let Some(old_cached_binned_entity) = old_cached_binned_entity {
|
||||||
if old_bin_key.batch_set_key != new_bin_key.batch_set_key
|
if old_cached_binned_entity.cached_bin_key != new_cached_binned_entity.cached_bin_key {
|
||||||
|| old_bin_key.bin_key != new_bin_key.bin_key
|
|
||||||
|| old_bin_key.phase_type != new_bin_key.phase_type
|
|
||||||
{
|
|
||||||
self.entities_that_changed_bins.push(EntityThatChangedBins {
|
self.entities_that_changed_bins.push(EntityThatChangedBins {
|
||||||
main_entity,
|
main_entity,
|
||||||
old_bin_key,
|
old_cached_binned_entity,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,27 +871,35 @@ where
|
|||||||
// reverse order because `swap_remove_index` will potentially invalidate
|
// reverse order because `swap_remove_index` will potentially invalidate
|
||||||
// all indices after the one we remove.
|
// all indices after the one we remove.
|
||||||
for index in ReverseFixedBitSetZeroesIterator::new(&self.valid_cached_entity_bin_keys) {
|
for index in ReverseFixedBitSetZeroesIterator::new(&self.valid_cached_entity_bin_keys) {
|
||||||
let Some((entity, entity_bin_key)) =
|
let Some((entity, cached_binned_entity)) =
|
||||||
self.cached_entity_bin_keys.swap_remove_index(index)
|
self.cached_entity_bin_keys.swap_remove_index(index)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
remove_entity_from_bin(
|
if let Some(ref cached_bin_key) = cached_binned_entity.cached_bin_key {
|
||||||
entity,
|
remove_entity_from_bin(
|
||||||
&entity_bin_key,
|
entity,
|
||||||
&mut self.multidrawable_meshes,
|
cached_bin_key,
|
||||||
&mut self.batchable_meshes,
|
&mut self.multidrawable_meshes,
|
||||||
&mut self.unbatchable_meshes,
|
&mut self.batchable_meshes,
|
||||||
&mut self.non_mesh_items,
|
&mut self.unbatchable_meshes,
|
||||||
);
|
&mut self.non_mesh_items,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an entity changed bins, we need to remove it from its old bin.
|
// If an entity changed bins, we need to remove it from its old bin.
|
||||||
for entity_that_changed_bins in self.entities_that_changed_bins.drain(..) {
|
for entity_that_changed_bins in self.entities_that_changed_bins.drain(..) {
|
||||||
|
let Some(ref old_cached_bin_key) = entity_that_changed_bins
|
||||||
|
.old_cached_binned_entity
|
||||||
|
.cached_bin_key
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
remove_entity_from_bin(
|
remove_entity_from_bin(
|
||||||
entity_that_changed_bins.main_entity,
|
entity_that_changed_bins.main_entity,
|
||||||
&entity_that_changed_bins.old_bin_key,
|
old_cached_bin_key,
|
||||||
&mut self.multidrawable_meshes,
|
&mut self.multidrawable_meshes,
|
||||||
&mut self.batchable_meshes,
|
&mut self.batchable_meshes,
|
||||||
&mut self.unbatchable_meshes,
|
&mut self.unbatchable_meshes,
|
||||||
|
Loading…
Reference in New Issue
Block a user