From baa41a195aec80c0160e6220d3aa33381ebde890 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Mon, 11 Oct 2010 21:04:05 +0200 Subject: [PATCH] cleanups --- include/mitsuba/render/gkdtree.h | 266 ++++++++++++++++++++++++++----- src/tests/test_kd.cpp | 2 +- 2 files changed, 226 insertions(+), 42 deletions(-) diff --git a/include/mitsuba/render/gkdtree.h b/include/mitsuba/render/gkdtree.h index 1e7dfa47..fed27367 100644 --- a/include/mitsuba/render/gkdtree.h +++ b/include/mitsuba/render/gkdtree.h @@ -174,7 +174,7 @@ public: } } #if defined(MTS_KD_DEBUG) - /* Uh oh, allocation could not be found. Check if it has size==0 */ + /* Uh oh, allocation could not be found. Check if it has size == 0 */ if (newSize == 0) { for (std::vector::iterator it = m_chunks.begin(); it != m_chunks.end(); ++it) { @@ -476,9 +476,12 @@ public: m_exactPrimThreshold = 65536; m_maxDepth = 0; m_retract = true; - m_parallel = true; + m_parallelBuild = true; } + /** + * \brief Release all memory + */ virtual ~GenericKDTree() { if (m_indices) delete[] m_indices; @@ -486,6 +489,160 @@ public: delete[] m_nodes; } + /** + * \brief Set the traversal cost used by the surface area heuristic + */ + inline void setTraversalCost(Float traversalCost) { + m_traversalCost = traversalCost; + } + + /** + * \brief Return the traversal cost used by the surface area heuristic + */ + inline Float getTraversalCost() const { + return m_traversalCost; + } + + /** + * \brief Set the intersection cost used by the surface area heuristic + */ + inline void setIntersectionCost(Float intersectionCost) { + m_intersectionCost = intersectionCost; + } + + /** + * \brief Return the intersection cost used by the surface area heuristic + */ + inline Float getIntersectionCost() const { + return m_intersectionCost; + } + + /** + * \brief Set the bonus factor for empty space used by the + * surface area heuristic + */ + inline void setEmptySpaceBonus(Float emptySpaceBonus) { + m_emptySpaceBonus = emptySpaceBonus; + } + + /** + * \brief Return the bonus factor for empty space used by the + * surface area heuristic + */ + inline Float getEmptySpaceBonus() const { + return m_emptySpaceBonus; + } + + /** + * \brief Set the maximum tree depth (0 = use heuristic) + */ + inline void setMaxDepth(size_type maxDepth) { + m_maxDepth = maxDepth; + } + + /** + * \brief Return maximum tree depth (0 = use heuristic) + */ + inline size_type getMaxDepth() const { + return m_maxDepth; + } + + /** + * \brief Specify whether or not to use primitive clipping will + * be used in the tree construction. + */ + inline void setClip(bool clip) { + m_clip = clip; + } + + /** + * \brief Return whether or not to use primitive clipping will + * be used in the tree construction. + */ + inline bool getClip() const { + return m_clip; + } + + /** + * \brief Specify whether or not bad splits can be "retracted". + */ + inline void setRetract(bool retract) { + m_retract = retract; + } + + /** + * \brief Return whether or not bad splits can be "retracted". + */ + inline bool getRetract() const { + return m_retract; + } + + /** + * \brief Set the number of bad refines allowed to happen + * in succession before a leaf node will be created. + */ + inline void setMaxBadRefines(size_type maxBadRefines) { + m_maxBadRefines = maxBadRefines; + } + + /** + * \brief Return the number of bad refines allowed to happen + * in succession before a leaf node will be created. + */ + inline size_type getMaxBadRefines() const { + return m_maxBadRefines; + } + + /** + * \brief Set the number of primitives, at which recursion will + * stop when building the tree. + */ + inline void setStopPrims(size_type stopPrims) { + m_stopPrims = stopPrims; + } + + /** + * \brief Return the number of primitives, at which recursion will + * stop when building the tree. + */ + inline size_type getStopPrims() const { + return m_stopPrims; + } + + /** + * \brief Specify whether or not tree construction + * should run in parallel. + */ + inline void setParallelBuild(bool parallel) { + m_parallelBuild = parallel; + } + + /** + * \brief Return whether or not tree construction + * will run in parallel. + */ + inline bool getParallelBuild() const { + return m_parallelBuild; + } + + /** + * \brief Specify the number of primitives, at which the builder will switch + * from (approximate) Min-Max binning to the accurate O(n log n) SAH-based + * optimization method. + */ + inline void setExactPrimitiveThreshold(bool exactPrimThreshold) { + m_exactPrimThreshold = exactPrimThreshold; + } + + /** + * \brief Return the number of primitives, at which the builder will switch + * from (approximate) Min-Max binning to the accurate O(n log n) SAH-based + * optimization method. + */ + inline bool getExactPrimitiveThreshold() const { + return m_exactPrimThreshold; + } + /** * \brief Build a KD-tree over supplied geometry */ @@ -525,7 +682,8 @@ public: Log(EDebug, " Scene bounding box (min) : %s", m_aabb.min.toString().c_str()); Log(EDebug, " Scene bounding box (max) : %s", m_aabb.max.toString().c_str()); Log(EDebug, " Min-max bins : %i", MTS_KD_MINMAX_BINS); - Log(EDebug, " Greedy SAH optimization : use for <= %i primitives", m_exactPrimThreshold); + Log(EDebug, " Greedy SAH optimization : use for <= %i primitives", + m_exactPrimThreshold); Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no"); Log(EDebug, " Retract bad splits : %s", m_retract ? "yes" : "no"); Log(EDebug, " Stopping primitive count : %i", m_stopPrims); @@ -533,9 +691,9 @@ public: size_type procCount = getProcessorCount(); if (procCount == 1) - m_parallel = false; + m_parallelBuild = false; - if (m_parallel) { + if (m_parallelBuild) { m_builders.resize(procCount); for (size_type i=0; ibroadcast(); for (size_type i=0; igetSplit(); bool result = target->initInnerNode(axis, split, children - target); if (!result) - Log(EError, "Cannot represent relative pointer -- too many primitives?"); + Log(EError, "Cannot represent relative pointer -- " + "too many primitives?"); Float tmp = aabb.min[axis]; aabb.min[axis] = split; @@ -861,10 +1020,12 @@ protected: leftAlloc.getChunkCount(), memString(leftAlloc.size()).c_str()); Log(EDebug, " Right events : " SIZE_T_FMT " chunks (%s)", rightAlloc.getChunkCount(), memString(rightAlloc.size()).c_str()); - Log(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, " SIZE_T_FMT " blocks (%s)", - nodes.size(), nodes.blockCount(), memString(nodes.capacity() * sizeof(KDNode)).c_str()); - Log(EDebug, " Indices : " SIZE_T_FMT " entries, " SIZE_T_FMT " blocks (%s)", - indices.size(), indices.blockCount(), memString(indices.capacity() * sizeof(index_type)).c_str()); + Log(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, " SIZE_T_FMT + " blocks (%s)", nodes.size(), nodes.blockCount(), + memString(nodes.capacity() * sizeof(KDNode)).c_str()); + Log(EDebug, " Indices : " SIZE_T_FMT " entries, " SIZE_T_FMT + " blocks (%s)", indices.size(), indices.blockCount(), + memString(indices.capacity() * sizeof(index_type)).c_str()); } void accumulateStatisticsFrom(const BuildContext &ctx) { @@ -915,7 +1076,8 @@ protected: /* Bit layout: 31 : False (inner node) 30 : Indirection node flag - 29-3 : Offset to the left child + 29-3 : Offset to the left child + or indirection table entry 2-0 : Split axis */ uint32_t combined; @@ -972,8 +1134,11 @@ protected: * they lie in different memory chunks. In this case, the node * stores an index into a globally shared pointer list. */ - inline void initIndirectionNode(int axis, float split, uint32_t indirectionEntry) { - inner.combined = EIndirectionMask | axis | ((uint32_t) indirectionEntry << 2); + inline void initIndirectionNode(int axis, float split, + uint32_t indirectionEntry) { + inner.combined = EIndirectionMask + | ((uint32_t) indirectionEntry << 2) + | axis; inner.split = split; } @@ -1069,7 +1234,8 @@ protected: int badRefines = m_interface.badRefines; EdgeEvent *eventStart = leftAlloc.allocate(eventCount), *eventEnd = eventStart + eventCount; - memcpy(eventStart, m_interface.eventStart, eventCount * sizeof(EdgeEvent)); + memcpy(eventStart, m_interface.eventStart, + eventCount * sizeof(EdgeEvent)); m_interface.threadMap[node] = m_id; m_interface.node = NULL; m_interface.condJobTaken->signal(); @@ -1110,7 +1276,8 @@ protected: * accurate SAH-based optimizier. */ boost::tuple createEventList( - OrderedChunkAllocator &alloc, const AABB &nodeAABB, index_type *prims, size_type primCount) { + OrderedChunkAllocator &alloc, const AABB &nodeAABB, + index_type *prims, size_type primCount) { size_type initialSize = primCount * 6, actualPrimCount = 0; EdgeEvent *eventStart = alloc.allocate(initialSize); EdgeEvent *eventEnd = eventStart; @@ -1296,11 +1463,12 @@ protected: } if (primCount <= m_exactPrimThreshold) { - OrderedChunkAllocator &alloc = isLeftChild ? ctx.leftAlloc : ctx.rightAlloc; + OrderedChunkAllocator &alloc = isLeftChild + ? ctx.leftAlloc : ctx.rightAlloc; boost::tuple events = createEventList(alloc, nodeAABB, indices, primCount); Float sahCost; - if (m_parallel) { + if (m_parallelBuild) { m_interface.mutex->lock(); m_interface.depth = depth; m_interface.node = node; @@ -1320,10 +1488,11 @@ protected: // Never tear down this subtree (return a SAH cost of -infinity) sahCost = -std::numeric_limits::infinity(); } else { - std::sort(boost::get<0>(events), boost::get<1>(events), EdgeEventOrdering()); + std::sort(boost::get<0>(events), boost::get<1>(events), + EdgeEventOrdering()); sahCost = buildTreeSAH(ctx, depth, node, nodeAABB, - boost::get<0>(events), boost::get<1>(events), boost::get<2>(events), + boost::get<0>(events), boost::get<1>(events), boost::get<2>(events), isLeftChild, badRefines); } alloc.release(boost::get<0>(events)); @@ -1572,7 +1741,8 @@ protected: sahCostPlanarLeft *= m_emptySpaceBonus; if (nL == 0 || nR + numPlanar == 0) sahCostPlanarRight *= m_emptySpaceBonus; - if (sahCostPlanarLeft < bestSplit.sahCost || sahCostPlanarRight < bestSplit.sahCost) { + if (sahCostPlanarLeft < bestSplit.sahCost || + sahCostPlanarRight < bestSplit.sahCost) { bestSplit.pos = pos; bestSplit.axis = axis; if (sahCostPlanarLeft < sahCostPlanarRight) { @@ -1660,8 +1830,8 @@ protected: storage.set(event->index, ELeftSide); primsBoth--; primsLeft++; - } else if (event->pos > bestSplit.pos || (event->pos == bestSplit.pos && - !bestSplit.planarLeft)) { + } else if (event->pos > bestSplit.pos + || (event->pos == bestSplit.pos && !bestSplit.planarLeft)) { storage.set(event->index, ERightSide); primsBoth--; primsRight++; @@ -1701,10 +1871,11 @@ protected: /* ==================================================================== */ if (m_clip) { - EdgeEvent *leftEventsTempStart = leftAlloc.allocate(primsLeft * 6), - *rightEventsTempStart = rightAlloc.allocate(primsRight * 6), - *newEventsLeftStart = leftAlloc.allocate(primsBoth * 6), - *newEventsRightStart = rightAlloc.allocate(primsBoth * 6); + EdgeEvent + *leftEventsTempStart = leftAlloc.allocate(primsLeft * 6), + *rightEventsTempStart = rightAlloc.allocate(primsRight * 6), + *newEventsLeftStart = leftAlloc.allocate(primsBoth * 6), + *newEventsRightStart = rightAlloc.allocate(primsBoth * 6); EdgeEvent *leftEventsTempEnd = leftEventsTempStart, *rightEventsTempEnd = rightEventsTempStart, @@ -1732,13 +1903,17 @@ protected: if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) { for (int axis=0; axis<3; ++axis) { - float min = (float) clippedLeft.min[axis], max = (float) clippedLeft.max[axis]; + float min = (float) clippedLeft.min[axis], + max = (float) clippedLeft.max[axis]; if (min == max) { - *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis, min, index); + *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, + axis, min, index); } else { - *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, axis, min, index); - *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, axis, max, index); + *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, + axis, min, index); + *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, + axis, max, index); } } } else { @@ -1747,13 +1922,17 @@ protected: if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) { for (int axis=0; axis<3; ++axis) { - float min = (float) clippedRight.min[axis], max = (float) clippedRight.max[axis]; + float min = (float) clippedRight.min[axis], + max = (float) clippedRight.max[axis]; if (min == max) { - *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis, min, index); + *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, + axis, min, index); } else { - *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, axis, min, index); - *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, axis, max, index); + *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, + axis, min, index); + *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, + axis, max, index); } } } else { @@ -1922,8 +2101,10 @@ protected: * invBinSize[axis]); int maxIdx = (int) ((aabb.max[axis] - m_aabb.min[axis]) * invBinSize[axis]); - m_maxBins[axis * BinCount + std::max(0, std::min(maxIdx, BinCount-1))]++; - m_minBins[axis * BinCount + std::max(0, std::min(minIdx, BinCount-1))]++; + m_maxBins[axis * BinCount + + std::max(0, std::min(maxIdx, BinCount-1))]++; + m_minBins[axis * BinCount + + std::max(0, std::min(minIdx, BinCount-1))]++; } } } @@ -2025,7 +2206,8 @@ protected: if (idx == leftBin && idxNext > leftBin) break; if (idx < leftBin && idxNext > leftBin) { - /* Insufficient floating point resolution -- a leaf will be created. */ + /* Insufficient floating point resolution + -> a leaf will be created. */ candidate.sahCost = std::numeric_limits::infinity(); break; } @@ -2035,7 +2217,8 @@ protected: } if (split <= m_aabb.min[axis] || split > m_aabb.max[axis]) { - /* Insufficient floating point resolution -- a leaf will be created. */ + /* Insufficient floating point resolution + -> a leaf will be created. */ candidate.sahCost = std::numeric_limits::infinity(); } @@ -2051,7 +2234,8 @@ protected: */ boost::tuple partition( BuildContext &ctx, const Derived *derived, index_type *primIndices, - SplitCandidate &split, bool isLeftChild, Float traversalCost, Float intersectionCost) { + SplitCandidate &split, bool isLeftChild, Float traversalCost, + Float intersectionCost) { const float splitPos = split.pos; const int axis = split.axis; size_type numLeft = 0, numRight = 0; @@ -2155,7 +2339,7 @@ private: Float m_traversalCost; Float m_intersectionCost; Float m_emptySpaceBonus; - bool m_clip, m_retract, m_parallel; + bool m_clip, m_retract, m_parallelBuild; AABB m_aabb; size_type m_maxDepth; size_type m_stopPrims; diff --git a/src/tests/test_kd.cpp b/src/tests/test_kd.cpp index 1eb3457f..0441e314 100644 --- a/src/tests/test_kd.cpp +++ b/src/tests/test_kd.cpp @@ -112,7 +112,7 @@ public: void test02_buildSimple() { Properties bunnyProps("ply"); - bunnyProps.setString("filename", "tools/tests/lucy.ply"); + bunnyProps.setString("filename", "tools/tests/happy.ply"); ref mesh = static_cast (PluginManager::getInstance()-> createObject(TriMesh::m_theClass, bunnyProps));