Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ else()
endif()
add_subdirectory (montecarlo)
if(geom)
add_subdirectory (builtins/bvh) # hard coded builtin for geom/geom TODO mv to full builtin ROOT build option
add_subdirectory (geom)
endif()
if(NOT WIN32)
Expand Down
1 change: 1 addition & 0 deletions README/ReleaseNotes/v642/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The `TMVA_SOFIE_GNN` tutorials have been migrated to this workflow and produce i
* The header `Rpair.h` is deprecated and will be removed after ROOT 6.44, use `<utility>` instead.
* The header `Hparam.h` and `Hoption.h` are now deprecated and will be removed in ROOT 6.44, use instead `THistPainter`, `TGraph2DPainter` public interfaces.
* The headers `Htypes.h` and `Gtypes.h` that were deprecated in ROOT 6.20 will now emit warnings and will be fully removed in ROOT 6.44. Use instead `Rtypes.h`.
* The headers of the `bvh` library in `Geom` are no longer public in ROOT 6.42.
* The header `GLConstants.h` is no longer part of ROOT installed headers.
* The header `Bswapcpy.h` is deprecated and will be removed from the public interface after ROOT 6.44, it's an implementation detail for Unix i386 GNUC used by TBufferFile.
* The header `VectorizedTMath.h` is deprecated and will be removed in ROOT 6.44. Use instead `TMathVectorized.h`.
Expand Down
21 changes: 21 additions & 0 deletions builtins/bvh/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.21)
project(bvh VERSION 2.0)

option(BVH_BUILD_C_API "Builds the C API library wrapper" OFF)
option(BVH_C_API_STATIC_LINK_STDLIB "Link the C API library statically against the standard C++ library (only supported by clang/gcc)" OFF)
option(BVH_C_API_UNSAFE_CASTS "Enable unsafe casts in C API" OFF)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

add_subdirectory(src/bvh/v2)

if (PROJECT_IS_TOP_LEVEL)
include(CTest)
if (BUILD_TESTING)
add_subdirectory(test)
endif()

include(cmake/Install.cmake)
endif()
16 changes: 16 additions & 0 deletions builtins/bvh/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Copyright 2022 Arsène Pérard-Gayot

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
83 changes: 83 additions & 0 deletions builtins/bvh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# BVH Construction and Traversal Library

