do a better job at keeping track of statistics

metadata
Wenzel Jakob 2010-10-10 18:10:14 +02:00
parent 87b82cc5e1
commit a1ca92bda2
2 changed files with 63 additions and 48 deletions

View File

@ -28,6 +28,14 @@
#define MTS_KD_MINMAX_BINS 32 ///< Min-max bin count #define MTS_KD_MINMAX_BINS 32 ///< Min-max bin count
#define MTS_KD_MIN_ALLOC 128 ///< Allocate memory in 128 KB chunks #define MTS_KD_MIN_ALLOC 128 ///< Allocate memory in 128 KB chunks
#if 1
#define KDAssert(expr) Assert(expr)
#define KDAssertEx(expr, text) AssertEx(expr, text)
#else
#define KDAssert(expr)
#define KDAssertEx(expr, text)
#endif
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
/** /**
@ -143,7 +151,8 @@ public:
return; return;
} }
} }
SLog(EError, "OrderedChunkAllocator: Internal error in shrinkAllocation"); SLog(EError, "OrderedChunkAllocator: Internal error while"
" releasing memory");
} }
inline size_t getChunkCount() const { return m_chunks.size(); } inline size_t getChunkCount() const { return m_chunks.size(); }
@ -279,8 +288,9 @@ public:
m_clip = true; m_clip = true;
m_stopPrims = 1; m_stopPrims = 1;
m_maxBadRefines = 2; m_maxBadRefines = 2;
m_exactDepth = 1; m_exactPrimThreshold = 1024;
m_maxDepth = 100; m_maxDepth = 0;
m_retract = true;
} }
/** /**
@ -323,8 +333,9 @@ public:
Log(EDebug, " Scene bounding box (min) : %s", m_aabb.min.toString().c_str()); 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, " Scene bounding box (max) : %s", m_aabb.max.toString().c_str());
Log(EDebug, " Min-max bins : %i", MTS_KD_MINMAX_BINS); Log(EDebug, " Min-max bins : %i", MTS_KD_MINMAX_BINS);
Log(EDebug, " Greedy SAH optimization : >= level %i", m_exactDepth); Log(EDebug, " Greedy SAH optimization : <= %i primitives", m_exactPrimThreshold);
Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no"); Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no");
Log(EDebug, " Retract bad splits : %s", m_retract ? "yes" : "no");
Log(EDebug, ""); Log(EDebug, "");
size_type procCount = getProcessorCount(); size_type procCount = getProcessorCount();
@ -342,8 +353,8 @@ public:
m_aabb, m_aabb, indices, primCount, true, 0); m_aabb, m_aabb, indices, primCount, true, 0);
ctx.leftAlloc.release(indices); ctx.leftAlloc.release(indices);
Assert(ctx.leftAlloc.getUsed() == 0); KDAssert(ctx.leftAlloc.getUsed() == 0);
Assert(ctx.rightAlloc.getUsed() == 0); KDAssert(ctx.rightAlloc.getUsed() == 0);
m_interface.done = true; m_interface.done = true;
m_interface.cond->broadcast(); m_interface.cond->broadcast();
@ -738,14 +749,14 @@ protected:
* accurate SAH-based optimizier. * accurate SAH-based optimizier.
*/ */
boost::tuple<EdgeEvent *, EdgeEvent *> createEventList( boost::tuple<EdgeEvent *, EdgeEvent *> createEventList(
OrderedChunkAllocator &alloc, index_type *prims, size_type primCount) { OrderedChunkAllocator &alloc, const AABB &nodeAABB, index_type *prims, size_type primCount) {
size_type initialSize = primCount * 6; size_type initialSize = primCount * 6;
EdgeEvent *eventStart = alloc.allocate<EdgeEvent>(initialSize); EdgeEvent *eventStart = alloc.allocate<EdgeEvent>(initialSize);
EdgeEvent *eventEnd = eventStart; EdgeEvent *eventEnd = eventStart;
for (size_type i=0; i<primCount; ++i) { for (size_type i=0; i<primCount; ++i) {
index_type index = prims[i]; index_type index = prims[i];
AABB aabb = downCast()->getAABB(index); AABB aabb = downCast()->getClippedAABB(index, nodeAABB);
for (int axis=0; axis<3; ++axis) { for (int axis=0; axis<3; ++axis) {
float min = (float) aabb.min[axis], max = (float) aabb.max[axis]; float min = (float) aabb.min[axis], max = (float) aabb.max[axis];
@ -818,7 +829,7 @@ protected:
Float buildTreeMinMax(BuildContext &ctx, unsigned int depth, KDNode *node, Float buildTreeMinMax(BuildContext &ctx, unsigned int depth, KDNode *node,
const AABB &nodeAABB, const AABB &tightAABB, index_type *indices, const AABB &nodeAABB, const AABB &tightAABB, index_type *indices,
size_type primCount, bool isLeftChild, size_type badRefines) { size_type primCount, bool isLeftChild, size_type badRefines) {
Assert(nodeAABB.contains(tightAABB)); KDAssert(nodeAABB.contains(tightAABB));
Float leafCost = primCount * m_intersectionCost; Float leafCost = primCount * m_intersectionCost;
if (primCount <= m_stopPrims || depth >= m_maxDepth) { if (primCount <= m_stopPrims || depth >= m_maxDepth) {
@ -826,10 +837,10 @@ protected:
return leafCost; return leafCost;
} }
if (depth == m_exactDepth) { if (primCount <= m_exactPrimThreshold) {
OrderedChunkAllocator &alloc = isLeftChild ? ctx.leftAlloc : ctx.rightAlloc; OrderedChunkAllocator &alloc = isLeftChild ? ctx.leftAlloc : ctx.rightAlloc;
boost::tuple<EdgeEvent *, EdgeEvent *> events boost::tuple<EdgeEvent *, EdgeEvent *> events
= createEventList(alloc, indices, primCount); = createEventList(alloc, nodeAABB, indices, primCount);
std::sort(boost::get<0>(events), boost::get<1>(events), EdgeEventOrdering()); std::sort(boost::get<0>(events), boost::get<1>(events), EdgeEventOrdering());
@ -888,6 +899,7 @@ protected:
initialIndirectionTableSize); initialIndirectionTableSize);
m_indirectionTable.push_back(children); m_indirectionTable.push_back(children);
} }
ctx.innerNodeCount++;
AABB childAABB(nodeAABB); AABB childAABB(nodeAABB);
childAABB.max[bestSplit.axis] = bestSplit.pos; childAABB.max[bestSplit.axis] = bestSplit.pos;
@ -921,9 +933,8 @@ protected:
/* Final decision */ /* Final decision */
/* ==================================================================== */ /* ==================================================================== */
if (finalSAHCost < primCount * m_intersectionCost) { if (!m_retract || finalSAHCost < primCount * m_intersectionCost) {
ctx.expTraversalSteps += nodeAABB.getSurfaceArea(); ctx.expTraversalSteps += nodeAABB.getSurfaceArea();
ctx.innerNodeCount++;
return finalSAHCost; return finalSAHCost;
} else { } else {
/* In the end, splitting didn't help to reduce the SAH cost. /* In the end, splitting didn't help to reduce the SAH cost.
@ -1027,7 +1038,7 @@ protected:
/* Keep track of the beginning of dimensions */ /* Keep track of the beginning of dimensions */
if (event < eventEnd && event->axis != axis) { if (event < eventEnd && event->axis != axis) {
Assert(eventsByAxisCtr < 3); KDAssert(eventsByAxisCtr < 3);
eventsByAxis[eventsByAxisCtr++] = event; eventsByAxis[eventsByAxisCtr++] = event;
} }
@ -1073,7 +1084,7 @@ protected:
} else { } else {
/* When primitive clipping is active, this should /* When primitive clipping is active, this should
never happen! */ never happen! */
AssertEx(!m_clip, "Internal error: edge event is out of bounds"); KDAssertEx(!m_clip, "Internal error: edge event is out of bounds");
} }
/* The split plane is moved past 't'. All prims, /* The split plane is moved past 't'. All prims,
@ -1084,14 +1095,14 @@ protected:
} }
/* Sanity checks. Everything should now be left of the split plane */ /* Sanity checks. Everything should now be left of the split plane */
Assert(numRight[0] == 0 && numLeft[0] == primCount && KDAssert(numRight[0] == 0 && numLeft[0] == primCount &&
numRight[1] == 0 && numLeft[1] == primCount && numRight[1] == 0 && numLeft[1] == primCount &&
numRight[2] == 0 && numLeft[2] == primCount); numRight[2] == 0 && numLeft[2] == primCount);
Assert(eventsByAxis[1]->axis == 1 && (eventsByAxis[1]-1)->axis == 0); KDAssert(eventsByAxis[1]->axis == 1 && (eventsByAxis[1]-1)->axis == 0);
Assert(eventsByAxis[2]->axis == 2 && (eventsByAxis[2]-1)->axis == 1); KDAssert(eventsByAxis[2]->axis == 2 && (eventsByAxis[2]-1)->axis == 1);
Assert(bestSplit.sahCost != std::numeric_limits<Float>::infinity()); KDAssert(bestSplit.sahCost != std::numeric_limits<Float>::infinity());
/* "Bad refines" heuristic from PBRT */ /* "Bad refines" heuristic from PBRT */
if (bestSplit.sahCost >= leafCost) { if (bestSplit.sahCost >= leafCost) {
@ -1121,7 +1132,7 @@ protected:
if (event->type == EdgeEvent::EEdgeEnd && event->pos <= bestSplit.pos) { if (event->type == EdgeEvent::EEdgeEnd && event->pos <= bestSplit.pos) {
/* The primitive's interval ends before or on the split plane /* The primitive's interval ends before or on the split plane
-> classify to the left side */ -> classify to the left side */
Assert(storage.get(event->index) == EBothSides); KDAssert(storage.get(event->index) == EBothSides);
storage.set(event->index, ELeftSide); storage.set(event->index, ELeftSide);
primsBoth--; primsBoth--;
primsLeft++; primsLeft++;
@ -1129,7 +1140,7 @@ protected:
&& event->pos >= bestSplit.pos) { && event->pos >= bestSplit.pos) {
/* The primitive's interval starts after or on the split plane /* The primitive's interval starts after or on the split plane
-> classify to the right side */ -> classify to the right side */
Assert(storage.get(event->index) == EBothSides); KDAssert(storage.get(event->index) == EBothSides);
storage.set(event->index, ERightSide); storage.set(event->index, ERightSide);
primsBoth--; primsBoth--;
primsRight++; primsRight++;
@ -1137,7 +1148,7 @@ protected:
/* If the planar primitive is not on the split plane, the /* If the planar primitive is not on the split plane, the
classification is easy. Otherwise, place it on the side with classification is easy. Otherwise, place it on the side with
the better SAH score */ the better SAH score */
Assert(storage.get(event->index) == EBothSides); KDAssert(storage.get(event->index) == EBothSides);
if (event->pos < bestSplit.pos || (event->pos == bestSplit.pos if (event->pos < bestSplit.pos || (event->pos == bestSplit.pos
&& bestSplit.planarLeft)) { && bestSplit.planarLeft)) {
storage.set(event->index, ELeftSide); storage.set(event->index, ELeftSide);
@ -1149,15 +1160,15 @@ protected:
primsBoth--; primsBoth--;
primsRight++; primsRight++;
} else { } else {
AssertEx(false, "Internal error!"); KDAssertEx(false, "Internal error!");
} }
} }
} }
/* Some sanity checks */ /* Some sanity checks */
Assert(primsLeft + primsRight + primsBoth == primCount); KDAssert(primsLeft + primsRight + primsBoth == primCount);
Assert(primsLeft + primsBoth == bestSplit.numLeft); KDAssert(primsLeft + primsBoth == bestSplit.numLeft);
Assert(primsRight + primsBoth == bestSplit.numRight); KDAssert(primsRight + primsBoth == bestSplit.numRight);
OrderedChunkAllocator &leftAlloc = ctx.leftAlloc, OrderedChunkAllocator &leftAlloc = ctx.leftAlloc,
&rightAlloc = ctx.rightAlloc; &rightAlloc = ctx.rightAlloc;
@ -1207,11 +1218,11 @@ protected:
generate new events for each side */ generate new events for each side */
const index_type index = event->index; const index_type index = event->index;
AABB clippedLeft = downCast()->clip(index, leftNodeAABB); AABB clippedLeft = downCast()->getClippedAABB(index, leftNodeAABB);
AABB clippedRight = downCast()->clip(index, rightNodeAABB); AABB clippedRight = downCast()->getClippedAABB(index, rightNodeAABB);
Assert(leftNodeAABB.contains(clippedLeft)); KDAssert(leftNodeAABB.contains(clippedLeft));
Assert(rightNodeAABB.contains(clippedRight)); KDAssert(rightNodeAABB.contains(clippedRight));
if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) { if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
for (int axis=0; axis<3; ++axis) { for (int axis=0; axis<3; ++axis) {
@ -1249,10 +1260,10 @@ protected:
} }
} }
Assert(leftEventsTempEnd - leftEventsTempStart <= primsLeft * 6); KDAssert(leftEventsTempEnd - leftEventsTempStart <= primsLeft * 6);
Assert(rightEventsTempEnd - rightEventsTempStart <= primsRight * 6); KDAssert(rightEventsTempEnd - rightEventsTempStart <= primsRight * 6);
Assert(newEventsLeftEnd - newEventsLeftStart <= primsBoth * 6); KDAssert(newEventsLeftEnd - newEventsLeftStart <= primsBoth * 6);
Assert(newEventsRightEnd - newEventsRightStart <= primsBoth * 6); KDAssert(newEventsRightEnd - newEventsRightStart <= primsBoth * 6);
ctx.pruned += prunedLeft + prunedRight; ctx.pruned += prunedLeft + prunedRight;
/* Sort the events from overlapping prims */ /* Sort the events from overlapping prims */
@ -1290,8 +1301,8 @@ protected:
*rightEventsEnd++ = *event; *rightEventsEnd++ = *event;
} }
} }
Assert(leftEventsEnd - leftEventsStart <= bestSplit.numLeft * 6); KDAssert(leftEventsEnd - leftEventsStart <= bestSplit.numLeft * 6);
Assert(rightEventsEnd - rightEventsStart <= bestSplit.numRight * 6); KDAssert(rightEventsEnd - rightEventsStart <= bestSplit.numRight * 6);
} }
/* Shrink the edge event storage now that we know exactly how /* Shrink the edge event storage now that we know exactly how
@ -1317,6 +1328,7 @@ protected:
initialIndirectionTableSize); initialIndirectionTableSize);
m_indirectionTable.push_back(children); m_indirectionTable.push_back(children);
} }
ctx.innerNodeCount++;
Float leftSAHCost = buildTreeSAH(ctx, depth+1, children, Float leftSAHCost = buildTreeSAH(ctx, depth+1, children,
leftNodeAABB, leftEventsStart, leftEventsEnd, leftNodeAABB, leftEventsStart, leftEventsEnd,
@ -1344,9 +1356,8 @@ protected:
/* Final decision */ /* Final decision */
/* ==================================================================== */ /* ==================================================================== */
if (finalSAHCost < primCount * m_intersectionCost) { if (!m_retract || finalSAHCost < primCount * m_intersectionCost) {
ctx.expTraversalSteps += nodeAABB.getSurfaceArea(); ctx.expTraversalSteps += nodeAABB.getSurfaceArea();
ctx.innerNodeCount++;
return finalSAHCost; return finalSAHCost;
} else { } else {
/* In the end, splitting didn't help to reduce the SAH cost. /* In the end, splitting didn't help to reduce the SAH cost.
@ -1367,9 +1378,13 @@ protected:
*/ */
void tearUp(BuildContext &ctx, KDNode *node) { void tearUp(BuildContext &ctx, KDNode *node) {
if (node->isLeaf()) { if (node->isLeaf()) {
if (node->getPrimStart() != node->getPrimEnd())
ctx.nonemptyLeafNodeCount--;
ctx.leafNodeCount--;
/// XXX Create primitive list for leaf /// XXX Create primitive list for leaf
} else { } else {
KDNode *left; KDNode *left;
ctx.innerNodeCount--;
if (EXPECT_TAKEN(!node->isIndirection())) if (EXPECT_TAKEN(!node->isIndirection()))
left = node->getLeft(); left = node->getLeft();
else else
@ -1472,7 +1487,7 @@ protected:
binIdx++; binIdx++;
} }
Assert(candidate.sahCost != std::numeric_limits<Float>::infinity()); KDAssert(candidate.sahCost != std::numeric_limits<Float>::infinity());
const int axis = candidate.axis; const int axis = candidate.axis;
const float min = m_aabb.min[axis]; const float min = m_aabb.min[axis];
@ -1570,18 +1585,18 @@ protected:
const AABB aabb = derived->getAABB(primIndex); const AABB aabb = derived->getAABB(primIndex);
if (aabb.max[axis] <= splitPos) { if (aabb.max[axis] <= splitPos) {
Assert(numLeft < split.numLeft); KDAssert(numLeft < split.numLeft);
leftBounds.expandBy(aabb); leftBounds.expandBy(aabb);
leftIndices[numLeft++] = primIndex; leftIndices[numLeft++] = primIndex;
} else if (aabb.min[axis] > splitPos) { } else if (aabb.min[axis] > splitPos) {
Assert(numRight < split.numRight); KDAssert(numRight < split.numRight);
rightBounds.expandBy(aabb); rightBounds.expandBy(aabb);
rightIndices[numRight++] = primIndex; rightIndices[numRight++] = primIndex;
} else { } else {
leftBounds.expandBy(aabb); leftBounds.expandBy(aabb);
rightBounds.expandBy(aabb); rightBounds.expandBy(aabb);
Assert(numLeft < split.numLeft); KDAssert(numLeft < split.numLeft);
Assert(numRight < split.numRight); KDAssert(numRight < split.numRight);
leftIndices[numLeft++] = primIndex; leftIndices[numLeft++] = primIndex;
rightIndices[numRight++] = primIndex; rightIndices[numRight++] = primIndex;
} }
@ -1590,8 +1605,8 @@ protected:
leftBounds.clip(m_aabb); leftBounds.clip(m_aabb);
rightBounds.clip(m_aabb); rightBounds.clip(m_aabb);
Assert(numLeft == split.numLeft); KDAssert(numLeft == split.numLeft);
Assert(numRight == split.numRight); KDAssert(numRight == split.numRight);
/// Release the unused memory regions /// Release the unused memory regions
if (isLeftChild) if (isLeftChild)
@ -1652,12 +1667,12 @@ private:
Float m_traversalCost; Float m_traversalCost;
Float m_intersectionCost; Float m_intersectionCost;
Float m_emptySpaceBonus; Float m_emptySpaceBonus;
bool m_clip; bool m_clip, m_retract;
AABB m_aabb; AABB m_aabb;
size_type m_maxDepth; size_type m_maxDepth;
size_type m_stopPrims; size_type m_stopPrims;
size_type m_maxBadRefines; size_type m_maxBadRefines;
size_type m_exactDepth; size_type m_exactPrimThreshold;
std::vector<SAHTreeBuilder *> m_builders; std::vector<SAHTreeBuilder *> m_builders;
BuildInterface m_interface; BuildInterface m_interface;
}; };

View File

@ -95,7 +95,7 @@ public:
return m_triangles[idx].getAABB(m_vertexBuffer); return m_triangles[idx].getAABB(m_vertexBuffer);
} }
inline AABB clip(index_type idx, const AABB &aabb) const { inline AABB getClippedAABB(index_type idx, const AABB &aabb) const {
return m_triangles[idx].getClippedAABB(m_vertexBuffer, aabb); return m_triangles[idx].getClippedAABB(m_vertexBuffer, aabb);
} }