Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
357c7a5
Clamp Morton branching factor and add regression test
stefanatwork Jul 6, 2026
55ca27c
Created regression test for morton builder clamp
stefanatwork Jul 9, 2026
9d504af
Fixed regression test
stefanatwork Jul 15, 2026
f591cf3
Renamed paramters so they wouldn't shadow members
stefanatwork Jul 15, 2026
cbe7df2
Fixed indentation
stefanatwork Jul 15, 2026
2b6ff51
Merge branch 'master' into sw/clamp_branching_factor
stefanatwork Jul 15, 2026
5011f85
Branching factor is limited in multiple places:
stefanatwork Aug 3, 2026
b92442e
Merge branch 'master' into sw/clamp_branching_factor
stefanatwork Aug 4, 2026
aaee243
Merge branch 'master' into sw/clamp_branching_factor
stefanatwork Aug 18, 2026
985b6db
Use unified regression test binary
stefanatwork Aug 18, 2026
61001f9
Add embree_regression_tests tutorial with one test case per sighting
stefanatwork Aug 12, 2026
405f4ee
Fix Sighting-01: clamp time segment range symmetrically
stefanatwork Aug 12, 2026
4596bf9
Fix Sighting-02: clamp LBBox callback time indices
stefanatwork Aug 12, 2026
1643b14
Fix Sighting-03: harden LBBox time-range clamping
stefanatwork Aug 12, 2026
c457e65
Fix Sighting-04/05: harden instance nonlinear bounds indices
stefanatwork Aug 12, 2026
7d750eb
Fix Sighting-08/09: validate instance-array IDs and instPrimID
stefanatwork Aug 12, 2026
526db23
Fix Sighting-15: clamp InstanceArray nonlinear bounds indices
stefanatwork Aug 12, 2026
bc7bb17
Fix Sighting-06: validate PrimRefMB range before leaf build
stefanatwork Aug 12, 2026
7ca89f5
Fix Sighting-07: validate user-geometry time-step ranges
stefanatwork Aug 12, 2026
66107c2
Fix Sighting-10: write ddPdudu to correct output pointer
stefanatwork Aug 12, 2026
e8f665d
Fix Sighting-11: verify subdiv topology before half-edge init
stefanatwork Aug 12, 2026
e62d157
Fix Sighting-12: prevent curve index overflow bypass
stefanatwork Aug 12, 2026
89bc4ef
Fix Sighting-13: bound recursive derivative root search
stefanatwork Aug 12, 2026
29e48b3
Fix Sighting-14: guard GridSOA leaf decode for invalid refs
stefanatwork Aug 12, 2026
b17f9d3
Fix Sighting-02/03 follow-up: use EmptyTy in LBBox empty paths
stefanatwork Aug 12, 2026
6a865a5
Fix misleading indentation in getObject guards
stefanatwork Aug 12, 2026
bdc79f3
Style: remove trailing whitespace; add braces around single-line ifs
stefanatwork Aug 12, 2026
67bc9d1
Fix: restore dropped line_offset declaration in GridSOAMBIntersector1…
stefanatwork Aug 12, 2026
6451a98
Fix Issue-02/08/12 test failures: empty bounds, ID validation order, …
stefanatwork Aug 12, 2026
44a521e
Fix Sighting-11: targeted face-vertex sum check instead of full verify()
stefanatwork Aug 12, 2026
5c507b8
Fix Sighting-11: use topology[0].verify() to guard half-edge init wit…
stefanatwork Aug 13, 2026
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
93 changes: 66 additions & 27 deletions common/math/lbbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ namespace embree

template<typename T1>
__forceinline LBBox ( const LBBox<T1>& other )
: bounds0(other.bounds0), bounds1(other.bounds1) {}
: bounds0(other.bounds0), bounds1(other.bounds1) {}

