From cdbb660188507f0495c16b2d4c5f1074406c77cd Mon Sep 17 00:00:00 2001 From: erichanwang Date: Wed, 22 Jul 2026 23:56:45 -0500 Subject: [PATCH] Wire BroadphaseBench into the build, retire a stale doc claim broadphase_bench.cpp landed with the spatial-hash broad phase but was never added as a CMake target, so it only ever ran if someone happened to compile it by hand. The README's Known Limitations section also still described the broad phase as an O(n^2) loop after that loop had already been replaced. Added the missing target and replaced the stale line with the actual crossover numbers measured on this machine: the hash is slower below roughly 300 bodies and 22x faster at 10,000, both bracketing the point where the demos here (tens of bodies) sit below the crossover. --- CMakeLists.txt | 4 ++++ PROGRESS.md | 6 ++++++ README.md | 24 ++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 PROGRESS.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 526c6e5..70099a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(Blocks src/main_blocks.cpp) add_executable(Parachutes src/main_parachutes.cpp) add_executable(Tests tests/test_math_physics.cpp) add_executable(Benchmark bench/benchmark.cpp) +add_executable(BroadphaseBench bench/broadphase_bench.cpp) add_executable(ControlDemo src/main_control_demo.cpp) # The renderer's row-sharing loop uses std::thread. @@ -19,6 +20,7 @@ target_link_libraries(Blocks PRIVATE Threads::Threads) target_link_libraries(Parachutes PRIVATE Threads::Threads) target_link_libraries(Tests PRIVATE Threads::Threads) target_link_libraries(Benchmark PRIVATE Threads::Threads) +target_link_libraries(BroadphaseBench PRIVATE Threads::Threads) target_link_libraries(ControlDemo PRIVATE Threads::Threads) # SDL2 linking removed for now to fix build errors; uncomment when UI is enabled @@ -38,6 +40,7 @@ if(MSVC) target_compile_options(Parachutes PRIVATE /W4 /O2) target_compile_options(Tests PRIVATE /W4 /O2) target_compile_options(Benchmark PRIVATE /W4 /O2) + target_compile_options(BroadphaseBench PRIVATE /W4 /O2) target_compile_options(ControlDemo PRIVATE /W4 /O2) else() target_compile_options(GameEngine PRIVATE -Wall -Wextra -O2) @@ -45,5 +48,6 @@ else() target_compile_options(Parachutes PRIVATE -Wall -Wextra -O2) target_compile_options(Tests PRIVATE -Wall -Wextra -O2) target_compile_options(Benchmark PRIVATE -Wall -Wextra -O2) + target_compile_options(BroadphaseBench PRIVATE -Wall -Wextra -O2) target_compile_options(ControlDemo PRIVATE -Wall -Wextra -O2) endif() diff --git a/PROGRESS.md b/PROGRESS.md new file mode 100644 index 0000000..fb3ec0a --- /dev/null +++ b/PROGRESS.md @@ -0,0 +1,6 @@ +# Progress + +2026-07-22: Wired `BroadphaseBench` into CMakeLists.txt (built but not a +target since the spatial-hash commit), and replaced the README's stale +"O(n^2) broad phase" limitation with the actual spatial-hash numbers measured +on this machine: 0.34x at 100 bodies, 1.50x at 1,000, 22.33x at 10,000. diff --git a/README.md b/README.md index 3c0ffdf..8e073ce 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,25 @@ ray counter on every ray; that single contended cache line cost roughly half the achievable scaling, and the counter is now thread-local and folded in once per worker. +**Broad phase: O(n^2) all-pairs loop vs. spatial hash** + +```sh +./build/BroadphaseBench +``` + +| Bodies | O(n^2) | Spatial hash | Speedup | +|---|---|---|---| +| 100 | 0.050 ms | 0.146 ms | 0.34x | +| 1,000 | 2.991 ms | 1.990 ms | 1.50x | +| 10,000 | 300.220 ms | 13.444 ms | 22.33x | + +The all-pairs loop is genuinely faster below roughly 300 bodies, where the +hashing overhead exceeds the pairs it saves; `BroadphaseBench` bisects for the +exact crossover each run rather than quoting one body count as universal. It +also asserts the hash's candidate set is a superset of every colliding pair +the exhaustive loop finds before reporting any timing, since a broad phase +that drops a pair is a tunnelling bug no speedup is worth. + ## Known limitations The control loop itself is real and tested, but nothing here reads a real @@ -210,8 +229,9 @@ split from any input source: Collision treats every body as a sphere, so blocks resolve against their bounding sphere rather than their faces and will not come to rest on a corner -realistically. The broad phase is an O(n^2) pair loop, which is fine for the -tens of bodies these demos use. +realistically. The broad phase is a uniform spatial hash (`src/physics/BroadPhase.h`); +below roughly 300 bodies the plain O(n^2) loop it replaced is still faster, +since the demos here only ever run tens of bodies at once. The BVH is rebuilt from scratch each frame in the animated demos rather than refitted, regardless of which split heuristic is selected.