![Build Status](https://github.com/madmann91/bvh/workflows/build-and-test/badge.svg)

> Note: This is the 2nd version of this library. Check the `v1` branch for the older, first version
> of this library.

This library is a small, standalone library for BVH construction and traversal. It is licensed
under the MIT license.

![Example rendering generated by a path tracer using this library](render.jpg)
(Scene by Blend Swap user MaTTeSr, available [here](https://www.blendswap.com/blend/18762),
distributed under CC-BY 3.0)

## Performance

Here is a comparison of this library with other alternatives
([Embree](https://github.com/embree/embree),
[Fast-BVH](https://github.com/brandonpelfrey/Fast-BVH), and
[nanort](https://github.com/lighttransport/nanort)):

![Performance comparison with Embree, nanort, and Fast-BVH](chart.png)

## Features

Here is a list of features supported by this library (changes from `v1` are indicated with [NEW]):

- [NEW] C++20 interface using `std::span` instead of raw pointers,
- Low-level API with direct access to various builders,
- [NEW] High-level `DefaultBuilder` API which selects the best builder depending on the desired
BVH quality level.
- High-quality, single-threaded sweeping SAH builder,
- Fast, medium-quality, single-threaded binned SAH builder inspired by
"On Fast Construction of SAH-based Bounding Volume Hierarchies", by I. Wald,
- Fast, high-quality, multithreaded mini-tree BVH builder inspired by
"Rapid Bounding Volume Hierarchy Generation using Mini Trees", by P. Ganestam et al.,
- Reinsertion optimizer based on "Parallel Reinsertion for Bounding Volume Hierarchy
Optimization", by D. Meister and J. Bittner,
- Fast and robust traversal algorithm using "Robust BVH Ray Traversal", by T. Ize.
- Fast ray-triangle intersection algorithm based on
"Fast, Minimum Storage Ray/Triangle Intersection", by T. Möller and B. Trumbore,
- [NEW] Surface area traversal order heuristic for shadow rays based on
"SATO: Surface Area Traversal Order for Shadow Ray Tracing", by J. Nah and D. Manocha,
- Fast ray-sphere intersection routine,
- [NEW] Serialization/deserialization interface,
- [NEW] Variable amount of dimensions (e.g. 2D, 3D, 4D BVHs are supported) and different scalar types
(e.g. `float` or `double`),
- [NEW] Only depends on the standard library (parallelization uses a custom thread pool based on
`std::thread`),
- [NEW] C API for the high-level parts of the library is available.

## Building

This library is header-only, and can be added as a CMake subproject by cloning or adding as this
repository as submodule, for instance in `<your-project>/contrib/bvh`, and then adding this to
`<your-project>/CMakeLists.txt`:

add_subdirectory(contrib/bvh)
target_link_library(my_project PUBLIC bvh)

If you want to build the examples, use:

mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=<Debug|Release> -DENABLE_TESTING=ON
cmake --build .

## C API

The library can be used via a small set of high-level C bindings. These bindings are not enabled by
default, but can be built by configuring CMake with `-DBVH_BUILD_C_API=ON`. Additionally, if the
intent is to use the library in a pure C environment which does not have the C++ standard library as
a dependency, it might be a good idea to statically the C++ standard library. That can be done by
adding the flag `-DBVH_STATIC_LINK_STDLIB_C_API=ON` to the CMake command line.

## Usage

The library contains several examples that are kept up-to-date with the API:

- A [basic example](test/simple_example.cpp) that traces one ray on a scene made of a couple of triangles,
- A [benchmarking utility](test/benchmark.cpp) that showcases what the library can do.
- A [serialization test](test/serialize.cpp) that shows how to save and load a BVH from a file.
- A [C API example](test/c_api_example.c) that shows how to use the C bindings to this library.
44 changes: 44 additions & 0 deletions builtins/bvh/cmake/Install.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
include(GNUInstallDirs)
set(bvh_targets bvh)
if (BVH_BUILD_C_API)
list(APPEND bvh_targets bvh_c)
endif()

install(
DIRECTORY ${PROJECT_SOURCE_DIR}/src/bvh
DESTINATION include
FILES_MATCHING PATTERN "*.h"
PATTERN "c_api" EXCLUDE)
install(
FILES ${PROJECT_SOURCE_DIR}/src/bvh/v2/c_api/bvh.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bvh/v2/c_api/)
install(
TARGETS ${bvh_targets}
EXPORT bvh_exports
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(
EXPORT bvh_exports
FILE bvh-targets.cmake
NAMESPACE bvh::v2::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/bvh/v2/)

include(CMakePackageConfigHelpers)
set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/bvh/v2/)

configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/bvh-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/bvh-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_CMAKEDIR})

write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/bvh-config-version.cmake"
COMPATIBILITY AnyNewerVersion)

install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/bvh-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/bvh-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_CMAKEDIR})
5 changes: 5 additions & 0 deletions builtins/bvh/cmake/bvh-config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/bvh-targets.cmake")

check_required_components(bvh_c)
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ target_include_directories(bvh INTERFACE

set_target_properties(bvh PROPERTIES CXX_STANDARD 20)

install(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
DESTINATION include/bvh/v2
FILES_MATCHING PATTERN "*.h"
PATTERN "c_api" EXCLUDE)
add_library(bvh::bvh ALIAS bvh)

if (BVH_BUILD_C_API)
add_subdirectory(c_api)
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class BinnedSahBuilder : public TopDownSahBuilder<Node> {
public:
using typename TopDownSahBuilder<Node>::Config;

BVH_ALWAYS_INLINE static Bvh<Node> build(
[[nodiscard]] BVH_ALWAYS_INLINE static Bvh<Node> build(
std::span<const BBox> bboxes,
std::span<const Vec> centers,
const Config& config = {})
Expand Down
50 changes: 24 additions & 26 deletions geom/geom/inc/bvh/v2/bvh.h → builtins/bvh/src/bvh/v2/bvh.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,8 @@

Bvh& operator = (Bvh&&) = default;

//bool operator == (const Bvh& other) const = default;
//bool operator != (const Bvh& other) const = default;
bool operator == (const Bvh& other) const {
return other.nodes == nodes && other.prim_ids == prim_ids;
}
bool operator != (const Bvh& other) const {
return other.nodes != nodes || other.prim_ids != prim_ids;
}
bool operator == (const Bvh& other) const = default;

Check failure on line 30 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / alma10

defaulted ‘bool bvh::v2::Bvh<Node>::operator==(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 30 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / ubuntu2404 CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator==(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 30 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / alma9 CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator==(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 30 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / ubuntu22 imt=Off, CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator==(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’
bool operator != (const Bvh& other) const = default;

Check failure on line 31 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / alma10

defaulted ‘bool bvh::v2::Bvh<Node>::operator!=(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 31 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / ubuntu2404 CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator!=(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 31 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / alma9 CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator!=(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

Check failure on line 31 in builtins/bvh/src/bvh/v2/bvh.h

View workflow job for this annotation

GitHub Actions / ubuntu22 imt=Off, CMAKE_BUILD_TYPE=Debug

defaulted ‘bool bvh::v2::Bvh<Node>::operator!=(const bvh::v2::Bvh<Node>&) const’ only available with ‘-std=c++20’ or ‘-std=gnu++20’

/// Returns whether the node located at the given index is the left child of its parent.
static BVH_ALWAYS_INLINE bool is_left_sibling(size_t node_id) { return node_id % 2 == 1; }
Expand All @@ -60,11 +54,11 @@
BVH_ALWAYS_INLINE const Node& get_root() const { return nodes[0]; }

/// Extracts the BVH rooted at the given node index.
inline Bvh extract_bvh(size_t root_id) const;
[[nodiscard]] inline Bvh extract_bvh(size_t root_id) const;

/// Traverses the BVH from the given index in `start` using the provided stack. Every leaf
/// encountered on the way is processed using the given `LeafFn` function, and every pair of
/// nodes is processed with the function in `HitFn`, which returns a triplet of booleans
/// nodes is processed with the function in `InnerFn`, which returns a triplet of booleans
/// indicating whether the first child should be processed, whether the second child should be
/// processed, and whether to traverse the second child first instead of the other way around.
template <bool IsAnyHit, typename Stack, typename LeafFn, typename InnerFn>
Expand All @@ -87,8 +81,11 @@
template <typename LeafFn = IgnoreArgs>
inline void refit(LeafFn&& = {});

template <typename IndexType = typename Index::Type>
inline void serialize(OutputStream&) const;
static inline Bvh deserialize(InputStream&);

template <typename IndexType = typename Index::Type>
[[nodiscard]] static inline Bvh deserialize(InputStream&);
};

template <typename Node>
Expand Down Expand Up @@ -146,12 +143,10 @@
stack.push(far_index);
}
top = near_index;
} else if (hit_right) {
} else if (hit_right)
top = right.index;
}
else [[unlikely]] {
else [[unlikely]]
goto restart;
}
}

[[maybe_unused]] auto was_hit = leaf_fn(top.first_id(), top.first_id() + top.prim_count());
Expand All @@ -165,18 +160,19 @@
template <bool IsAnyHit, bool IsRobust, typename Stack, typename LeafFn, typename InnerFn>
void Bvh<Node>::intersect(const Ray& ray, Index start, Stack& stack, LeafFn&& leaf_fn, InnerFn&& inner_fn) const {
auto inv_dir = ray.template get_inv_dir<!IsRobust>();
auto inv_dir_pad_or_inv_org = IsRobust ? ray.pad_inv_dir(inv_dir) : -inv_dir * ray.org;
auto inv_org = -inv_dir * ray.org;
auto inv_dir_pad = ray.pad_inv_dir(inv_dir);
auto octant = ray.get_octant();

traverse_top_down<IsAnyHit>(start, stack, leaf_fn, [&] (const Node& left, const Node& right) {
inner_fn(left, right);
std::pair<Scalar, Scalar> intr_left, intr_right;
if constexpr (IsRobust) {
intr_left = left .intersect_robust(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
intr_right = right.intersect_robust(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
intr_left = left .intersect_robust(ray, inv_dir, inv_dir_pad, octant);
intr_right = right.intersect_robust(ray, inv_dir, inv_dir_pad, octant);
} else {
intr_left = left .intersect_fast(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
intr_right = right.intersect_fast(ray, inv_dir, inv_dir_pad_or_inv_org, octant);
intr_left = left .intersect_fast(ray, inv_dir, inv_org, octant);
intr_right = right.intersect_fast(ray, inv_dir, inv_org, octant);
}
return std::make_tuple(
intr_left.first <= intr_left.second,
Expand Down Expand Up @@ -222,24 +218,26 @@
}

template <typename Node>
template <typename IndexType>
void Bvh<Node>::serialize(OutputStream& stream) const {
stream.write(nodes.size());
stream.write(prim_ids.size());
stream.write(static_cast<IndexType>(nodes.size()));
stream.write(static_cast<IndexType>(prim_ids.size()));
for (auto&& node : nodes)
node.serialize(stream);
for (auto&& prim_id : prim_ids)
stream.write(prim_id);
stream.write(static_cast<IndexType>(prim_id));
}

template <typename Node>
template <typename IndexType>
Bvh<Node> Bvh<Node>::deserialize(InputStream& stream) {
Bvh bvh;
bvh.nodes.resize(stream.read<size_t>());
bvh.prim_ids.resize(stream.read<size_t>());
bvh.nodes.resize(stream.read<IndexType>());
bvh.prim_ids.resize(stream.read<IndexType>());
for (auto& node : bvh.nodes)
node = Node::deserialize(stream);
for (auto& prim_id : bvh.prim_ids)
prim_id = stream.read<size_t>();
prim_id = stream.read<IndexType>();
return bvh;
}

Expand Down
19 changes: 19 additions & 0 deletions builtins/bvh/src/bvh/v2/c_api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
add_library(bvh_c SHARED bvh.cpp)
target_link_libraries(bvh_c PRIVATE bvh)
target_compile_definitions(bvh_c PRIVATE -DBVH_BUILD_API)
target_include_directories(bvh_c INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>)
set_target_properties(bvh_c PROPERTIES
CXX_STANDARD 20
CXX_VISIBILITY_PRESET hidden
INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)

if (BVH_C_API_STATIC_LINK_STDLIB)
# Link statically against standard C++ library
target_link_options(bvh_c PRIVATE $<$<C_COMPILER_ID:GNU,Clang>:-static-libstdc++>)
endif()

if (BVH_C_API_UNSAFE_CASTS)
target_compile_definitions(bvh_c PRIVATE -DBVH_C_API_UNSAFE_CASTS)
endif()
28 changes: 28 additions & 0 deletions builtins/bvh/src/bvh/v2/c_api/bvh.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <bvh/v2/c_api/bvh.h>
#include <bvh/v2/c_api/bvh_impl.h>
#include <bvh/v2/thread_pool.h>

namespace bvh::v2::c_api {

BVH_TYPES(float, 2, 2f)
BVH_TYPES(float, 3, 3f)
BVH_TYPES(double, 2, 2d)
BVH_TYPES(double, 3, 3d)

extern "C" {

BVH_EXPORT struct bvh_thread_pool* bvh_thread_pool_create(size_t thread_count) {
return reinterpret_cast<bvh_thread_pool*>(new bvh::v2::ThreadPool(thread_count));
}

BVH_EXPORT void bvh_thread_pool_destroy(bvh_thread_pool* thread_pool) {
return delete reinterpret_cast<bvh::v2::ThreadPool*>(thread_pool);
}

BVH_IMPL(float, 2, 2f)
BVH_IMPL(float, 3, 3f)
BVH_IMPL(double, 2, 2d)
BVH_IMPL(double, 3, 3d)

} // extern "C"
} // namespace bvh::v2::c_api
Loading
Loading