20 #if !defined(__MITSUBA_RENDER_GKDTREE_H_)
21 #define __MITSUBA_RENDER_GKDTREE_H_
25 #include <boost/static_assert.hpp>
28 #if defined(__LINUX__)
37 #define MTS_KD_MAXDEPTH 48
40 #define MTS_KD_MIN_ALLOC 512*1024
43 #define MTS_KD_BLOCKSIZE_KD (512*1024/sizeof(KDNode))
44 #define MTS_KD_BLOCKSIZE_IDX (512*1024/sizeof(uint32_t))
50 #define MTS_KD_AABB_EPSILON 1e-3f
52 #if defined(MTS_KD_DEBUG)
53 #define KDAssert(expr) SAssert(expr)
54 #define KDAssertEx(expr, text) SAssertEx(expr, text)
56 #define KDAssert(expr)
57 #define KDAssertEx(expr, text)
82 : m_minAllocation(minAllocation) {
94 for (std::vector<Chunk>::iterator it = m_chunks.begin();
95 it != m_chunks.end(); ++it)
104 m_chunks.reserve(m_chunks.size() + other.m_chunks.size());
105 m_chunks.insert(m_chunks.end(), other.m_chunks.begin(),
106 other.m_chunks.end());
124 template <
typename T> T * __restrict
allocate(
size_t size) {
126 for (std::vector<Chunk>::iterator it = m_chunks.begin();
127 it != m_chunks.end(); ++it) {
129 if (chunk.remainder() >= size) {
130 T* result =
reinterpret_cast<T *
>(chunk.cur);
137 size_t allocSize = std::max(size,
142 chunk.cur = chunk.start + size;
143 chunk.size = allocSize;
144 m_chunks.push_back(chunk);
146 return reinterpret_cast<T *
>(chunk.start);
150 for (std::vector<Chunk>::iterator it = m_chunks.begin();
151 it != m_chunks.end(); ++it) {
153 if ((
uint8_t *) ptr >= chunk.start &&
154 (
uint8_t *) ptr < chunk.start + chunk.size) {
159 #if defined(MTS_KD_DEBUG)
161 for (std::vector<Chunk>::iterator it = m_chunks.begin();
162 it != m_chunks.end(); ++it) {
163 const Chunk &chunk = *it;
164 if ((
uint8_t *) ptr == chunk.start + chunk.size)
167 SLog(
EError,
"OrderedChunkAllocator: Internal error while"
168 " releasing memory");
176 newSize *=
sizeof(T);
177 for (std::vector<Chunk>::iterator it = m_chunks.begin();
178 it != m_chunks.end(); ++it) {
180 if ((
uint8_t *) ptr >= chunk.start &&
181 (
uint8_t *) ptr < chunk.start + chunk.size) {
182 chunk.cur = (
uint8_t *) ptr + newSize;
186 #if defined(MTS_KD_DEBUG)
189 for (std::vector<Chunk>::iterator it = m_chunks.begin();
190 it != m_chunks.end(); ++it) {
191 const Chunk &chunk = *it;
192 if ((
uint8_t *) ptr == chunk.start + chunk.size)
196 SLog(
EError,
"OrderedChunkAllocator: Internal error while"
197 " releasing memory");
208 for (std::vector<Chunk>::const_iterator it = m_chunks.begin();
209 it != m_chunks.end(); ++it)
210 result += (*it).size;
219 for (std::vector<Chunk>::const_iterator it = m_chunks.begin();
220 it != m_chunks.end(); ++it)
221 result += (*it).used();
229 std::ostringstream oss;
230 oss <<
"OrderedChunkAllocator[" << endl;
231 for (
size_t i=0; i<m_chunks.size(); ++i)
232 oss <<
" Chunk " << i <<
": " << m_chunks[i].toString() << endl;
242 inline size_t used()
const {
246 inline size_t remainder()
const {
247 return size - used();
250 std::string toString()
const {
257 size_t m_minAllocation;
258 std::vector<Chunk> m_chunks;
283 size_t blockIdx = m_pos / BlockSize;
284 size_t offset = m_pos % BlockSize;
285 if (blockIdx == m_blocks.size())
286 m_blocks.push_back(
new T[BlockSize]);
287 m_blocks[blockIdx][offset] = value;
301 #if defined(MTS_KD_DEBUG)
304 size_t blockIdx = m_pos / BlockSize;
305 size_t offset = m_pos % BlockSize;
307 if (EXPECT_TAKEN(offset + size <= BlockSize)) {
308 if (blockIdx == m_blocks.size())
309 m_blocks.push_back(
new T[BlockSize]);
310 result = m_blocks[blockIdx] + offset;
314 if (blockIdx == m_blocks.size())
315 m_blocks.push_back(
new T[BlockSize]);
316 result = m_blocks[blockIdx];
317 m_pos += BlockSize - offset + size;
323 return *(m_blocks[index / BlockSize] +
324 (index % BlockSize));
328 return *(m_blocks[index / BlockSize] +
329 (index % BlockSize));
344 return m_blocks.size();
351 return m_blocks.size() * BlockSize;
362 #if defined(MTS_KD_DEBUG)
372 for (
typename std::vector<T *>::iterator it = m_blocks.begin();
373 it != m_blocks.end(); ++it)
379 std::vector<T *> m_blocks;
397 : m_buffer(NULL), m_bufferSize(0) { }
408 m_bufferSize = size/4 + ((size % 4) > 0 ? 1 : 0);
409 m_buffer =
new uint8_t[m_bufferSize];
416 uint8_t *ptr = m_buffer + (index >> 2);
417 uint8_t shift = (index & 3) << 1;
418 *ptr = (*ptr & ~(3 << shift)) | (value << shift);
422 uint8_t *ptr = m_buffer + (index >> 2);
423 uint8_t shift = (index & 3) << 1;
424 return (*ptr >> shift) & 3;
484 EIndirectionMask = 1 << 30,
485 ELeafOffsetMask = ~ETypeMask,
486 EInnerAxisMask = 0x3,
487 EInnerOffsetMask = ~(EInnerAxisMask + EIndirectionMask),
488 ERelOffsetLimit = (1<<28) - 1
493 leaf.combined = (
uint32_t) ETypeMask | offset;
494 leaf.end = offset + numPrims;
502 if (relOffset < 0 || relOffset > ERelOffsetLimit)
504 inner.combined = axis | ((
uint32_t) relOffset << 2);
519 inner.combined = EIndirectionMask
520 | ((
uint32_t) indirectionEntry << 2)
527 return leaf.combined & (
uint32_t) ETypeMask;
532 return leaf.combined & (
uint32_t) EIndirectionMask;
537 return leaf.combined & (
uint32_t) ELeafOffsetMask;
547 return(inner.combined & (
uint32_t) EInnerOffsetMask) >> 2;
553 ((inner.combined & (
uint32_t) EInnerOffsetMask) >> 2);
558 return (
const KDNode *) ((ptrdiff_t)
this ^ (ptrdiff_t) 8);
564 ((inner.combined & (
uint32_t) EInnerOffsetMask) >> 2);
569 return getLeft() + 1;
582 return inner.combined & (
uint32_t) EInnerAxisMask;
587 std::ostringstream oss;
589 oss <<
"KDNode[leaf, primStart=" << getPrimStart()
590 <<
", primCount=" << getPrimEnd()-getPrimStart() <<
"]";
592 oss <<
"KDNode[interior, axis=" << getAxis()
593 <<
", split=" << getAxis()
595 << ((inner.combined & EInnerOffsetMask) >> 2)
601 BOOST_STATIC_ASSERT(
sizeof(KDNode) == 8);
616 return m_nodes != NULL;
620 inline const AABBType &
getAABB()
const {
return m_aabb; }
634 #if defined(_MSC_VER) && !defined(__INTELLISENSE__)
638 #pragma float_control(precise, on)
642 #define KDLog(level, fmt, ...) Thread::getThread()->getLogger()->log(\
643 level, KDTreeBase<AABB>::m_theClass, __FILE__, __LINE__, \
705 template <
typename AABBType,
typename TreeConstructionHeuristic,
typename Derived>
711 struct EdgeEventOrdering;
718 typedef typename AABBType::Scalar
Scalar;
722 using Parent::m_nodes;
723 using Parent::m_aabb;
724 using Parent::m_tightAABB;
725 using Parent::m_logLevel;
726 using Parent::isBuilt;
734 m_traversalCost = 15;
736 m_emptySpaceBonus = 0.9f;
740 m_exactPrimThreshold = 65536;
743 m_parallelBuild =
true;
762 m_traversalCost = traversalCost;
774 return m_traversalCost;
783 m_queryCost = queryCost;
800 m_emptySpaceBonus = emptySpaceBonus;
808 return m_emptySpaceBonus;
815 m_maxDepth = maxDepth;
822 m_minMaxBins = minMaxBins;
874 m_maxBadRefines = maxBadRefines;
882 return m_maxBadRefines;
890 m_stopPrims = stopPrims;
906 m_parallelBuild = parallel;
914 return m_parallelBuild;
923 m_exactPrimThreshold = exactPrimThreshold;
932 return m_exactPrimThreshold;
950 node(node), target(target), context(context), aabb(aabb) { }
961 KDLog(
EError,
"The kd-tree has already been built!");
962 if (m_traversalCost <= 0)
964 if (m_queryCost <= 0)
966 if (m_emptySpaceBonus <= 0 || m_emptySpaceBonus > 1)
967 KDLog(
EError,
"The empty space bonus must be in [0, 1]");
968 if (m_minMaxBins <= 1)
969 KDLog(
EError,
"The number of min-max bins must be > 2");
971 SizeType primCount = cast()->getPrimitiveCount();
972 if (primCount == 0) {
973 KDLog(
EWarn,
"kd-tree contains no geometry!");
976 m_nodes[0].initLeafNode(0, 0);
980 if (primCount <= m_exactPrimThreshold)
981 m_parallelBuild =
false;
983 BuildContext ctx(primCount, m_minMaxBins);
987 m_maxDepth = (int) (8 + 1.3f *
math::log2i(primCount));
990 KDLog(m_logLevel,
"Creating a preliminary index list (%s)",
997 AABBType &aabb = m_aabb;
1000 aabb.expandBy(cast()->getAABB(i));
1004 #if defined(DOUBLE_PRECISION)
1005 for (
int i=0; i<3; ++i) {
1011 KDLog(m_logLevel,
"Computed scene bounds in %i ms",
1012 timer->getMilliseconds());
1013 KDLog(m_logLevel,
"");
1015 KDLog(m_logLevel,
"kd-tree configuration:");
1016 KDLog(m_logLevel,
" Traversal cost : %.2f", m_traversalCost);
1017 KDLog(m_logLevel,
" Query cost : %.2f", m_queryCost);
1018 KDLog(m_logLevel,
" Empty space bonus : %.2f", m_emptySpaceBonus);
1019 KDLog(m_logLevel,
" Max. tree depth : %i", m_maxDepth);
1020 KDLog(m_logLevel,
" Scene bounding box (min) : %s",
1021 aabb.min.toString().c_str());
1022 KDLog(m_logLevel,
" Scene bounding box (max) : %s",
1023 aabb.max.toString().c_str());
1024 KDLog(m_logLevel,
" Min-max bins : %i", m_minMaxBins);
1025 KDLog(m_logLevel,
" O(n log n) method : use for <= %i primitives",
1026 m_exactPrimThreshold);
1027 KDLog(m_logLevel,
" Perfect splits : %s", m_clip ?
"yes" :
"no");
1028 KDLog(m_logLevel,
" Retract bad splits : %s",
1029 m_retract ?
"yes" :
"no");
1030 KDLog(m_logLevel,
" Stopping primitive count : %i", m_stopPrims);
1031 KDLog(m_logLevel,
" Build tree in parallel : %s",
1032 m_parallelBuild ?
"yes" :
"no");
1033 KDLog(m_logLevel,
"");
1037 m_parallelBuild =
false;
1039 if (m_parallelBuild) {
1040 m_builders.resize(procCount);
1041 for (
SizeType i=0; i<procCount; ++i) {
1042 m_builders[i] =
new TreeBuilder(i,
this);
1043 m_builders[i]->incRef();
1044 m_builders[i]->start();
1048 m_indirectionLock =
new Mutex();
1049 KDNode *prelimRoot = ctx.nodes.allocate(1);
1050 buildTreeMinMax(ctx, 1, prelimRoot, aabb, aabb,
1051 indices, primCount,
true, 0);
1052 ctx.leftAlloc.release(indices);
1054 KDAssert(ctx.leftAlloc.used() == 0);
1055 KDAssert(ctx.rightAlloc.used() == 0);
1057 if (m_parallelBuild) {
1059 m_interface.done =
true;
1060 m_interface.cond->broadcast();
1062 for (
SizeType i=0; i<m_builders.size(); ++i)
1063 m_builders[i]->join();
1066 KDLog(
EInfo,
"Finished -- took %i ms.", timer->getMilliseconds());
1067 KDLog(m_logLevel,
"");
1069 KDLog(m_logLevel,
"Temporary memory statistics:");
1070 KDLog(m_logLevel,
" Classification storage : %s",
1071 memString((ctx.classStorage.size() * (1+procCount))).c_str());
1073 m_indirections.size(),
memString(m_indirections.capacity()
1074 *
sizeof(
KDNode *)).c_str());
1076 KDLog(m_logLevel,
" Main thread:");
1077 ctx.printStats(m_logLevel);
1078 size_t totalUsage = m_indirections.capacity()
1079 *
sizeof(
KDNode *) + ctx.size();
1082 ctx.leftAlloc.cleanup();
1083 ctx.rightAlloc.cleanup();
1084 for (
SizeType i=0; i<m_builders.size(); ++i) {
1085 KDLog(m_logLevel,
" Worker thread %i:", i+1);
1086 BuildContext &subCtx = m_builders[i]->getContext();
1087 subCtx.printStats(m_logLevel);
1088 totalUsage += subCtx.size();
1089 subCtx.leftAlloc.cleanup();
1090 subCtx.rightAlloc.cleanup();
1091 ctx.accumulateStatisticsFrom(subCtx);
1095 KDLog(m_logLevel,
"");
1097 KDLog(m_logLevel,
"Optimizing memory layout ..");
1099 Float expTraversalSteps = 0;
1100 Float expLeavesVisited = 0;
1101 Float expPrimitivesIntersected = 0;
1102 Float heuristicCost = 0;
1104 SizeType nodePtr = 0, indexPtr = 0;
1106 const SizeType primBucketCount = 16;
1107 SizeType primBuckets[primBucketCount];
1108 memset(primBuckets, 0,
sizeof(
SizeType)*primBucketCount);
1109 m_nodeCount = ctx.innerNodeCount + ctx.leafNodeCount;
1110 m_indexCount = ctx.primIndexCount;
1114 sizeof(
KDNode) * (m_nodeCount+1)))+1;
1115 m_indices =
new IndexType[m_indexCount];
1120 std::stack<RewriteItem> stack;
1121 stack.push(RewriteItem(prelimRoot, &m_nodes[nodePtr++], &ctx, aabb));
1122 while (!stack.empty()) {
1123 RewriteItem item = stack.top();
1126 typename std::map<const KDNode *, IndexType>::const_iterator it
1127 = m_interface.threadMap.find(item.node);
1129 if (it != m_interface.threadMap.end())
1130 item.context = &m_builders[(*it).second]->getContext();
1132 if (item.node->isLeaf()) {
1133 SizeType primStart = item.node->getPrimStart(),
1134 primEnd = item.node->getPrimEnd(),
1135 primsInLeaf = primEnd-primStart;
1136 item.target->initLeafNode(indexPtr, primsInLeaf);
1138 Float quantity = TreeConstructionHeuristic::getQuantity(item.aabb),
1139 weightedQuantity = quantity * primsInLeaf;
1140 expLeavesVisited += quantity;
1141 expPrimitivesIntersected += weightedQuantity;
1142 heuristicCost += weightedQuantity * m_queryCost;
1143 if (primsInLeaf < primBucketCount)
1144 primBuckets[primsInLeaf]++;
1145 if (primsInLeaf > maxPrimsInLeaf)
1146 maxPrimsInLeaf = primsInLeaf;
1149 = item.context->indices;
1150 for (
SizeType idx = primStart; idx<primEnd; ++idx) {
1151 KDAssert(indices[idx] >= 0 && indices[idx] < primCount);
1152 m_indices[indexPtr++] = indices[idx];
1155 Float quantity = TreeConstructionHeuristic::getQuantity(item.aabb);
1156 expTraversalSteps += quantity;
1157 heuristicCost += quantity * m_traversalCost;
1160 if (EXPECT_TAKEN(!item.node->isIndirection()))
1161 left = item.node->getLeft();
1163 left = m_indirections[item.node->getIndirectionIndex()];
1165 KDNode *children = &m_nodes[nodePtr];
1167 int axis = item.node->getAxis();
1168 float split = item.node->getSplit();
1169 bool result = item.target->initInnerNode(axis, split, children - item.target);
1171 KDLog(
EError,
"Cannot represent relative pointer -- "
1172 "too many primitives?");
1174 Float tmp = item.aabb.min[axis];
1175 item.aabb.min[axis] = split;
1176 stack.push(RewriteItem(left+1, children+1, item.context, item.aabb));
1177 item.aabb.min[axis] = tmp;
1178 item.aabb.max[axis] = split;
1179 stack.push(RewriteItem(left, children, item.context, item.aabb));
1183 KDAssert(nodePtr == ctx.innerNodeCount + ctx.leafNodeCount);
1184 KDAssert(indexPtr == m_indexCount);
1186 KDLog(m_logLevel,
"Finished -- took %i ms.", timer->getMilliseconds());
1190 ctx.indices.clear();
1191 for (
SizeType i=0; i<m_builders.size(); ++i) {
1192 BuildContext &subCtx = m_builders[i]->getContext();
1193 subCtx.nodes.clear();
1194 subCtx.indices.clear();
1196 m_indirectionLock = NULL;
1197 std::vector<KDNode *>().swap(m_indirections);
1199 if (m_builders.size() > 0) {
1200 for (
SizeType i=0; i<m_builders.size(); ++i)
1201 m_builders[i]->decRef();
1205 KDLog(m_logLevel,
"");
1207 Float rootQuantity = TreeConstructionHeuristic::getQuantity(aabb);
1208 expTraversalSteps /= rootQuantity;
1209 expLeavesVisited /= rootQuantity;
1210 expPrimitivesIntersected /= rootQuantity;
1211 heuristicCost /= rootQuantity;
1219 aabb.min -= (aabb.max-aabb.min) * eps +
VectorType(eps);
1220 aabb.max += (aabb.max-aabb.min) * eps +
VectorType(eps);
1222 KDLog(m_logLevel,
"Structural kd-tree statistics:");
1224 m_interface.threadMap.size());
1225 KDLog(m_logLevel,
" Node storage cost : %s",
1227 KDLog(m_logLevel,
" Index storage cost : %s",
1229 KDLog(m_logLevel,
" Inner nodes : %i", ctx.innerNodeCount);
1230 KDLog(m_logLevel,
" Leaf nodes : %i", ctx.leafNodeCount);
1231 KDLog(m_logLevel,
" Nonempty leaf nodes : %i",
1232 ctx.nonemptyLeafNodeCount);
1233 std::ostringstream oss;
1234 oss <<
" Leaf node histogram : ";
1235 for (
SizeType i=0; i<primBucketCount; i++) {
1236 oss << i <<
"(" << primBuckets[i] <<
") ";
1237 if ((i+1)%4==0 && i+1<primBucketCount) {
1238 KDLog(m_logLevel,
"%s", oss.str().c_str());
1243 KDLog(m_logLevel,
"%s", oss.str().c_str());
1244 KDLog(m_logLevel,
"");
1245 KDLog(m_logLevel,
"Qualitative kd-tree statistics:");
1246 KDLog(m_logLevel,
" Retracted splits : %i", ctx.retractedSplits);
1247 KDLog(m_logLevel,
" Pruned primitives : %i", ctx.pruned);
1248 KDLog(m_logLevel,
" Largest leaf node : %i primitives",
1250 KDLog(m_logLevel,
" Avg. prims/nonempty leaf : %.2f",
1251 ctx.primIndexCount / (
Float) ctx.nonemptyLeafNodeCount);
1252 KDLog(m_logLevel,
" Expected traversals/query : %.2f", expTraversalSteps);
1253 KDLog(m_logLevel,
" Expected leaf visits/query : %.2f", expLeavesVisited);
1254 KDLog(m_logLevel,
" Expected prim. visits/query : %.2f",
1255 expPrimitivesIntersected);
1256 KDLog(m_logLevel,
" Final cost : %.2f", heuristicCost);
1257 KDLog(m_logLevel,
"");
1259 #if defined(__LINUX__)
1275 EBothSidesProcessed = 3
1295 : pos(pos), index(index), type(type), axis(axis) { }
1299 std::ostringstream oss;
1300 oss <<
"EdgeEvent[" << endl
1301 <<
" pos = " << pos <<
"," << endl
1302 <<
" index = " << index <<
"," << endl
1304 if (type == EEdgeEnd)
1306 else if (type == EEdgePlanar)
1308 else if (type == EEdgeStart)
1313 <<
" axis = " << axis << endl
1323 unsigned int type:2;
1325 unsigned int axis:2;
1328 BOOST_STATIC_ASSERT(
sizeof(
EdgeEvent) == 12);
1356 cost(std::numeric_limits<
Float>::infinity()),
1357 pos(0), axis(0), numLeft(0), numRight(0), planarLeft(false), leftBin(-1) {
1361 std::ostringstream oss;
1362 oss <<
"SplitCandidate[" << endl
1363 <<
" cost=" << cost <<
"," << endl
1364 <<
" pos=" << pos <<
"," << endl
1365 <<
" axis=" << axis <<
"," << endl
1366 <<
" numLeft=" << numLeft <<
"," << endl
1367 <<
" numRight=" << numRight <<
"," << endl
1368 <<
" leftBin=" << leftBin <<
"," << endl
1369 <<
" planarLeft=" << (planarLeft ?
"yes" :
"no") << endl
1394 : minMaxBins(binCount) {
1395 classStorage.setPrimitiveCount(primCount);
1397 nonemptyLeafNodeCount = 0;
1400 retractedSplits = 0;
1405 return leftAlloc.size() + rightAlloc.size()
1406 + nodes.capacity() *
sizeof(
KDNode)
1407 + indices.capacity() *
sizeof(
IndexType)
1408 + classStorage.size();
1413 leftAlloc.getChunkCount(),
1416 rightAlloc.getChunkCount(),
1419 SIZE_T_FMT " blocks (%s)", nodes.size(), nodes.blockCount(),
1421 KDLog(level,
" Indices : " SIZE_T_FMT
" entries, "
1422 SIZE_T_FMT
" blocks (%s)", indices.size(),
1423 indices.blockCount(),
memString(indices.capacity()
1457 mutex =
new Mutex();
1474 m_context(parent->cast()->getPrimitiveCount(),
1475 parent->getMinMaxBins()),
1476 m_interface(parent->m_interface) {
1481 KDAssert(m_context.leftAlloc.used() == 0);
1482 KDAssert(m_context.rightAlloc.used() == 0);
1489 while (!m_interface.done && !m_interface.node)
1490 m_interface.cond->wait();
1491 if (m_interface.done) {
1494 int depth = m_interface.depth;
1495 KDNode *node = m_interface.node;
1496 AABBType nodeAABB = m_interface.nodeAABB;
1497 size_t eventCount = m_interface.eventEnd - m_interface.eventStart;
1498 SizeType primCount = m_interface.primCount;
1499 int badRefines = m_interface.badRefines;
1501 *eventEnd = eventStart + eventCount;
1502 memcpy(eventStart, m_interface.eventStart,
1504 m_interface.threadMap[node] = m_id;
1505 m_interface.node = NULL;
1506 m_interface.condJobTaken->signal();
1510 m_parent->buildTree(m_context, depth, node,
1511 nodeAABB, eventStart, eventEnd, primCount,
true, badRefines);
1512 leftAlloc.
release(eventStart);
1529 return static_cast<Derived *
>(
this);
1533 inline const Derived *
cast()
const {
1534 return static_cast<const Derived *
>(
this);
1542 : start(start), end(end), primCount(primCount) { }
1554 SizeType initialSize = primCount * 2 * PointType::dim, actualPrimCount = 0;
1555 EdgeEvent *eventStart = alloc.
allocate<EdgeEvent>(initialSize);
1556 EdgeEvent *eventEnd = eventStart;
1558 for (
SizeType i=0; i<primCount; ++i) {
1562 aabb = cast()->getClippedAABB(index, nodeAABB);
1563 if (!aabb.isValid() || aabb.getSurfaceArea() == 0)
1566 aabb = cast()->getAABB(index);
1569 for (
int axis=0; axis<PointType::dim; ++axis) {
1574 *eventEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis,
1577 *eventEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, axis,
1579 *eventEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, axis,
1587 if (newSize != initialSize)
1590 return EventList(eventStart, eventEnd, actualPrimCount);
1608 EdgeEvent *eventEnd,
SizeType primCount) {
1609 node->initLeafNode((
SizeType) ctx.indices.size(), primCount);
1610 if (primCount > 0) {
1612 ctx.nonemptyLeafNodeCount++;
1614 for (EdgeEvent *event = eventStart;
event != eventEnd
1615 &&
event->axis == 0; ++event) {
1616 if (event->type == EdgeEvent::EEdgeStart ||
1617 event->type == EdgeEvent::EEdgePlanar) {
1618 ctx.indices.push_back(event->index);
1623 ctx.primIndexCount += primCount;
1625 ctx.leafNodeCount++;
1642 node->initLeafNode((
SizeType) ctx.indices.size(), primCount);
1643 if (primCount > 0) {
1644 ctx.nonemptyLeafNodeCount++;
1645 for (
SizeType i=0; i<primCount; ++i)
1646 ctx.indices.push_back(indices[i]);
1647 ctx.primIndexCount += primCount;
1649 ctx.leafNodeCount++;
1674 *tempEnd = tempStart + indexCount,
1677 for (
SizeType i=start, end = start + indexCount; i<end; ++i)
1678 *ptr++ = ctx.indices[i];
1681 std::sort(tempStart, tempEnd, std::less<IndexType>());
1685 while (ptr < tempEnd) {
1686 ctx.indices[idx] = *ptr++;
1687 while (ptr < tempEnd && *ptr == ctx.indices[idx])
1692 int nSeen = idx-start;
1693 ctx.primIndexCount = ctx.primIndexCount - indexCount + nSeen;
1694 ctx.indices.resize(idx);
1696 node->initLeafNode(start, nSeen);
1697 ctx.nonemptyLeafNodeCount++;
1698 ctx.leafNodeCount++;
1730 const AABBType &nodeAABB,
IndexType *indices,
1733 ? ctx.leftAlloc : ctx.rightAlloc;
1734 EventList events = createEventList(alloc, nodeAABB, indices, primCount);
1736 if (m_parallelBuild) {
1738 m_interface.depth = depth;
1739 m_interface.node = node;
1740 m_interface.nodeAABB = nodeAABB;
1741 m_interface.eventStart = events.start;
1742 m_interface.eventEnd = events.end;
1743 m_interface.primCount = events.primCount;
1744 m_interface.badRefines = badRefines;
1745 m_interface.cond->signal();
1748 while (m_interface.node)
1749 m_interface.condJobTaken->wait();
1752 cost = -std::numeric_limits<Float>::infinity();
1754 std::sort(events.start, events.end, EdgeEventOrdering());
1756 cost = buildTree(ctx, depth, node, nodeAABB, events.start,
1757 events.end, events.primCount, isLeftChild, badRefines);
1793 const AABBType &nodeAABB,
const AABBType &tightAABB,
IndexType *indices,
1795 KDAssert(nodeAABB.contains(tightAABB));
1797 Float leafCost = primCount * m_queryCost;
1798 if (primCount <= m_stopPrims || depth >= m_maxDepth) {
1799 createLeaf(ctx, node, indices, primCount);
1803 if (primCount <= m_exactPrimThreshold)
1804 return transitionToNLogN(ctx, depth, node, nodeAABB, indices,
1805 primCount, isLeftChild, badRefines);
1811 ctx.minMaxBins.setAABB(tightAABB);
1812 ctx.minMaxBins.bin(cast(), indices, primCount);
1817 SplitCandidate bestSplit = ctx.minMaxBins.minimizeCost(m_traversalCost,
1820 if (bestSplit.cost == std::numeric_limits<Float>::infinity()) {
1828 KDLog(
EWarn,
"Min-max binning was unable to split %i primitives with %s "
1829 "-- retrying with the O(n log n) greedy optimization",
1830 primCount, tightAABB.toString().c_str());
1831 return transitionToNLogN(ctx, depth, node, nodeAABB, indices,
1832 primCount, isLeftChild, badRefines);
1836 if (bestSplit.cost >= leafCost) {
1837 if ((bestSplit.cost > 4 * leafCost && primCount < 16)
1838 || badRefines >= m_maxBadRefines) {
1839 createLeaf(ctx, node, indices, primCount);
1849 typename MinMaxBins::Partition partition =
1850 ctx.minMaxBins.partition(ctx, cast(), indices, bestSplit,
1851 isLeftChild, m_traversalCost, m_queryCost);
1857 KDNode *children = ctx.nodes.allocate(2);
1861 SizeType leafNodeCountBeforeSplit = ctx.leafNodeCount;
1862 SizeType nonemptyLeafNodeCountBeforeSplit = ctx.nonemptyLeafNodeCount;
1863 SizeType innerNodeCountBeforeSplit = ctx.innerNodeCount;
1865 if (!node->initInnerNode(bestSplit.axis, bestSplit.pos, children-node)) {
1868 m_indirections.push_back(children);
1871 node->initIndirectionNode(bestSplit.axis, bestSplit.pos,
1874 ctx.innerNodeCount++;
1876 AABBType childAABB(nodeAABB);
1877 childAABB.max[bestSplit.axis] = bestSplit.pos;
1879 Float leftCost = buildTreeMinMax(ctx, depth+1, children,
1880 childAABB, partition.left, partition.leftIndices,
1881 bestSplit.numLeft,
true, badRefines);
1883 childAABB.min[bestSplit.axis] = bestSplit.pos;
1884 childAABB.max[bestSplit.axis] = nodeAABB.max[bestSplit.axis];
1886 Float rightCost = buildTreeMinMax(ctx, depth+1, children + 1,
1887 childAABB, partition.right, partition.rightIndices,
1888 bestSplit.numRight,
false, badRefines);
1890 TreeConstructionHeuristic tch(nodeAABB);
1891 std::pair<Float, Float> prob = tch(bestSplit.axis,
1892 bestSplit.pos - nodeAABB.min[bestSplit.axis],
1893 nodeAABB.max[bestSplit.axis] - bestSplit.pos);
1897 Float finalCost = m_traversalCost +
1898 (prob.first * leftCost + prob.second * rightCost);
1902 ctx.rightAlloc.release(partition.rightIndices);
1904 ctx.leftAlloc.release(partition.leftIndices);
1910 if (!m_retract || finalCost < primCount * m_queryCost) {
1915 ctx.nodes.resize(nodePosBeforeSplit);
1916 ctx.retractedSplits++;
1917 ctx.leafNodeCount = leafNodeCountBeforeSplit;
1918 ctx.nonemptyLeafNodeCount = nonemptyLeafNodeCountBeforeSplit;
1919 ctx.innerNodeCount = innerNodeCountBeforeSplit;
1920 createLeafAfterRetraction(ctx, node, indexPosBeforeSplit);
1955 const AABBType &nodeAABB, EdgeEvent *eventStart, EdgeEvent *eventEnd,
1958 Float leafCost = primCount * m_queryCost;
1959 if (primCount <= m_stopPrims || depth >= m_maxDepth) {
1960 createLeaf(ctx, node, eventStart, eventEnd, primCount);
1964 SplitCandidate bestSplit;
1977 numRight[PointType::dim];
1979 for (
int i=0; i<PointType::dim; ++i) {
1981 numRight[i] = primCount;
1984 EdgeEvent *eventsByAxis[PointType::dim];
1985 int eventsByAxisCtr = 1;
1986 eventsByAxis[0] = eventStart;
1987 TreeConstructionHeuristic tch(nodeAABB);
1990 for (EdgeEvent *event = eventStart;
event < eventEnd; ) {
1995 int axis =
event->axis;
1996 float pos =
event->pos;
1997 SizeType numStart = 0, numEnd = 0, numPlanar = 0;
2000 while (event < eventEnd && event->pos == pos
2001 && event->axis == axis
2002 && event->type == EdgeEvent::EEdgeEnd) {
2007 while (event < eventEnd && event->pos == pos
2008 && event->axis == axis
2009 && event->type == EdgeEvent::EEdgePlanar) {
2010 ++numPlanar; ++event;
2014 while (event < eventEnd && event->pos == pos
2015 && event->axis == axis
2016 && event->type == EdgeEvent::EEdgeStart) {
2017 ++numStart; ++event;
2021 if (event < eventEnd && event->axis != axis) {
2022 KDAssert(eventsByAxisCtr < PointType::dim);
2023 eventsByAxis[eventsByAxisCtr++] = event;
2028 numRight[axis] -= numPlanar + numEnd;
2031 if (EXPECT_TAKEN(pos > nodeAABB.min[axis] && pos < nodeAABB.max[axis])) {
2032 const SizeType nL = numLeft[axis], nR = numRight[axis];
2035 std::pair<Float, Float> prob = tch(axis,
2036 pos - nodeAABB.min[axis],
2037 nodeAABB.max[axis] - pos);
2039 if (numPlanar == 0) {
2040 Float cost = m_traversalCost + m_queryCost
2041 * (prob.first * nLF + prob.second * nRF);
2042 if (nL == 0 || nR == 0)
2043 cost *= m_emptySpaceBonus;
2044 if (cost < bestSplit.cost) {
2045 bestSplit.pos = pos;
2046 bestSplit.axis = axis;
2047 bestSplit.cost = cost;
2048 bestSplit.numLeft = nL;
2049 bestSplit.numRight = nR;
2052 Float costPlanarLeft = m_traversalCost
2053 + m_queryCost * (prob.first * (nL+numPlanar) + prob.second * nRF);
2054 Float costPlanarRight = m_traversalCost
2055 + m_queryCost * (prob.first * nLF + prob.second * (nR+numPlanar));
2057 if (nL + numPlanar == 0 || nR == 0)
2058 costPlanarLeft *= m_emptySpaceBonus;
2059 if (nL == 0 || nR + numPlanar == 0)
2060 costPlanarRight *= m_emptySpaceBonus;
2062 if (costPlanarLeft < bestSplit.cost ||
2063 costPlanarRight < bestSplit.cost) {
2064 bestSplit.pos = pos;
2065 bestSplit.axis = axis;
2067 if (costPlanarLeft < costPlanarRight) {
2068 bestSplit.cost = costPlanarLeft;
2069 bestSplit.numLeft = nL + numPlanar;
2070 bestSplit.numRight = nR;
2071 bestSplit.planarLeft =
true;
2073 bestSplit.cost = costPlanarRight;
2074 bestSplit.numLeft = nL;
2075 bestSplit.numRight = nR + numPlanar;
2076 bestSplit.planarLeft =
false;
2081 #if defined(MTS_KD_DEBUG)
2082 if (m_clip && (pos < nodeAABB.min[axis]
2083 || pos > nodeAABB.max[axis])) {
2085 KDLog(
EError,
"Internal error: edge event is out of bounds");
2094 numLeft[axis] += numStart + numPlanar;
2097 #if defined(MTS_KD_DEBUG)
2099 for (
int i=0; i<PointType::dim; ++i)
2100 KDAssert(numRight[i] == 0 && numLeft[i] == primCount);
2101 for (
int i=1; i<PointType::dim; ++i)
2102 KDAssert(eventsByAxis[i]->axis == i && (eventsByAxis[i]-1)->axis == i-1);
2106 if (bestSplit.cost >= leafCost) {
2107 if ((bestSplit.cost > 4 * leafCost && primCount < 16)
2108 || badRefines >= m_maxBadRefines
2109 || bestSplit.cost == std::numeric_limits<Float>::infinity()) {
2110 createLeaf(ctx, node, eventStart, eventEnd, primCount);
2123 for (EdgeEvent *event = eventsByAxis[bestSplit.axis];
2124 event < eventEnd && event->axis == bestSplit.axis; ++event)
2125 storage.
set(event->index, EBothSides);
2127 SizeType primsLeft = 0, primsRight = 0, primsBoth = primCount;
2129 for (EdgeEvent *event = eventsByAxis[bestSplit.axis];
2130 event < eventEnd && event->axis == bestSplit.axis; ++event) {
2131 if (event->type == EdgeEvent::EEdgeEnd && event->pos <= bestSplit.pos) {
2134 KDAssert(storage.
get(event->index) == EBothSides);
2135 storage.
set(event->index, ELeftSide);
2138 }
else if (event->type == EdgeEvent::EEdgeStart
2139 && event->pos >= bestSplit.pos) {
2142 KDAssert(storage.
get(event->index) == EBothSides);
2143 storage.
set(event->index, ERightSide);
2146 }
else if (event->type == EdgeEvent::EEdgePlanar) {
2150 KDAssert(storage.
get(event->index) == EBothSides);
2151 if (event->pos < bestSplit.pos || (event->pos == bestSplit.pos
2152 && bestSplit.planarLeft)) {
2153 storage.
set(event->index, ELeftSide);
2156 }
else if (event->pos > bestSplit.pos
2157 || (event->pos == bestSplit.pos && !bestSplit.planarLeft)) {
2158 storage.
set(event->index, ERightSide);
2168 KDAssert(primsLeft + primsRight + primsBoth == primCount);
2169 KDAssert(primsLeft + primsBoth == bestSplit.numLeft);
2170 KDAssert(primsRight + primsBoth == bestSplit.numRight);
2173 &rightAlloc = ctx.rightAlloc;
2175 EdgeEvent *leftEventsStart, *rightEventsStart;
2177 leftEventsStart = eventStart;
2178 rightEventsStart = rightAlloc.
allocate<EdgeEvent>(bestSplit.numRight * 2 * PointType::dim);
2180 leftEventsStart = leftAlloc.
allocate<EdgeEvent>(bestSplit.numLeft * 2 * PointType::dim);
2181 rightEventsStart = eventStart;
2184 EdgeEvent *leftEventsEnd = leftEventsStart, *rightEventsEnd = rightEventsStart;
2186 AABBType leftNodeAABB = nodeAABB, rightNodeAABB = nodeAABB;
2187 leftNodeAABB.max[bestSplit.axis] = bestSplit.pos;
2188 rightNodeAABB.min[bestSplit.axis] = bestSplit.pos;
2190 SizeType prunedLeft = 0, prunedRight = 0;
2198 *leftEventsTempStart = leftAlloc.
allocate<EdgeEvent>(primsLeft * 2 * PointType::dim),
2199 *rightEventsTempStart = rightAlloc.allocate<EdgeEvent>(primsRight * 2 * PointType::dim),
2200 *newEventsLeftStart = leftAlloc.
allocate<EdgeEvent>(primsBoth * 2 * PointType::dim),
2201 *newEventsRightStart = rightAlloc.allocate<EdgeEvent>(primsBoth * 2 * PointType::dim);
2203 EdgeEvent *leftEventsTempEnd = leftEventsTempStart,
2204 *rightEventsTempEnd = rightEventsTempStart,
2205 *newEventsLeftEnd = newEventsLeftStart,
2206 *newEventsRightEnd = newEventsRightStart;
2208 for (EdgeEvent *event = eventStart;
event<eventEnd; ++event) {
2209 int classification = storage.
get(event->index);
2211 if (classification == ELeftSide) {
2213 *leftEventsTempEnd++ = *event;
2214 }
else if (classification == ERightSide) {
2216 *rightEventsTempEnd++ = *event;
2217 }
else if (classification == EBothSides) {
2222 AABBType clippedLeft = cast()->getClippedAABB(index, leftNodeAABB);
2223 AABBType clippedRight = cast()->getClippedAABB(index, rightNodeAABB);
2225 KDAssert(leftNodeAABB.contains(clippedLeft));
2226 KDAssert(rightNodeAABB.contains(clippedRight));
2228 if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
2229 for (
int axis=0; axis<PointType::dim; ++axis) {
2230 float min = clippedLeft.min[axis],
2231 max = clippedLeft.max[axis];
2234 *newEventsLeftEnd++ = EdgeEvent(
2235 EdgeEvent::EEdgePlanar,
2238 *newEventsLeftEnd++ = EdgeEvent(
2239 EdgeEvent::EEdgeStart,
2241 *newEventsLeftEnd++ = EdgeEvent(
2242 EdgeEvent::EEdgeEnd,
2250 if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) {
2251 for (
int axis=0; axis<PointType::dim; ++axis) {
2252 float min = clippedRight.min[axis],
2253 max = clippedRight.max[axis];
2256 *newEventsRightEnd++ = EdgeEvent(
2257 EdgeEvent::EEdgePlanar,
2260 *newEventsRightEnd++ = EdgeEvent(
2261 EdgeEvent::EEdgeStart,
2263 *newEventsRightEnd++ = EdgeEvent(
2264 EdgeEvent::EEdgeEnd,
2274 storage.
set(index, EBothSidesProcessed);
2278 KDAssert((
SizeType) (leftEventsTempEnd - leftEventsTempStart) <= primsLeft * 2 * PointType::dim);
2279 KDAssert((
SizeType) (rightEventsTempEnd - rightEventsTempStart) <= primsRight * 2 * PointType::dim);
2280 KDAssert((
SizeType) (newEventsLeftEnd - newEventsLeftStart) <= primsBoth * 2 * PointType::dim);
2281 KDAssert((
SizeType) (newEventsRightEnd - newEventsRightStart) <= primsBoth * 2 * PointType::dim);
2282 ctx.pruned += prunedLeft + prunedRight;
2285 std::sort(newEventsLeftStart, newEventsLeftEnd, EdgeEventOrdering());
2286 std::sort(newEventsRightStart, newEventsRightEnd, EdgeEventOrdering());
2289 leftEventsEnd = std::merge(leftEventsTempStart,
2290 leftEventsTempEnd, newEventsLeftStart, newEventsLeftEnd,
2291 leftEventsStart, EdgeEventOrdering());
2294 rightEventsEnd = std::merge(rightEventsTempStart,
2295 rightEventsTempEnd, newEventsRightStart, newEventsRightEnd,
2296 rightEventsStart, EdgeEventOrdering());
2299 leftAlloc.
release(newEventsLeftStart);
2300 leftAlloc.
release(leftEventsTempStart);
2301 rightAlloc.release(newEventsRightStart);
2302 rightAlloc.release(rightEventsTempStart);
2304 for (EdgeEvent *event = eventStart;
event < eventEnd; ++event) {
2305 int classification = storage.
get(event->index);
2307 if (classification == ELeftSide) {
2309 *leftEventsEnd++ = *event;
2310 }
else if (classification == ERightSide) {
2312 *rightEventsEnd++ = *event;
2313 }
else if (classification == EBothSides) {
2316 *leftEventsEnd++ = *event;
2317 *rightEventsEnd++ = *event;
2320 KDAssert((
SizeType) (leftEventsEnd - leftEventsStart) <= bestSplit.numLeft * 2 * PointType::dim);
2321 KDAssert((
SizeType) (rightEventsEnd - rightEventsStart) <= bestSplit.numRight * 2 * PointType::dim);
2326 ctx.leftAlloc.shrinkAllocation(leftEventsStart,
2327 leftEventsEnd - leftEventsStart);
2329 ctx.rightAlloc.shrinkAllocation(rightEventsStart,
2330 rightEventsEnd - rightEventsStart);
2336 KDNode *children = ctx.nodes.allocate(2);
2340 SizeType leafNodeCountBeforeSplit = ctx.leafNodeCount;
2341 SizeType nonemptyLeafNodeCountBeforeSplit = ctx.nonemptyLeafNodeCount;
2342 SizeType innerNodeCountBeforeSplit = ctx.innerNodeCount;
2344 if (!node->initInnerNode(bestSplit.axis, bestSplit.pos, children-node)) {
2347 m_indirections.push_back(children);
2350 node->initIndirectionNode(bestSplit.axis, bestSplit.pos,
2353 ctx.innerNodeCount++;
2355 Float leftCost = buildTree(ctx, depth+1, children,
2356 leftNodeAABB, leftEventsStart, leftEventsEnd,
2357 bestSplit.numLeft - prunedLeft,
true, badRefines);
2359 Float rightCost = buildTree(ctx, depth+1, children+1,
2360 rightNodeAABB, rightEventsStart, rightEventsEnd,
2361 bestSplit.numRight - prunedRight,
false, badRefines);
2363 std::pair<Float, Float> prob = tch(bestSplit.axis,
2364 bestSplit.pos - nodeAABB.min[bestSplit.axis],
2365 nodeAABB.max[bestSplit.axis] - bestSplit.pos);
2369 Float finalCost = m_traversalCost +
2370 (prob.first * leftCost + prob.second * rightCost);
2374 ctx.rightAlloc.release(rightEventsStart);
2376 ctx.leftAlloc.release(leftEventsStart);
2382 if (!m_retract || finalCost < primCount * m_queryCost) {
2387 ctx.nodes.resize(nodePosBeforeSplit);
2388 ctx.retractedSplits++;
2389 ctx.leafNodeCount = leafNodeCountBeforeSplit;
2390 ctx.nonemptyLeafNodeCount = nonemptyLeafNodeCountBeforeSplit;
2391 ctx.innerNodeCount = innerNodeCountBeforeSplit;
2392 createLeafAfterRetraction(ctx, node, indexPosBeforeSplit);
2396 return bestSplit.cost;
2407 m_minBins =
new SizeType[m_binCount*PointType::dim];
2408 m_maxBins =
new SizeType[m_binCount*PointType::dim];
2420 for (
int axis=0; axis<PointType::dim; ++axis) {
2424 m_aabb.min[axis] = min;
2425 m_aabb.max[axis] = max;
2426 m_binSize[axis] = (max-min) / m_binCount;
2427 m_invBinSize[axis] = 1 / m_binSize[axis];
2433 return (
IndexType) std::min((
float) (m_binCount-1), std::max(0.0f, (pos - m_min[axis]) * m_invBinSize[axis]));
2446 m_primCount = primCount;
2447 memset(m_minBins, 0,
sizeof(
SizeType) * PointType::dim * m_binCount);
2448 memset(m_maxBins, 0,
sizeof(
SizeType) * PointType::dim * m_binCount);
2450 for (
SizeType i=0; i<m_primCount; ++i) {
2451 const AABBType aabb = derived->getAABB(indices[i]);
2452 for (
int axis=0; axis<PointType::dim; ++axis) {
2453 m_minBins[axis * m_binCount + computeIndex(
math::castflt_down(aabb.min[axis]), axis)]++;
2454 m_maxBins[axis * m_binCount + computeIndex(
math::castflt_up (aabb.max[axis]), axis)]++;
2466 TreeConstructionHeuristic tch(m_aabb);
2470 for (
int axis=0; axis<PointType::dim; ++axis) {
2471 SizeType numLeft = 0, numRight = m_primCount;
2472 Float leftWidth = 0, rightWidth = m_aabb.max[axis] - m_aabb.min[axis];
2473 const float binSize = m_binSize[axis];
2475 for (
int i=0; i<m_binCount-1; ++i) {
2476 numLeft += m_minBins[binIdx];
2477 numRight -= m_maxBins[binIdx];
2478 leftWidth += binSize;
2479 rightWidth -= binSize;
2480 std::pair<Float, Float> prob =
2481 tch(axis, leftWidth, rightWidth);
2483 Float cost = traversalCost + queryCost
2484 * (prob.first * numLeft + prob.second * numRight);
2486 if (cost < candidate.
cost) {
2487 candidate.
cost = cost;
2488 candidate.
axis = axis;
2499 KDAssert(candidate.
cost != std::numeric_limits<Float>::infinity() &&
2512 const AABBType &right,
IndexType *rightIndices) :
2513 left(left), leftIndices(leftIndices), right(right),
2514 rightIndices(rightIndices) { }
2526 SizeType numLeft = 0, numRight = 0;
2527 AABBType leftBounds, rightBounds;
2528 const int axis = split.
axis;
2533 leftIndices = primIndices;
2538 rightIndices = primIndices;
2541 for (
SizeType i=0; i<m_primCount; ++i) {
2542 const IndexType primIndex = primIndices[i];
2543 const AABBType aabb = derived->getAABB(primIndex);
2547 if (endIdx <= split.
leftBin) {
2549 leftBounds.expandBy(aabb);
2550 leftIndices[numLeft++] = primIndex;
2551 }
else if (startIdx > split.
leftBin) {
2553 rightBounds.expandBy(aabb);
2554 rightIndices[numRight++] = primIndex;
2556 leftBounds.expandBy(aabb);
2557 rightBounds.expandBy(aabb);
2560 leftIndices[numLeft++] = primIndex;
2561 rightIndices[numRight++] = primIndex;
2564 leftBounds.clip(m_aabb);
2565 rightBounds.clip(m_aabb);
2566 split.
pos = m_min[axis] + m_binSize[axis] * (split.
leftBin + 1);
2567 leftBounds.max[axis] = std::min(leftBounds.max[axis], (
Float) split.
pos);
2568 rightBounds.min[axis] = std::max(rightBounds.min[axis], (
Float) split.
pos);
2579 return Partition(leftBounds, leftIndices,
2580 rightBounds, rightIndices);
2587 float m_min[PointType::dim];
2588 float m_binSize[PointType::dim];
2589 float m_invBinSize[PointType::dim];
2612 #if defined(_MSC_VER)
2616 #pragma float_control(precise, off)
2620 template <
typename AABBType>
2622 =
new Class(
"KDTreeBase",
true,
"Object");
2624 template <
typename AABBType>
IndexType * m_indices
Definition: gkdtree.h:2594
#define KDAssertEx(expr, text)
Definition: gkdtree.h:57
IndexType computeIndex(float pos, int axis)
Compute the bin location for a given position and axis.
Definition: gkdtree.h:2432
EMask
Definition: gkdtree.h:482
~OrderedChunkAllocator()
Definition: gkdtree.h:86
SizeType getMaxDepth() const
Return maximum tree depth (0 = use heuristic)
Definition: gkdtree.h:835
OrderedChunkAllocator leftAlloc
Definition: gkdtree.h:1380
T & operator[](size_t index)
Definition: gkdtree.h:322
#define KDLog(level, fmt,...)
Definition: gkdtree.h:642
Data type for split candidates computed by the O(n log n) greedy optimization method.
Definition: gkdtree.h:1347
MTS_EXPORT_CORE std::string formatString(const char *pFmt,...)
Wrapped snprintf.
size_t getChunkCount() const
Definition: gkdtree.h:201
SizeType getMinMaxBins() const
Return the number of bins used for Min-Max binning.
Definition: gkdtree.h:828
Parent::SizeType SizeType
Definition: gkdtree.h:715
Communication data structure used to pass jobs to kd-tree builder threads.
Definition: gkdtree.h:1441
ref< ConditionVariable > condJobTaken
Definition: gkdtree.h:1444
void resize(size_t pos)
Resize the vector to the given size.
Definition: gkdtree.h:361
size_t used() const
Return the total amount of used memory in bytes.
Definition: gkdtree.h:217
std::string toString() const
Definition: gkdtree.h:1360
void createLeaf(BuildContext &ctx, KDNode *node, EdgeEvent *eventStart, EdgeEvent *eventEnd, SizeType primCount)
Leaf node creation helper function.
Definition: gkdtree.h:1607
EventList(EdgeEvent *start, EdgeEvent *end, SizeType primCount)
Definition: gkdtree.h:1541
Describes the beginning or end of a primitive when projected onto a certain dimension.
Definition: gkdtree.h:1282
FINLINE const KDNode *__restrict getLeft() const
Return the left child (assuming that this is an interior node)
Definition: gkdtree.h:551
Float getQueryCost() const
Return the query cost used by the tree construction heuristic (This is the average cost for testing a...
Definition: gkdtree.h:791
const T & operator[](size_t index) const
Definition: gkdtree.h:327
std::string toString() const
Return a string representation of the chunks.
Definition: gkdtree.h:228
float castflt_up(float val)
Cast to single precision and round up if not exactly representable (passthrough)
Definition: math.h:281
void setMaxBadRefines(SizeType maxBadRefines)
Set the number of bad refines allowed to happen in succession before a leaf node will be created...
Definition: gkdtree.h:873
void initLeafNode(unsigned int offset, unsigned int numPrims)
Initialize a leaf kd-Tree node.
Definition: gkdtree.h:492
KDNode * m_nodes
Definition: gkdtree.h:629
bool planarLeft
Definition: gkdtree.h:1352
BuildContext & getContext()
Definition: gkdtree.h:1516
Partition(const AABBType &left, IndexType *leftIndices, const AABBType &right, IndexType *rightIndices)
Definition: gkdtree.h:2511
int get(uint32_t index) const
Definition: gkdtree.h:421
SizeType m_stopPrims
Definition: gkdtree.h:2600
ClassificationStorage classStorage
Definition: gkdtree.h:1383
uint32_t combined
Definition: gkdtree.h:463
ELogLevel m_logLevel
Definition: gkdtree.h:630
FINLINE IndexType getPrimStart() const
Assuming this is a leaf node, return the first primitive index.
Definition: gkdtree.h:536
BlockedVector()
Definition: gkdtree.h:273
SizeType primIndexCount
Definition: gkdtree.h:1389
EClassificationResult
Primitive classification during tree-construction.
Definition: gkdtree.h:1267
Condition variable synchronization primitive. Can be used to wait for a condition to become true in a...
Definition: lock.h:106
float pos
Definition: gkdtree.h:1349
bool isBuilt() const
Return whether or not the kd-tree has been built.
Definition: gkdtree.h:615
BuildContext(SizeType primCount, SizeType binCount)
Definition: gkdtree.h:1393
void setAABB(const AABBType &aabb)
Prepare to bin for the specified bounds.
Definition: gkdtree.h:2419
Compact storage for primitive classifcation.
Definition: gkdtree.h:394
SizeType leafNodeCount
Definition: gkdtree.h:1386
void createLeafAfterRetraction(BuildContext &ctx, KDNode *node, SizeType start)
Leaf node creation helper function.
Definition: gkdtree.h:1665
Float m_queryCost
Definition: gkdtree.h:2596
KDNode * node
Definition: gkdtree.h:1450
void setQueryCost(Float queryCost)
Set the query cost used by the tree construction heuristic (This is the average cost for testing a co...
Definition: gkdtree.h:782
OrderedChunkAllocator rightAlloc
Definition: gkdtree.h:1380
void push_back(const T &value)
Append an element to the end.
Definition: gkdtree.h:282
void setMinMaxBins(SizeType minMaxBins)
Set the number of bins used for Min-Max binning.
Definition: gkdtree.h:821
#define KDAssert(expr)
Definition: gkdtree.h:56
bool getClip() const
Return whether or not to use primitive clipping will be used in the tree construction.
Definition: gkdtree.h:851
unsigned int type
Event type: end/planar/start.
Definition: gkdtree.h:1323
const KDNode * getRoot() const
Return the root node of the kd-tree.
Definition: gkdtree.h:610
Min-max binning as described in "Highly Parallel Fast KD-tree Construction for Interactive Ray Traci...
Definition: gkdtree.h:2405
size_t size() const
Return the total amount of chunk memory in bytes.
Definition: gkdtree.h:206
void createLeaf(BuildContext &ctx, KDNode *node, SizeType *indices, SizeType primCount)
Leaf node creation helper function.
Definition: gkdtree.h:1640
ELogLevel getLogLevel() const
Return the log level of kd-tree status messages.
Definition: gkdtree.h:604
Float m_emptySpaceBonus
Definition: gkdtree.h:2597
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
Debug message, usually turned off.
Definition: formatter.h:30
std::map< const KDNode *, IndexType > threadMap
Definition: gkdtree.h:1445
Base class of all kd-trees.
Definition: gkdtree.h:441
void initIndirectionNode(int axis, float split, uint32_t indirectionEntry)
Initialize an interior indirection node.
Definition: gkdtree.h:517
EventList createEventList(OrderedChunkAllocator &alloc, const AABBType &nodeAABB, IndexType *prims, SizeType primCount)
Create an edge event list for a given list of primitives.
Definition: gkdtree.h:1551
float pos
Plane position.
Definition: gkdtree.h:1319
SizeType getStopPrims() const
Return the number of primitives, at which recursion will stop when building the tree.
Definition: gkdtree.h:897
#define MTS_KD_AABB_EPSILON
To avoid numerical issues, the size of the scene bounding box is increased by this amount...
Definition: gkdtree.h:50
SizeType m_exactPrimThreshold
Definition: gkdtree.h:2602
size_t blockCount() const
Return the number of allocated blocks.
Definition: gkdtree.h:343
SizeType m_maxBadRefines
Definition: gkdtree.h:2601
void setClip(bool clip)
Specify whether or not to use primitive clipping will be used in the tree construction.
Definition: gkdtree.h:843
SizeType nonemptyLeafNodeCount
Definition: gkdtree.h:1387
AABBType aabb
Definition: gkdtree.h:946
Float getEmptySpaceBonus() const
Return the bonus factor for empty space used by the tree construction heuristic.
Definition: gkdtree.h:807
const GenericKDTree::BuildContext * context
Definition: gkdtree.h:945
SizeType getExactPrimitiveThreshold() const
Return the number of primitives, at which the builder will switch from (approximate) Min-Max binning ...
Definition: gkdtree.h:931
void setTraversalCost(Float traversalCost)
Set the traversal cost used by the tree construction heuristic.
Definition: gkdtree.h:761
bool operator()(const EdgeEvent &a, const EdgeEvent &b) const
Definition: gkdtree.h:1332
uint32_t SizeType
Size number format.
Definition: gkdtree.h:447
#define MTS_KD_MAXDEPTH
Activate lots of extra checks.
Definition: gkdtree.h:37
void unlock()
Definition: lock.h:211
IndexType * getIndices() const
Returns the underlying kd-tree index buffer.
Definition: gkdtree.h:768
SizeType primCount
Definition: gkdtree.h:1539
MinMaxBins minMaxBins
Definition: gkdtree.h:1384
SizeType retractedSplits
Definition: gkdtree.h:1390
void printStats(ELogLevel level)
Definition: gkdtree.h:1411
void accumulateStatisticsFrom(const BuildContext &ctx)
Definition: gkdtree.h:1427
~BlockedVector()
Definition: gkdtree.h:275
More relevant debug / information message.
Definition: formatter.h:31
std::string toString() const
Return a string representation.
Definition: gkdtree.h:1298
Simple RAII-style locking of a Mutex. On construction it locks the mutex and unlocks it on destructio...
Definition: lock.h:170
SizeType numLeft
Definition: gkdtree.h:1351
SizeType numRight
Definition: gkdtree.h:1351
size_t size() const
Return the currently used number of items.
Definition: gkdtree.h:336
int depth
Definition: gkdtree.h:1449
unsigned int axis
Event axis.
Definition: gkdtree.h:1325
void shrinkAllocation(T *ptr, size_t newSize)
Shrink the size of the last allocated chunk.
Definition: gkdtree.h:175
~ClassificationStorage()
Definition: gkdtree.h:399
AABBType m_tightAABB
Definition: gkdtree.h:631
EdgeEvent * eventStart
Definition: gkdtree.h:1452
bool initInnerNode(int axis, float split, ptrdiff_t relOffset)
Definition: gkdtree.h:501
void setPrimitiveCount(size_t size)
Definition: gkdtree.h:404
KD-tree node in 8 bytes.
Definition: gkdtree.h:452
SplitCandidate()
Definition: gkdtree.h:1355
FINLINE int getAxis() const
Return the split axis (assuming that this is an interior node)
Definition: gkdtree.h:581
void setStopPrims(SizeType stopPrims)
Set the number of primitives, at which recursion will stop when building the tree.
Definition: gkdtree.h:889
std::vector< TreeBuilder * > m_builders
Definition: gkdtree.h:2606
OrderedChunkAllocator(size_t minAllocation=512 *1024)
Definition: gkdtree.h:81
MinMaxBins(SizeType nBins)
Definition: gkdtree.h:2406
SizeType m_nodeCount
Definition: gkdtree.h:2604
void forget()
Forget about all chunks without actually freeing them. This is useful when the chunks have been merge...
Definition: gkdtree.h:114
T *__restrict allocate(size_t size)
Allocate a certain number of elements and return a pointer to the first one.
Definition: gkdtree.h:300
ref< Mutex > mutex
Definition: gkdtree.h:1443
Once the tree has been constructed, it is rewritten into a more convenient binary storage format...
Definition: gkdtree.h:942
BlockedVector< IndexType,(512 *1024/sizeof(uint32_t)) > indices
Definition: gkdtree.h:1382
BlockedVector< KDNode,(512 *1024/sizeof(KDNode)) > nodes
Definition: gkdtree.h:1381
MTS_EXPORT_CORE void *__restrict allocAligned(size_t size)
Allocate an aligned region of memory.
BuildInterface m_interface
Definition: gkdtree.h:2609
void set(uint32_t index, int value)
Definition: gkdtree.h:415
GenericKDTree()
Create a new kd-tree instance initialized with the default parameters.
Definition: gkdtree.h:732
void clear()
Release all memory.
Definition: gkdtree.h:371
TreeBuilder(IndexType id, GenericKDTree *parent)
Definition: gkdtree.h:1470
void merge(const OrderedChunkAllocator &other)
Merge the chunks of another allocator into this one.
Definition: gkdtree.h:103
void setParallelBuild(bool parallel)
Specify whether or not tree construction should run in parallel.
Definition: gkdtree.h:905
IndexType * rightIndices
Definition: gkdtree.h:2509
MTS_EXPORT_CORE int getCoreCount()
Determine the number of available CPU cores.
SizeType m_maxDepth
Definition: gkdtree.h:2599
int badRefines
Definition: gkdtree.h:1454
KDNode * target
Definition: gkdtree.h:944
uint32_t IndexType
Index number format (max 2^32 prims)
Definition: gkdtree.h:444
T *__restrict allocate(size_t size)
Request a block of memory from the allocator.
Definition: gkdtree.h:124
ClassificationStorage()
Definition: gkdtree.h:396
Definition: gkdtree.h:2505
Per-thread context used to manage memory allocations, also records some useful statistics.
Definition: gkdtree.h:1379
kd-tree builder thread
Definition: gkdtree.h:1468
void setLogLevel(ELogLevel level)
Return the log level of kd-tree status messages.
Definition: gkdtree.h:607
size_t size() const
Definition: gkdtree.h:427
const KDNode * node
Definition: gkdtree.h:943
#define SAssert(cond)
``Static'' assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
float split
Split plane coordinate.
Definition: gkdtree.h:466
FINLINE const KDNode *__restrict getRight() const
Return the left child (assuming that this is an interior node)
Definition: gkdtree.h:568
#define MTS_DECLARE_CLASS()
This macro must be used in the initial definition in classes that derive from Object.
Definition: class.h:158
Optimized KD-tree acceleration data structure for n-dimensional (n<=4) shapes and various queries on ...
Definition: gkdtree.h:706
void setMaxDepth(SizeType maxDepth)
Set the maximum tree depth (0 = use heuristic)
Definition: gkdtree.h:814
AABBType::VectorType VectorType
Definition: gkdtree.h:720
Reference counting helper.
Definition: ref.h:40
Warning message.
Definition: formatter.h:32
AABBType right
Definition: gkdtree.h:2508
Parent::KDNode KDNode
Definition: gkdtree.h:717
AABBType left
Definition: gkdtree.h:2506
FINLINE float getSplit() const
Return the split plane location (assuming that this is an interior node)
Definition: gkdtree.h:576
Stores meta-information about Object instances.
Definition: class.h:43
Basic vector implementation, which stores all data in a list of fixed-sized blocks.
Definition: gkdtree.h:271
RewriteItem(const KDNode *node, KDNode *target, const typename GenericKDTree::BuildContext *context, const AABBType &aabb)
Definition: gkdtree.h:948
BuildInterface()
Definition: gkdtree.h:1456
Cross-platform thread implementation.
Definition: thread.h:34
KDTreeBase< AABBType > Parent
Definition: gkdtree.h:711
MTS_EXPORT_CORE std::string memString(size_t size, bool precise=false)
Turn a memory size into a human-readable string.
SizeType innerNodeCount
Definition: gkdtree.h:1388
Platform independent milli/micro/nanosecond timerThis class implements a simple cross-platform timer ...
Definition: timer.h:37
ELogLevel
Available Log message types.
Definition: formatter.h:28
FINLINE IndexType getIndirectionIndex() const
Return the index of an indirection node.
Definition: gkdtree.h:546
Special "ordered" memory allocator.
Definition: gkdtree.h:79
Parent::IndexType IndexType
Definition: gkdtree.h:716
Error message, causes an exception to be thrown.
Definition: formatter.h:33
Float transitionToNLogN(BuildContext &ctx, unsigned int depth, KDNode *node, const AABBType &nodeAABB, IndexType *indices, SizeType primCount, bool isLeftChild, SizeType badRefines)
Implements the transition from min-max-binning to the O(n log n) optimization.
Definition: gkdtree.h:1729
EdgeEvent(uint16_t type, int axis, float pos, IndexType index)
Create a new edge event.
Definition: gkdtree.h:1294
IndexType index
Primitive index.
Definition: gkdtree.h:1321
Float getTraversalCost() const
Return the traversal cost used by the tree construction heuristic.
Definition: gkdtree.h:773
void bin(const Derived *derived, IndexType *indices, SizeType primCount)
Run min-max binning.
Definition: gkdtree.h:2444
Edge event comparison functor.
Definition: gkdtree.h:1331
void setRetract(bool retract)
Specify whether or not bad splits can be "retracted".
Definition: gkdtree.h:858
FINLINE bool isIndirection() const
Is this an indirection node?
Definition: gkdtree.h:531
ref< Mutex > m_indirectionLock
Definition: gkdtree.h:2608
virtual ~GenericKDTree()
Release all memory.
Definition: gkdtree.h:751
void release(T *ptr)
Definition: gkdtree.h:149
AABBType::PointType PointType
Definition: gkdtree.h:719
std::vector< KDNode * > m_indirections
Definition: gkdtree.h:2607
EdgeEvent * start
Definition: gkdtree.h:1538
std::string toString() const
Return a string representation.
Definition: gkdtree.h:586
bool getParallelBuild() const
Return whether or not tree construction will run in parallel.
Definition: gkdtree.h:913
FINLINE bool isLeaf() const
Is this a leaf node?
Definition: gkdtree.h:526
void cleanup()
Release all memory used by the allocator.
Definition: gkdtree.h:93
size_t capacity() const
Return the total capacity.
Definition: gkdtree.h:350
SizeType m_minMaxBins
Definition: gkdtree.h:2603
uint32_t end
End offset of the primitive list.
Definition: gkdtree.h:478
MTS_EXPORT_CORE void freeAligned(void *ptr)
Free an aligned region of memory.
Definition: gkdtree.h:1537
const AABBType & getAABB() const
Return a (slightly enlarged) axis-aligned bounding box containing all primitives. ...
Definition: gkdtree.h:620
EEventType
Possible event types.
Definition: gkdtree.h:1284
int leftBin
Definition: gkdtree.h:1353
SizeType getMaxBadRefines() const
Return the number of bad refines allowed to happen in succession before a leaf node will be created...
Definition: gkdtree.h:881
const AABBType & getTightAABB() const
Return a tight axis-aligned bounding box containing all primitives.
Definition: gkdtree.h:623
void run()
The thread's run method.
Definition: gkdtree.h:1485
IndexType * leftIndices
Definition: gkdtree.h:2507
size_t size()
Definition: gkdtree.h:1404
Float cost
Definition: gkdtree.h:1348
Parent of all Mitsuba classes.
Definition: object.h:38
SizeType primCount
Definition: gkdtree.h:1453
float castflt_down(float val)
Cast to single precision and round down if not exactly representable (passthrough) ...
Definition: math.h:297
MTS_EXPORT_CORE int log2i(uint32_t value)
Base-2 logarithm (32-bit integer version)
void buildInternal()
Build a KD-tree over the supplied geometry.
Definition: gkdtree.h:958
#define MTS_KD_MIN_ALLOC
OrderedChunkAllocator: don't create chunks smaller than 512 KiB.
Definition: gkdtree.h:40
bool m_retract
Definition: gkdtree.h:2598
AABBType nodeAABB
Definition: gkdtree.h:1451
Derived * cast()
Cast to the derived class.
Definition: gkdtree.h:1528
const Derived * cast() const
Cast to the derived class (const version)
Definition: gkdtree.h:1533
Partition partition(BuildContext &ctx, const Derived *derived, IndexType *primIndices, SplitCandidate &split, bool isLeftChild, Float traversalCost, Float queryCost)
Given a suitable split candiate, compute tight bounding boxes for the left and right subtrees and ret...
Definition: gkdtree.h:2522
FINLINE const KDNode *__restrict getSibling() const
Return the sibling of the current node.
Definition: gkdtree.h:557
AABBType::Scalar Scalar
Definition: gkdtree.h:718
bool getRetract() const
Return whether or not bad splits can be "retracted".
Definition: gkdtree.h:865
SplitCandidate minimizeCost(Float traversalCost, Float queryCost)
Evaluate the tree construction heuristic at each bin boundary and return the minimizer for the given ...
Definition: gkdtree.h:2465
Float buildTree(BuildContext &ctx, unsigned int depth, KDNode *node, const AABBType &nodeAABB, EdgeEvent *eventStart, EdgeEvent *eventEnd, SizeType primCount, bool isLeftChild, SizeType badRefines)
Definition: gkdtree.h:1954
void setExactPrimitiveThreshold(SizeType exactPrimThreshold)
Specify the number of primitives, at which the builder will switch from (approximate) Min-Max binning...
Definition: gkdtree.h:922
SizeType m_indexCount
Definition: gkdtree.h:2605
Float m_traversalCost
Definition: gkdtree.h:2595
Thin wrapper around the recursive boost thread lock.
Definition: lock.h:34
In addition to providing RAII-style locking, UniqueLock also allows for deferred locking until lock()...
Definition: lock.h:192
SizeType pruned
Definition: gkdtree.h:1391
bool done
Definition: gkdtree.h:1446
FINLINE IndexType getPrimEnd() const
Assuming this is a leaf node, return the last primitive index.
Definition: gkdtree.h:541
FINLINE KDNode *__restrict getLeft()
Return the left child (assuming that this is an interior node)
Definition: gkdtree.h:562
int axis
Definition: gkdtree.h:1350
Float buildTreeMinMax(BuildContext &ctx, unsigned int depth, KDNode *node, const AABBType &nodeAABB, const AABBType &tightAABB, IndexType *indices, SizeType primCount, bool isLeftChild, SizeType badRefines)
Build helper function (min-max binning)
Definition: gkdtree.h:1792
~TreeBuilder()
Definition: gkdtree.h:1480
~MinMaxBins()
Definition: gkdtree.h:2411
void setEmptySpaceBonus(Float emptySpaceBonus)
Set the bonus factor for empty space used by the tree construction heuristic.
Definition: gkdtree.h:799
EdgeEvent()
Dummy constructor.
Definition: gkdtree.h:1291