__forceinline LBBox& operator= ( const LBBox& other ) {
bounds0 = other.bounds0; bounds1 = other.bounds1; return *this;
__forceinline LBBox& operator= ( const LBBox& other ) {
bounds0 = other.bounds0; bounds1 = other.bounds1; return *this;
}

__forceinline LBBox (EmptyTy)
__forceinline LBBox (EmptyTy)
: bounds0(EmptyTy()), bounds1(EmptyTy()) {}
__forceinline explicit LBBox ( const BBox<T>& bounds)

__forceinline explicit LBBox ( const BBox<T>& bounds)
: bounds0(bounds), bounds1(bounds) { }
__forceinline LBBox ( const BBox<T>& bounds0, const BBox<T>& bounds1)

__forceinline LBBox ( const BBox<T>& bounds0, const BBox<T>& bounds1)
: bounds0(bounds0), bounds1(bounds1) { }

LBBox ( const avector<BBox<T>>& bounds )
LBBox ( const avector<BBox<T>>& bounds )
{
assert(bounds.size());
BBox<T> b0 = bounds.front();
Expand All @@ -61,12 +61,29 @@ namespace embree
template<typename BoundsFunc>
__forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range, float numTimeSegments)
{
if (!(numTimeSegments > 0.0f)) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

const float lower = time_range.lower*numTimeSegments;
const float upper = time_range.upper*numTimeSegments;
const float ilowerf = floor(lower);
const float iupperf = ceil(upper);
const int ilower = (int)ilowerf;
const int iupper = (int)iupperf;
if (!(ilowerf == ilowerf) || !(iupperf == iupperf)) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

const int ilower = (int)clamp(ilowerf, 0.0f, numTimeSegments);
const int iupper = (int)clamp(iupperf, 0.0f, numTimeSegments);
if (iupper <= ilower) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

const BBox<T> blower0 = bounds(ilower);
const BBox<T> bupper1 = bounds(iupper);
Expand Down Expand Up @@ -101,24 +118,46 @@ namespace embree
template<typename BoundsFunc>
__forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range_in, const BBox1f& geom_time_range, float geom_time_segments)
{
if (!(geom_time_segments > 0.0f) || !(geom_time_range.size() > 0.0f)) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

/* normalize global time_range_in to local geom_time_range */
const BBox1f time_range((time_range_in.lower-geom_time_range.lower)/geom_time_range.size(),
(time_range_in.upper-geom_time_range.lower)/geom_time_range.size());

const float lower = time_range.lower*geom_time_segments;
const float upper = time_range.upper*geom_time_segments;
const float ilowerf = floor(lower);
const float iupperf = ceil(upper);
const float ilowerfc = max(0.0f,ilowerf);
const float iupperfc = min(iupperf,geom_time_segments);
if (!(ilowerf == ilowerf) || !(iupperf == iupperf)) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

const float ilowerfc = clamp(ilowerf, 0.0f, geom_time_segments);
const float iupperfc = clamp(iupperf, 0.0f, geom_time_segments);
const int ilowerc = (int)ilowerfc;
const int iupperc = (int)iupperfc;
assert(iupperc-ilowerc > 0);
if (iupperc <= ilowerc) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

/* this larger iteration range guarantees that we process borders of geom_time_range is (partially) inside time_range_in */
const int ilower_iter = max(-1,(int)ilowerf);
const int iupper_iter = min((int)iupperf,(int)geom_time_segments+1);

const float iter_max = geom_time_segments + 1.0f;
const int ilower_iter = (int)clamp(ilowerf, -1.0f, iter_max);
const int iupper_iter = (int)clamp(iupperf, -1.0f, iter_max);
if (iupper_iter <= ilower_iter) {
bounds0 = EmptyTy();
bounds1 = EmptyTy();
return;
}

const BBox<T> blower0 = bounds(ilowerc);
const BBox<T> bupper1 = bounds(iupperc);
if (iupper_iter-ilower_iter == 1) {
Expand Down Expand Up @@ -163,7 +202,7 @@ namespace embree
bounds1 = b1;
return;
}

for (int i = ilower+1; i<iupper; i++)
{
const float f = float(i - time_range.begin()) / float(time_range.size());
Expand All @@ -184,7 +223,7 @@ namespace embree
{
const BBox3f bounds0 = lbounds.bounds0;
const BBox3f bounds1 = lbounds.bounds1;

/* normalize global target_time_range to local time_range_in */
const BBox1f time_range((target_time_range.lower-time_range_in.lower)/time_range_in.size(),
(target_time_range.upper-time_range_in.lower)/time_range_in.size());
Expand Down Expand Up @@ -212,7 +251,7 @@ namespace embree
b0.lower += dlower; b1.lower += dlower;
b0.upper += dupper; b1.upper += dupper;
}

this->bounds0 = b0;
this->bounds1 = b1;
}
Expand Down Expand Up @@ -255,7 +294,7 @@ namespace embree
}

/* calculates bounds for [0,1] time range from bounds in dt time range */
__forceinline LBBox global(const BBox1f& dt) const
__forceinline LBBox global(const BBox1f& dt) const
{
const float rcp_dt_size = 1.0f/dt.size();
const BBox<T> b0 = interpolate(-dt.lower*rcp_dt_size);
Expand All @@ -268,7 +307,7 @@ namespace embree
//template<typename TT> friend __forceinline bool operator!=( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }
friend __forceinline bool operator==( const LBBox& a, const LBBox& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }
friend __forceinline bool operator!=( const LBBox& a, const LBBox& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }

/*! output operator */
friend __forceinline embree_ostream operator<<(embree_ostream cout, const LBBox& box) {
return cout << "LBBox { " << box.bounds0 << "; " << box.bounds1 << " }";
Expand All @@ -288,16 +327,16 @@ namespace embree
__forceinline bool isvalid_non_empty( const LBBox<T>& v ) {
return isvalid_non_empty(v.bounds0) && isvalid_non_empty(v.bounds1);
}

template<typename T>
__forceinline T expectedArea(const T& a0, const T& a1, const T& b0, const T& b1)
{
const T da = a1-a0;
const T db = b1-b0;
return a0*b0+(a0*db+da*b0)*T(0.5f) + da*db*T(1.0f/3.0f);
}
template<> __forceinline float LBBox<Vec3fa>::expectedHalfArea() const

template<> __forceinline float LBBox<Vec3fa>::expectedHalfArea() const
{
const Vec3fa d0 = bounds0.size();
const Vec3fa d1 = bounds1.size();
Expand All @@ -309,7 +348,7 @@ namespace embree

template<typename T>
__forceinline float expectedApproxHalfArea(const LBBox<T>& box) {
return box.expectedApproxHalfArea();
return box.expectedApproxHalfArea();
}

template<typename T>
Expand Down
30 changes: 15 additions & 15 deletions include/embree4/rtcore_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef int ssize_t;
#endif
#endif

#if defined(_WIN32)
#if defined(_WIN32)
# define RTC_FORCEINLINE __forceinline
#else
# define RTC_FORCEINLINE inline __attribute__((always_inline))
Expand Down Expand Up @@ -223,25 +223,25 @@ enum RTCFeatureFlags
RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE |
RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE |
RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE,

RTC_FEATURE_FLAG_FLAT_CURVES =
RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE |
RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE |
RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE |
RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE |
RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE,

RTC_FEATURE_FLAG_NORMAL_ORIENTED_CURVES =
RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE |
RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE |
RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE |
RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE,

RTC_FEATURE_FLAG_LINEAR_CURVES =
RTC_FEATURE_FLAG_CONE_LINEAR_CURVE |
RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE |
RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE,

RTC_FEATURE_FLAG_BEZIER_CURVES =
RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE |
RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE |
Expand All @@ -256,7 +256,7 @@ enum RTCFeatureFlags
RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE |
RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE |
RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE,

RTC_FEATURE_FLAG_CURVES =
RTC_FEATURE_FLAG_CONE_LINEAR_CURVE |
RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE |
Expand All @@ -273,7 +273,7 @@ enum RTCFeatureFlags
RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE |
RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE |
RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE,

RTC_FEATURE_FLAG_INSTANCE = 1 << 23,

RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS = 1 << 24,
Expand Down Expand Up @@ -361,13 +361,13 @@ RTC_FORCEINLINE void rtcInitRayQueryContext(struct RTCRayQueryContext* context)
}

/* Point query structure for closest point query */
struct RTC_ALIGN(16) RTCPointQuery
struct RTC_ALIGN(16) RTCPointQuery
{
float x; // x coordinate of the query point
float y; // y coordinate of the query point
float z; // z coordinate of the query point
float time; // time of the point query
float radius; // radius of the point query
float radius; // radius of the point query
};

/* Structure of a packet of 4 query points */
Expand All @@ -387,7 +387,7 @@ struct RTC_ALIGN(32) RTCPointQuery8
float y[8]; // y coordinate of the query point
float z[8]; // z coordinate of the query point
float time[8]; // time of the point query
float radius[8]; // radius ofr the point query
float radius[8]; // radius ofr the point query
};

/* Structure of a packet of 16 query points */
Expand All @@ -406,11 +406,11 @@ struct RTC_ALIGN(16) RTCPointQueryContext
{
// accumulated 4x4 column major matrices from world space to instance space.
// undefined if size == 0.
float world2inst[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
float world2inst[RTC_MAX_INSTANCE_LEVEL_COUNT][16];

// accumulated 4x4 column major matrices from instance space to world space.
// undefined if size == 0.
float inst2world[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
float inst2world[RTC_MAX_INSTANCE_LEVEL_COUNT][16];

// instance ids.
unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT];
Expand Down Expand Up @@ -451,13 +451,13 @@ struct RTC_ALIGN(16) RTCPointQueryFunctionArguments
void* userPtr;

// primitive and geometry ID of primitive
unsigned int primID;
unsigned int geomID;
unsigned int primID;
unsigned int geomID;

// the context with transformation and instance ID stack
struct RTCPointQueryContext* context;

// If the current instance transform M (= context->world2inst[context->instStackSize])
// If the current instance transform M (= context->world2inst[context->instStackSize])
// is a similarity matrix, i.e there is a constant factor similarityScale such that
// for all x,y: dist(Mx, My) = similarityScale * dist(x, y),
// The similarity scale is 0, if the current instance transform is not a
Expand Down
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);
}

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
8 changes: 8 additions & 0 deletions kernels/builders/bvh_builder_msmblur.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,14 @@ namespace embree
if (in.depth > cfg.maxDepth)
throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");

if (in.prims.prims)
{
const mvector<PrimRefMB>& prims = *in.prims.prims;
if (in.prims.begin() > in.prims.end() || in.prims.end() > prims.size()) {
throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid motion-blur primitive range");
}
}

/* replace already found split by fallback split */
const BuildRecordSplit current(BuildRecord(in.prims,in.depth),findFallback(in.prims));

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
Loading
Loading