Optimize LBVH Construction using Bottom-up Build#230
Conversation
- Replace top-down split search with a single bottom-up pass (Apetrei 2014) to build the hierarchy and bounding boxes simultaneously - Update `ConstructionInfo` to track range endpoints instead of parent indices - Add Catch2 benchmarks for `LBVH::build` performance testing
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #230 +/- ##
==========================================
- Coverage 95.84% 95.84% -0.01%
==========================================
Files 160 160
Lines 16611 16589 -22
Branches 923 918 -5
==========================================
- Hits 15921 15899 -22
Misses 690 690
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR optimizes LBVH construction by switching from the prior top-down split search / two-pass approach to a single-pass bottom-up build (Apetrei 2014), while also adding benchmarks to measure LBVH::build performance.
Changes:
- Replaced hierarchy construction with a bottom-up, single-pass algorithm that builds internal nodes and bounding boxes simultaneously.
- Updated
ConstructionInfoto track subtree key-range endpoints (left/right) instead of parent indices. - Added Catch2 benchmark coverage for
LBVH::buildacross several meshes/scenes.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| tests/src/tests/broad_phase/test_lbvh.cpp | Adds Catch2 benchmarks to measure LBVH::build performance on multiple scenes. |
| src/ipc/broad_phase/lbvh.hpp | Updates construction metadata to store subtree range endpoints used by bottom-up build. |
| src/ipc/broad_phase/lbvh.cpp | Implements the Apetrei 2014 bottom-up build, including root swapping to preserve traversal assumptions. |
Comments suppressed due to low confidence (1)
src/ipc/broad_phase/lbvh.cpp:269
std::atomic::operator++defaults tomemory_order_seq_cst, which is typically more expensive than needed for this arrival gate in a performance-critical build. Consider switching tofetch_add(1, std::memory_order_acq_rel)(or equivalent) so (1) the memory ordering is explicit for correctness of publishing the child pointer/range/AABB data, and (2) you avoid the stronger global ordering constraints of seq_cst.
if (info.visitation_count++ == 0) {
// this is the first thread that arrived at this
// node -> finished
break;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Change `root_idx` to `std::atomic<int>` to prevent data races during parallel initialization - Safely assign the root node using `compare_exchange_strong` - Clarify `code_i` parameter in `delta` function documentation
Description
ConstructionInfoto track range endpoints instead of parent indicesLBVH::buildperformance testingFixes # (issue)

The single-pass bottom-up construction of Apetrei [2014] is up to 10% faster than the two-pass construction of Karras [2012]. Benchmarked on Apple M3 Pro with 11 cores.
Type of change