Skip to content

Commit 578fa2d

Browse files
jordan-xboxfreibold
authored andcommitted
Fix triangle splitting crash where FP error causes binning differences
Ultimately the root problem here is that when we do the binning stage we use a different method to test the first stage and the second. In the first stage we use bin() to get an integer bin associated with a point in space. In the second we get the floating point division point on the axis we have chosen to bin on and do FP comparisons instead. Under most circumstances this is fine. Occasionally these binning differences will result in unprofitable splits happening but still building a usable tree. In the test case I've given, the unprofitable splits we erroneously choose fill up the split limit and we don't end up splitting the triangles the previous stage had intended to choose. As a result, we can't split those triangles. Then when we do the real bifurcation, everything is on the same side. This resulted in an assertion failure in production (1). (1) We never noticed that the RelWithDebInfo build in MSVC still has assertions enabled. I can provide another change disabling these since I think it's unintentional.
1 parent e4b1a6c commit 578fa2d

2 files changed

Lines changed: 65 additions & 5 deletions

File tree

kernels/builders/heuristic_spatial_array.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,9 @@ namespace embree
283283

284284
if (likely(splits <= 1)) continue; /* todo: does this ever happen ? */
285285

286-
//int bin0 = split.mapping.bin(prims0[i].lower)[split.dim];
287-
//int bin1 = split.mapping.bin(prims0[i].upper)[split.dim];
288-
//if (unlikely(bin0 < split.pos && bin1 >= split.pos))
289-
290-
if (unlikely(prims0[i].lower[split.dim] < fpos && prims0[i].upper[split.dim] > fpos))
286+
const int bin0 = split.mapping.bin(prims0[i].lower)[split.dim];
287+
const int bin1 = split.mapping.bin(prims0[i].upper)[split.dim];
288+
if (unlikely(bin0 < split.pos && bin1 >= split.pos))
291289
{
292290
assert(splits > 1);
293291

tutorials/verify/verify.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,64 @@ namespace embree
17761776
}
17771777
};
17781778

1779+
struct TriangleSplitRegression : public VerifyApplication::Test
1780+
{
1781+
TriangleSplitRegression (int isa)
1782+
: VerifyApplication::Test("TriangleSplitRegression", isa, VerifyApplication::TEST_SHOULD_PASS) {}
1783+
1784+
VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent)
1785+
{
1786+
std::string cfg = state->rtcore + ",isa="+stringOfISA(isa) + ",max_spatial_split_replications=1.5,max_triagles_per_leaf=1";
1787+
RTCDeviceRef device = rtcNewDevice(cfg.c_str());
1788+
errorHandler(nullptr,rtcGetDeviceError(device));
1789+
SceneFlags sflags = { RTC_SCENE_FLAG_NONE, RTC_BUILD_QUALITY_HIGH };
1790+
VerifyScene scene(device,sflags);
1791+
AssertNoError(device);
1792+
1793+
RTCBuildArguments arguments = rtcDefaultBuildArguments();
1794+
1795+
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(nullptr, BBox1f(0, 1));
1796+
mesh->triangles = {
1797+
{ 0,1,2 },
1798+
{ 3,4,5 },
1799+
{ 6,7,8 },
1800+
{ 6,7,8 },
1801+
};
1802+
1803+
mesh->positions.push_back({});
1804+
auto& pos = mesh->positions.front();
1805+
1806+
const float
1807+
a = -6.4000024f, // Lower limit, matters for determining binning space
1808+
b = 25.6f, // Needs to be very close to one of the binning positions so the classifiers disagree
1809+
c = 34.f, // Just needs to be between b and d
1810+
d = 57.6000022f; // Upper limit, matters for determining binning space
1811+
1812+
pos.push_back(Vec3fa(b, 0, 0));
1813+
pos.push_back(Vec3fa(d, 0, 0));
1814+
pos.push_back(Vec3fa(d, 1, 0));
1815+
1816+
pos.push_back(Vec3fa(b, 0, 0));
1817+
pos.push_back(Vec3fa(c, 0, 0));
1818+
pos.push_back(Vec3fa(c, 1, 0));
1819+
1820+
pos.push_back(Vec3fa(a, 0, 0));
1821+
pos.push_back(Vec3fa(d, 0, 0));
1822+
pos.push_back(Vec3fa(d, 1, 0));
1823+
1824+
auto geom = scene.addGeometry(RTC_BUILD_QUALITY_HIGH, mesh.dynamicCast<SceneGraph::Node>());
1825+
1826+
RTCGeometry hgeom = rtcGetGeometry(scene, geom);
1827+
AssertNoError(device);
1828+
1829+
rtcEnableGeometry(hgeom);
1830+
rtcCommitScene (scene);
1831+
AssertNoError(device);
1832+
1833+
return VerifyApplication::PASSED;
1834+
}
1835+
};
1836+
17791837
struct UpdateTest : public VerifyApplication::IntersectTest
17801838
{
17811839
SceneFlags sflags;
@@ -6210,6 +6268,10 @@ namespace embree
62106268
groups.top()->add(new DisableAndDetachGeometryTest(to_string(sflags),isa,sflags));
62116269
groups.pop();
62126270

6271+
push(new TestGroup("triangle_split_epsilon",true,true));
6272+
groups.top()->add(new TriangleSplitRegression(isa));
6273+
groups.pop();
6274+
62136275
push(new TestGroup("update",true,true));
62146276
for (auto sflags : sceneFlagsDynamic) {
62156277
for (auto imode : intersectModes) {

0 commit comments

Comments
 (0)