From 2a950f9c5a1028f7f9adb07965d2baf43f358f1e Mon Sep 17 00:00:00 2001 From: Ray Hidayat Date: Tue, 20 Jan 2026 12:11:01 +1300 Subject: [PATCH 1/4] Fix Bvh::optimize_incremental being non-deterministic when restored from a serialized snapshot, due to significant state being stored in BvhWorkspace which cannot be serialized (#402) --- src/partitioning/bvh/bvh_optimize.rs | 21 +++++++++++++++++---- src/partitioning/bvh/bvh_tree.rs | 5 +++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/partitioning/bvh/bvh_optimize.rs b/src/partitioning/bvh/bvh_optimize.rs index 974753ab..6c01e3d0 100644 --- a/src/partitioning/bvh/bvh_optimize.rs +++ b/src/partitioning/bvh/bvh_optimize.rs @@ -240,15 +240,15 @@ impl Bvh { } workspace.rebuild_leaves.clear(); - workspace.rebuild_frame_index = workspace.rebuild_frame_index.overflowing_add(1).0; - let config = self.optimization_config(workspace.rebuild_frame_index); + self.optimization.rebuild_frame_index = self.optimization.rebuild_frame_index.overflowing_add(1).0; + let config = self.optimization_config(self.optimization.rebuild_frame_index); /* * Subtree optimizations. */ // let t0 = core::time::Instant::now(); let num_leaves = self.nodes[0].leaf_count(); - let mut start_index = workspace.rebuild_start_index; + let mut start_index = self.optimization.rebuild_start_index; // println!("Max candidate leaf count = {}", max_candidate_leaf_count); self.find_optimization_roots( @@ -266,7 +266,7 @@ impl Bvh { // to reach the target subtree count. } - workspace.rebuild_start_index = start_index; + self.optimization.rebuild_start_index = start_index; // println!( // "Num refinement candidates: {}, list: {:?}", @@ -522,6 +522,19 @@ impl Bvh { } } +/// The optimization state for used by `Bvh::optimize_incremental`. +/// This allows each call to `optimize_incremental` to continue from where the last one left off. +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize) +)] +pub(super) struct BvhIncrementalOptimizationState { + pub(super) rebuild_frame_index: u32, + pub(super) rebuild_start_index: u32, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum RootOptimizationMode { PriorityQueue, diff --git a/src/partitioning/bvh/bvh_tree.rs b/src/partitioning/bvh/bvh_tree.rs index 35baba88..fd1d5cef 100644 --- a/src/partitioning/bvh/bvh_tree.rs +++ b/src/partitioning/bvh/bvh_tree.rs @@ -1,4 +1,5 @@ use super::BvhOptimizationHeapEntry; +use super::bvh_optimize::BvhIncrementalOptimizationState; use crate::bounding_volume::{Aabb, BoundingVolume}; use crate::math::{Real, Vector}; use crate::query::{Ray, RayCast}; @@ -136,8 +137,6 @@ pub enum BvhBuildStrategy { pub struct BvhWorkspace { pub(super) refit_tmp: BvhNodeVec, pub(super) rebuild_leaves: Vec, - pub(super) rebuild_frame_index: u32, - pub(super) rebuild_start_index: u32, pub(super) optimization_roots: Vec, pub(super) queue: BinaryHeap, pub(super) dequeue: VecDeque, @@ -1752,6 +1751,7 @@ pub struct Bvh { // We don’t store this in `Self::nodes` since it’s only useful for node removal. pub(super) parents: Vec, pub(super) leaf_node_indices: VecMap, + pub(super) optimization: BvhIncrementalOptimizationState, } impl Bvh { @@ -2186,6 +2186,7 @@ impl Bvh { nodes, parents, leaf_node_indices, + optimization: _, } = self; nodes.capacity() * size_of::() + parents.capacity() * size_of::() From 7d3fd2ca72066f104e4ae62f31f64a4e6724a7ce Mon Sep 17 00:00:00 2001 From: Ray Hidayat Date: Sat, 24 Jan 2026 12:32:07 +1300 Subject: [PATCH 2/4] Fix typo in BvhIncrementalOptimizationState description (#403) --- src/partitioning/bvh/bvh_optimize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partitioning/bvh/bvh_optimize.rs b/src/partitioning/bvh/bvh_optimize.rs index 6c01e3d0..766f0485 100644 --- a/src/partitioning/bvh/bvh_optimize.rs +++ b/src/partitioning/bvh/bvh_optimize.rs @@ -522,7 +522,7 @@ impl Bvh { } } -/// The optimization state for used by `Bvh::optimize_incremental`. +/// The optimization state used by `Bvh::optimize_incremental`. /// This allows each call to `optimize_incremental` to continue from where the last one left off. #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] From 5a5b4027f818e065bb0f9283a9aa6b9768f2d045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 4 Apr 2026 18:20:33 +0200 Subject: [PATCH 3/4] chore: add comment for the new optimization field --- src/partitioning/bvh/bvh_tree.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/partitioning/bvh/bvh_tree.rs b/src/partitioning/bvh/bvh_tree.rs index fd1d5cef..cb5be196 100644 --- a/src/partitioning/bvh/bvh_tree.rs +++ b/src/partitioning/bvh/bvh_tree.rs @@ -1751,6 +1751,8 @@ pub struct Bvh { // We don’t store this in `Self::nodes` since it’s only useful for node removal. pub(super) parents: Vec, pub(super) leaf_node_indices: VecMap, + // NOTE: this cannot be in the workspace as we need this to survive serialization/deserialization + // to maintain determinism. pub(super) optimization: BvhIncrementalOptimizationState, } From 0ae96d4256bf8e0513acf87246ab330c606a6167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sat, 4 Apr 2026 18:20:56 +0200 Subject: [PATCH 4/4] cargo fmt --- src/partitioning/bvh/bvh_optimize.rs | 3 ++- src/partitioning/bvh/bvh_tree.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/partitioning/bvh/bvh_optimize.rs b/src/partitioning/bvh/bvh_optimize.rs index 766f0485..38c798e7 100644 --- a/src/partitioning/bvh/bvh_optimize.rs +++ b/src/partitioning/bvh/bvh_optimize.rs @@ -240,7 +240,8 @@ impl Bvh { } workspace.rebuild_leaves.clear(); - self.optimization.rebuild_frame_index = self.optimization.rebuild_frame_index.overflowing_add(1).0; + self.optimization.rebuild_frame_index = + self.optimization.rebuild_frame_index.overflowing_add(1).0; let config = self.optimization_config(self.optimization.rebuild_frame_index); /* diff --git a/src/partitioning/bvh/bvh_tree.rs b/src/partitioning/bvh/bvh_tree.rs index cb5be196..15866fa1 100644 --- a/src/partitioning/bvh/bvh_tree.rs +++ b/src/partitioning/bvh/bvh_tree.rs @@ -1,5 +1,5 @@ -use super::BvhOptimizationHeapEntry; use super::bvh_optimize::BvhIncrementalOptimizationState; +use super::BvhOptimizationHeapEntry; use crate::bounding_volume::{Aabb, BoundingVolume}; use crate::math::{Real, Vector}; use crate::query::{Ray, RayCast};