Skip to content
Open
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
7 changes: 6 additions & 1 deletion kernels/builders/bvh_builder_hair.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ namespace embree
createLeaf(createLeaf),
progressMonitor(progressMonitor),
reportFinishedRange(reportFinishedRange),
alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) {}
alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims)
{
if (cfg.branchingFactor > MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
}
}

/*! checks if all primitives are from the same geometry */
__forceinline bool sameGeometry(const PrimInfoRange& range)
Expand Down
17 changes: 14 additions & 3 deletions kernels/builders/bvh_builder_morton.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ namespace embree
if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize;
if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize;

if (branchingFactor > MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
}

minLeafSize = min(minLeafSize,maxLeafSize);
}

Settings (size_t branchingFactor, size_t maxDepth, size_t minLeafSize, size_t maxLeafSize, size_t singleThreadThreshold)
: branchingFactor(branchingFactor), maxDepth(maxDepth), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize), singleThreadThreshold(singleThreadThreshold)
Settings (size_t branchingFactor_, size_t maxDepth_, size_t minLeafSize_, size_t maxLeafSize_, size_t singleThreadThreshold_)
: branchingFactor(branchingFactor_), maxDepth(maxDepth_), minLeafSize(minLeafSize_), maxLeafSize(maxLeafSize_), singleThreadThreshold(singleThreadThreshold_)
{
if (branchingFactor > MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
}
minLeafSize = min(minLeafSize,maxLeafSize);
Comment thread
johguenther marked this conversation as resolved.
}

Expand Down Expand Up @@ -203,7 +210,11 @@ namespace embree
createLeaf(createLeaf),
calculateBounds(calculateBounds),
progressMonitor(progressMonitor),
morton(nullptr) {}
morton(nullptr)
{
if (branchingFactor > MAX_BRANCHING_FACTOR)
throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
}

ReductionTy createLargeLeaf(size_t depth, const range<unsigned>& current, Allocator alloc)
{
Expand Down
7 changes: 6 additions & 1 deletion kernels/builders/bvh_builder_msmblur_hair.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ namespace embree
createLeaf(createLeaf),
progressMonitor(progressMonitor),
unalignedHeuristic(scene),
temporalSplitHeuristic(scene->device,recalculatePrimRef) {}
temporalSplitHeuristic(scene->device,recalculatePrimRef)
{
if (cfg.branchingFactor > MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
}
}

private:

Expand Down
25 changes: 25 additions & 0 deletions kernels/common/rtcore_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,31 @@ RTC_NAMESPACE_BEGIN
if (arguments->primitiveArrayCapacity < arguments->primitiveCount)
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")

if (RTC_BUILD_ARGUMENTS_HAS((*arguments),maxLeafSize) && arguments->maxLeafSize > RTC_BUILD_MAX_PRIMITIVES_PER_LEAF) {
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxLeafSize must be smaller or equal to RTC_BUILD_MAX_PRIMITIVES_PER_LEAF")
}

if (RTC_BUILD_ARGUMENTS_HAS((*arguments),maxBranchingFactor))
{
const unsigned int branchingFactor = arguments->maxBranchingFactor;
if (branchingFactor < 2) {
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor must be greater or equal to 2");
}

if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)
{
if (branchingFactor > BVHBuilderMorton::MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor too large for RTC_BUILD_QUALITY_LOW (maximum is 8)")
}
}
else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM || arguments->buildQuality == RTC_BUILD_QUALITY_HIGH)
{
if (branchingFactor > GeneralBVHBuilder::MAX_BRANCHING_FACTOR) {
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"maxBranchingFactor too large for this build quality (maximum is 16)")
}
}
}

/* initialize the allocator */
bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));
bvh->allocator.reset();
Expand Down
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ FOREACH(xml ${PRIMITIVE_TESTS})
ENDFOREACH()
ENDFOREACH()

ADD_SUBDIRECTORY(regression)


IF (EMBREE_TESTING_INSTALL_TESTS)
# test resources
Expand Down
1 change: 0 additions & 1 deletion tests/integration/test_embree_release/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,3 @@ TEST_CASE("Minimal test", "[minimal]")

REQUIRE(true);
}

10 changes: 10 additions & 0 deletions tests/regression/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2009-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

add_executable(embree_regression_morton_builder_clamp morton_builder_clamp_regression.cpp)
target_link_libraries(embree_regression_morton_builder_clamp PRIVATE embree)
set_property(TARGET embree_regression_morton_builder_clamp PROPERTY FOLDER tests/regression)

