perf(render): skip redundant draw-order rebuilds
Docs Deploy / Build and Deploy MkDocs (push) Successful in 40s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 40s
This commit is contained in:
1 file changed
+189
-4
@@ -762,7 +762,9 @@ impl VulkanSmokeRenderer {
|
|||||||
apply_geometry_range_updates(
|
apply_geometry_range_updates(
|
||||||
&mut self.draw_ranges,
|
&mut self.draw_ranges,
|
||||||
&mut self.draw_range_capacities,
|
&mut self.draw_range_capacities,
|
||||||
|
&self.draw_range_world_queue,
|
||||||
geometry_ranges,
|
geometry_ranges,
|
||||||
|
&mut self.draw_order_dirty,
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -882,6 +884,19 @@ impl VulkanSmokeRenderer {
|
|||||||
context: "dynamic draw range index is out of bounds",
|
context: "dynamic draw range index is out of bounds",
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let world_queue = self
|
||||||
|
.draw_range_world_queue
|
||||||
|
.get(range_index)
|
||||||
|
.copied()
|
||||||
|
.ok_or(VulkanSmokeRendererError::InvalidStaticMesh {
|
||||||
|
context: "dynamic draw range index is out of bounds",
|
||||||
|
})?;
|
||||||
|
mark_draw_order_dirty_on_activity_change(
|
||||||
|
world_queue,
|
||||||
|
range.index_count,
|
||||||
|
index_count,
|
||||||
|
&mut self.draw_order_dirty,
|
||||||
|
);
|
||||||
range.index_count = index_count;
|
range.index_count = index_count;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1017,8 +1032,11 @@ impl VulkanSmokeRenderer {
|
|||||||
// Calling this setter opts the range into the world queue. Fixed
|
// Calling this setter opts the range into the world queue. Fixed
|
||||||
// screen/sky/weather ranges remain `None` because their pass order is
|
// screen/sky/weather ranges remain `None` because their pass order is
|
||||||
// intentionally owned by the caller.
|
// intentionally owned by the caller.
|
||||||
self.draw_range_world_queue[range_index] = Some(transparent);
|
set_and_mark_dirty_if_changed(
|
||||||
self.draw_order_dirty = true;
|
&mut self.draw_range_world_queue[range_index],
|
||||||
|
Some(transparent),
|
||||||
|
&mut self.draw_order_dirty,
|
||||||
|
);
|
||||||
if pipeline_changed {
|
if pipeline_changed {
|
||||||
self.rebuild_pipeline_resources()?;
|
self.rebuild_pipeline_resources()?;
|
||||||
}
|
}
|
||||||
@@ -1047,8 +1065,7 @@ impl VulkanSmokeRenderer {
|
|||||||
context: "dynamic draw range index is out of bounds",
|
context: "dynamic draw range index is out of bounds",
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
*key = Some(sort_key);
|
set_and_mark_dirty_if_changed(key, Some(sort_key), &mut self.draw_order_dirty);
|
||||||
self.draw_order_dirty = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2300,13 +2317,21 @@ fn validate_geometry_upload(
|
|||||||
fn apply_geometry_range_updates(
|
fn apply_geometry_range_updates(
|
||||||
ranges: &mut [super::VulkanStaticDrawRange],
|
ranges: &mut [super::VulkanStaticDrawRange],
|
||||||
capacities: &mut [u32],
|
capacities: &mut [u32],
|
||||||
|
world_queues: &[Option<bool>],
|
||||||
geometry_ranges: &[super::VulkanDynamicDrawRange],
|
geometry_ranges: &[super::VulkanDynamicDrawRange],
|
||||||
|
draw_order_dirty: &mut bool,
|
||||||
) {
|
) {
|
||||||
for geometry in geometry_ranges {
|
for geometry in geometry_ranges {
|
||||||
// `validate_geometry_upload` has already checked every handle. Keep
|
// `validate_geometry_upload` has already checked every handle. Keep
|
||||||
// this helper infallible so state is changed only after the Vulkan
|
// this helper infallible so state is changed only after the Vulkan
|
||||||
// upload succeeds.
|
// upload succeeds.
|
||||||
let range = &mut ranges[geometry.range_index];
|
let range = &mut ranges[geometry.range_index];
|
||||||
|
mark_draw_order_dirty_on_activity_change(
|
||||||
|
world_queues[geometry.range_index],
|
||||||
|
range.index_count,
|
||||||
|
geometry.index_count,
|
||||||
|
draw_order_dirty,
|
||||||
|
);
|
||||||
range.first_index = geometry.first_index;
|
range.first_index = geometry.first_index;
|
||||||
range.index_count = geometry.index_count;
|
range.index_count = geometry.index_count;
|
||||||
// A moved segment no longer owns the old tail. Keeping the previous
|
// A moved segment no longer owns the old tail. Keeping the previous
|
||||||
@@ -2469,11 +2494,36 @@ fn sorted_world_draw_order(
|
|||||||
next_without_transparency
|
next_without_transparency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_and_mark_dirty_if_changed<T: PartialEq>(
|
||||||
|
current: &mut T,
|
||||||
|
next: T,
|
||||||
|
draw_order_dirty: &mut bool,
|
||||||
|
) {
|
||||||
|
if *current == next {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*current = next;
|
||||||
|
*draw_order_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_draw_order_dirty_on_activity_change(
|
||||||
|
world_queue: Option<bool>,
|
||||||
|
current_index_count: u32,
|
||||||
|
next_index_count: u32,
|
||||||
|
draw_order_dirty: &mut bool,
|
||||||
|
) {
|
||||||
|
let active_changed = (current_index_count == 0) != (next_index_count == 0);
|
||||||
|
if world_queue.is_some() && active_changed {
|
||||||
|
*draw_order_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::{VulkanDynamicDrawRange, VulkanStaticDrawRange, VulkanStaticMesh};
|
use super::super::{VulkanDynamicDrawRange, VulkanStaticDrawRange, VulkanStaticMesh};
|
||||||
use super::{
|
use super::{
|
||||||
apply_geometry_range_updates, apply_world_transparency, completed_readback_buffer_index,
|
apply_geometry_range_updates, apply_world_transparency, completed_readback_buffer_index,
|
||||||
|
mark_draw_order_dirty_on_activity_change, set_and_mark_dirty_if_changed,
|
||||||
sorted_world_draw_order, take_runtime_children_with_validation_snapshot,
|
sorted_world_draw_order, take_runtime_children_with_validation_snapshot,
|
||||||
take_runtime_owners_in_dependency_order, validate_geometry_upload,
|
take_runtime_owners_in_dependency_order, validate_geometry_upload,
|
||||||
world_material_pipeline_states, RollbackOnDrop,
|
world_material_pipeline_states, RollbackOnDrop,
|
||||||
@@ -2598,14 +2648,17 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let original = ranges[0];
|
let original = ranges[0];
|
||||||
let mut capacities = vec![3, 3];
|
let mut capacities = vec![3, 3];
|
||||||
|
let mut draw_order_dirty = false;
|
||||||
apply_geometry_range_updates(
|
apply_geometry_range_updates(
|
||||||
&mut ranges,
|
&mut ranges,
|
||||||
&mut capacities,
|
&mut capacities,
|
||||||
|
&[None, None],
|
||||||
&[VulkanDynamicDrawRange {
|
&[VulkanDynamicDrawRange {
|
||||||
range_index: 1,
|
range_index: 1,
|
||||||
first_index: 3,
|
first_index: 3,
|
||||||
index_count: 9,
|
index_count: 9,
|
||||||
}],
|
}],
|
||||||
|
&mut draw_order_dirty,
|
||||||
);
|
);
|
||||||
assert_eq!(ranges[0], original);
|
assert_eq!(ranges[0], original);
|
||||||
assert_eq!(capacities, vec![3, 9]);
|
assert_eq!(capacities, vec![3, 9]);
|
||||||
@@ -2615,11 +2668,13 @@ mod tests {
|
|||||||
apply_geometry_range_updates(
|
apply_geometry_range_updates(
|
||||||
&mut ranges,
|
&mut ranges,
|
||||||
&mut capacities,
|
&mut capacities,
|
||||||
|
&[None, None],
|
||||||
&[VulkanDynamicDrawRange {
|
&[VulkanDynamicDrawRange {
|
||||||
range_index: 1,
|
range_index: 1,
|
||||||
first_index: 3,
|
first_index: 3,
|
||||||
index_count: 3,
|
index_count: 3,
|
||||||
}],
|
}],
|
||||||
|
&mut draw_order_dirty,
|
||||||
);
|
);
|
||||||
assert_eq!(ranges[0], original);
|
assert_eq!(ranges[0], original);
|
||||||
assert_eq!(capacities, vec![3, 3]);
|
assert_eq!(capacities, vec![3, 3]);
|
||||||
@@ -2647,6 +2702,72 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn geometry_updates_dirty_world_order_on_activation_and_deactivation() {
|
||||||
|
let mut ranges = [VulkanStaticDrawRange {
|
||||||
|
first_index: 0,
|
||||||
|
index_count: 0,
|
||||||
|
material_index: 0,
|
||||||
|
lightmap_index: u8::MAX,
|
||||||
|
batch_flags: 0,
|
||||||
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
|
alpha_test_reference: 0,
|
||||||
|
}];
|
||||||
|
let mut capacities = [6];
|
||||||
|
let world_queues = [Some(true)];
|
||||||
|
let mut draw_order_dirty = false;
|
||||||
|
|
||||||
|
apply_geometry_range_updates(
|
||||||
|
&mut ranges,
|
||||||
|
&mut capacities,
|
||||||
|
&world_queues,
|
||||||
|
&[VulkanDynamicDrawRange {
|
||||||
|
range_index: 0,
|
||||||
|
first_index: 0,
|
||||||
|
index_count: 3,
|
||||||
|
}],
|
||||||
|
&mut draw_order_dirty,
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
draw_order_dirty,
|
||||||
|
"activating the queued range changes order"
|
||||||
|
);
|
||||||
|
|
||||||
|
draw_order_dirty = false;
|
||||||
|
apply_geometry_range_updates(
|
||||||
|
&mut ranges,
|
||||||
|
&mut capacities,
|
||||||
|
&world_queues,
|
||||||
|
&[VulkanDynamicDrawRange {
|
||||||
|
range_index: 0,
|
||||||
|
first_index: 0,
|
||||||
|
index_count: 6,
|
||||||
|
}],
|
||||||
|
&mut draw_order_dirty,
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!draw_order_dirty,
|
||||||
|
"changing an active count does not change order"
|
||||||
|
);
|
||||||
|
|
||||||
|
apply_geometry_range_updates(
|
||||||
|
&mut ranges,
|
||||||
|
&mut capacities,
|
||||||
|
&world_queues,
|
||||||
|
&[VulkanDynamicDrawRange {
|
||||||
|
range_index: 0,
|
||||||
|
first_index: 0,
|
||||||
|
index_count: 0,
|
||||||
|
}],
|
||||||
|
&mut draw_order_dirty,
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
draw_order_dirty,
|
||||||
|
"deactivating the queued range changes order"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_owners_drop_remaining_children_after_partial_init_failures() {
|
fn runtime_owners_drop_remaining_children_after_partial_init_failures() {
|
||||||
let cases = [
|
let cases = [
|
||||||
@@ -2852,6 +2973,70 @@ mod tests {
|
|||||||
assert_eq!(order, vec![2, 3, 1, 0]);
|
assert_eq!(order, vec![2, 3, 1, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unchanged_sort_keys_and_transparency_do_not_dirty_draw_order() {
|
||||||
|
let mut sort_key = None;
|
||||||
|
let mut draw_order_dirty = false;
|
||||||
|
|
||||||
|
set_and_mark_dirty_if_changed(&mut sort_key, Some(3.0), &mut draw_order_dirty);
|
||||||
|
assert_eq!(sort_key, Some(3.0));
|
||||||
|
assert!(draw_order_dirty);
|
||||||
|
|
||||||
|
draw_order_dirty = false;
|
||||||
|
set_and_mark_dirty_if_changed(&mut sort_key, Some(3.0), &mut draw_order_dirty);
|
||||||
|
assert_eq!(sort_key, Some(3.0));
|
||||||
|
assert!(!draw_order_dirty);
|
||||||
|
|
||||||
|
set_and_mark_dirty_if_changed(&mut sort_key, Some(4.0), &mut draw_order_dirty);
|
||||||
|
assert_eq!(sort_key, Some(4.0));
|
||||||
|
assert!(draw_order_dirty);
|
||||||
|
|
||||||
|
let mut transparent = None;
|
||||||
|
draw_order_dirty = false;
|
||||||
|
set_and_mark_dirty_if_changed(&mut transparent, Some(true), &mut draw_order_dirty);
|
||||||
|
assert_eq!(transparent, Some(true));
|
||||||
|
assert!(draw_order_dirty);
|
||||||
|
|
||||||
|
draw_order_dirty = false;
|
||||||
|
set_and_mark_dirty_if_changed(&mut transparent, Some(true), &mut draw_order_dirty);
|
||||||
|
assert_eq!(transparent, Some(true));
|
||||||
|
assert!(!draw_order_dirty);
|
||||||
|
|
||||||
|
set_and_mark_dirty_if_changed(&mut transparent, Some(false), &mut draw_order_dirty);
|
||||||
|
assert_eq!(transparent, Some(false));
|
||||||
|
assert!(draw_order_dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn world_draw_order_dirties_on_activation_and_deactivation() {
|
||||||
|
let mut draw_order_dirty = false;
|
||||||
|
|
||||||
|
mark_draw_order_dirty_on_activity_change(None, 0, 6, &mut draw_order_dirty);
|
||||||
|
assert!(
|
||||||
|
!draw_order_dirty,
|
||||||
|
"fixed pass slots keep their original order"
|
||||||
|
);
|
||||||
|
|
||||||
|
mark_draw_order_dirty_on_activity_change(Some(true), 0, 6, &mut draw_order_dirty);
|
||||||
|
assert!(
|
||||||
|
draw_order_dirty,
|
||||||
|
"activating a queued range changes its order"
|
||||||
|
);
|
||||||
|
|
||||||
|
draw_order_dirty = false;
|
||||||
|
mark_draw_order_dirty_on_activity_change(Some(false), 6, 12, &mut draw_order_dirty);
|
||||||
|
assert!(
|
||||||
|
!draw_order_dirty,
|
||||||
|
"changing an active count does not change order"
|
||||||
|
);
|
||||||
|
|
||||||
|
mark_draw_order_dirty_on_activity_change(Some(true), 6, 0, &mut draw_order_dirty);
|
||||||
|
assert!(
|
||||||
|
draw_order_dirty,
|
||||||
|
"deactivating a queued range changes its order"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tree_canopy_queue_follows_sky_and_precedes_foreground_effects() {
|
fn tree_canopy_queue_follows_sky_and_precedes_foreground_effects() {
|
||||||
const SCREEN_GRADIENT: usize = 0;
|
const SCREEN_GRADIENT: usize = 0;
|
||||||
|
|||||||
Reference in new issue
Block a user