if (BUILD_TESTING)
add_test(NAME regression_morton_builder_clamp COMMAND embree_regression_morton_builder_clamp)
endif()
151 changes: 151 additions & 0 deletions tests/regression/morton_builder_clamp_regression.cpp
Comment thread
johguenther marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright 2026 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include <embree4/rtcore.h>
#include <embree4/rtcore_builder.h>

#include <cassert>
#include <cstring>
#include <iostream>
#include <limits>
#include <vector>

constexpr unsigned int max_branching_factor = 8;

struct Node
{
Node()
{
for (unsigned int i = 0; i < max_branching_factor; ++i)
children[i] = nullptr;
}
virtual ~Node() = default;
Node *children[max_branching_factor];
};

static bool buildProgress(void * /*userPtr*/, double /*f*/)
{
return true;
}

bool memoryMonitor(void * /*userPtr*/, ssize_t /*bytes*/, bool /*post*/)
{
return true;
}

static void *createNode(RTCThreadLocalAllocator alloc, unsigned int childCount, void * /*userPtr*/)
{
assert(childCount <= max_branching_factor);
if (childCount > max_branching_factor)
return nullptr;

Node *node = (Node *)rtcThreadLocalAlloc(alloc, sizeof(Node), 16);
new (node) Node();
return node;
}

static void setNodeChildren(void *nodePtr, void **children, unsigned int childCount, void * /*userPtr*/)
{
assert(childCount <= max_branching_factor);
if (childCount > max_branching_factor)
return;
Node *node = (Node *)nodePtr;
for (unsigned int i = 0; i < childCount; ++i)
node->children[i] = (Node *)children[i];
}

static void setNodeBounds(void *nodePtr, const RTCBounds **bounds, unsigned int childCount, void * /*userPtr*/)
{
assert(childCount <= max_branching_factor);
/* deliberately empty in regression test */
}

static void *createLeaf(RTCThreadLocalAllocator alloc,
const RTCBuildPrimitive *prims,
size_t primCount,
void * /*userPtr*/)
{

Node *node = (Node *)rtcThreadLocalAlloc(alloc, sizeof(Node), 16);
new (node) Node();
return node;
}

static std::vector<RTCBuildPrimitive> makeGridPrimitives(size_t primitiveCount)
{
std::vector<RTCBuildPrimitive> prims(primitiveCount);
for (size_t i = 0; i < primitiveCount; ++i)
{
const float x = float(i % 32);
const float y = float((i / 32) % 32);

RTCBuildPrimitive p{};
p.lower_x = x * 2.0f;
p.lower_y = y * 2.0f;
p.lower_z = 0.0f;
p.upper_x = p.lower_x + 0.5f;
p.upper_y = p.lower_y + 0.5f;
p.upper_z = 0.5f;
p.geomID = 0;
p.primID = (unsigned int)i;
prims[i] = p;
}
return prims;
}

static bool runCase(unsigned int maxBranchingFactor)
{
RTCDevice device = rtcNewDevice(nullptr);
if (device == nullptr)
return false;

RTCBVH bvh = rtcNewBVH(device);
if (bvh == nullptr)
{
rtcReleaseDevice(device);
return false;
}

std::vector<RTCBuildPrimitive> prims = makeGridPrimitives(1024);

RTCBuildArguments args = rtcDefaultBuildArguments();
args.byteSize = sizeof(args);
args.buildQuality = RTC_BUILD_QUALITY_LOW;
args.maxBranchingFactor = maxBranchingFactor;
args.maxDepth = 1024;
args.minLeafSize = 1;
args.maxLeafSize = 1;
args.bvh = bvh;
args.primitives = prims.data();
args.primitiveCount = prims.size();
args.primitiveArrayCapacity = prims.size();
args.createNode = createNode;
args.setNodeChildren = setNodeChildren;
args.setNodeBounds = setNodeBounds;
args.createLeaf = createLeaf;
args.buildProgress = buildProgress;

rtcGetDeviceError(device);
void *root = rtcBuildBVH(&args);
RTCError error = rtcGetDeviceError(device);

rtcReleaseBVH(bvh);
rtcReleaseDevice(device);
return root == nullptr && error == RTC_ERROR_INVALID_ARGUMENT;
}

int main()
{
bool okOversized = runCase(64);
bool okExtreme = runCase(std::numeric_limits<unsigned int>::max());

if (!okOversized) {
std::cerr << "Morton oversized maxBranchingFactor regression failed for maxBranchingFactor=64\n";
}
if (!okExtreme) {
std::cerr << "Morton oversized maxBranchingFactor regression failed for maxBranchingFactor=UINT_MAX\n";
}

std::cout << "Morton oversized branching factor regression test completed.\n";
return (okOversized && okExtreme) ? 0 : 1;
}
Loading