the octree-class is now completely lock-free (using atomic exchange operations)
parent
2db91b43f9
commit
fbfe3e395d
|
@ -20,10 +20,50 @@
|
||||||
#define __OCTREE_H
|
#define __OCTREE_H
|
||||||
|
|
||||||
#include <mitsuba/mitsuba.h>
|
#include <mitsuba/mitsuba.h>
|
||||||
#include <mitsuba/core/aabb.h>
|
#include <mitsuba/core/octree.h>
|
||||||
|
#include <mitsuba/core/atomic.h>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Implements a lock-free singly linked list.
|
||||||
|
*/
|
||||||
|
template <typename T> class LockFreeList {
|
||||||
|
public:
|
||||||
|
struct ListItem {
|
||||||
|
T value;
|
||||||
|
ListItem *next;
|
||||||
|
|
||||||
|
inline ListItem(const T &value) :
|
||||||
|
value(value), next(NULL) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline LockFreeList() : m_head(NULL) {}
|
||||||
|
|
||||||
|
~LockFreeList() {
|
||||||
|
ListItem *cur = m_head;
|
||||||
|
while (cur) {
|
||||||
|
ListItem *next = cur->next;
|
||||||
|
delete cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ListItem *head() const {
|
||||||
|
return m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const T &value) {
|
||||||
|
ListItem *item = new ListItem(value);
|
||||||
|
ListItem **cur = &m_head;
|
||||||
|
while (!atomicCompareAndExchangePtr<ListItem>(cur, item, NULL))
|
||||||
|
cur = &((*cur)->next);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ListItem *m_head;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Generic multiple-reference octree.
|
* \brief Generic multiple-reference octree.
|
||||||
*
|
*
|
||||||
|
@ -67,29 +107,34 @@ private:
|
||||||
struct OctreeNode {
|
struct OctreeNode {
|
||||||
public:
|
public:
|
||||||
OctreeNode() {
|
OctreeNode() {
|
||||||
pthread_rwlock_init(&lock, NULL);
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
children[i] = NULL;
|
children[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
~OctreeNode() {
|
~OctreeNode() {
|
||||||
pthread_rwlock_destroy(&lock);
|
|
||||||
for (int i=0; i<8; ++i) {
|
for (int i=0; i<8; ++i) {
|
||||||
if (children[i])
|
if (children[i])
|
||||||
delete children[i];
|
delete children[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void readLock() const { pthread_rwlock_rdlock(&lock); }
|
|
||||||
inline void readUnlock() const { pthread_rwlock_unlock(&lock); }
|
|
||||||
inline void writeLock() { pthread_rwlock_wrlock(&lock); }
|
|
||||||
inline void writeUnlock() { pthread_rwlock_unlock(&lock); }
|
|
||||||
|
|
||||||
OctreeNode *children[8];
|
OctreeNode *children[8];
|
||||||
mutable pthread_rwlock_t lock;
|
LockFreeList<T> data;
|
||||||
std::vector<T> data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Return the AABB for a child of the specified index
|
||||||
|
inline AABB childBounds(int child, const AABB &nodeAABB, const Point ¢er) const {
|
||||||
|
AABB childAABB;
|
||||||
|
childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
|
||||||
|
childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
|
||||||
|
childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
|
||||||
|
childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
|
||||||
|
childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
|
||||||
|
childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
|
||||||
|
return childAABB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void insert(OctreeNode *node, const AABB &nodeAABB, const T &value,
|
void insert(OctreeNode *node, const AABB &nodeAABB, const T &value,
|
||||||
const AABB &coverage, Float diag2, int depth) {
|
const AABB &coverage, Float diag2, int depth) {
|
||||||
/* Add the data item to the current octree node if the max. tree
|
/* Add the data item to the current octree node if the max. tree
|
||||||
|
@ -97,51 +142,32 @@ private:
|
||||||
than the current node size */
|
than the current node size */
|
||||||
if (depth == m_maxDepth ||
|
if (depth == m_maxDepth ||
|
||||||
(nodeAABB.getExtents().lengthSquared() < diag2)) {
|
(nodeAABB.getExtents().lengthSquared() < diag2)) {
|
||||||
node->writeLock();
|
node->data.append(value);
|
||||||
node->data.push_back(value);
|
|
||||||
node->writeUnlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise: test for overlap */
|
/* Otherwise: test for overlap */
|
||||||
const Point center = nodeAABB.getCenter();
|
const Point center = nodeAABB.getCenter();
|
||||||
bool over[8];
|
|
||||||
AABB childAABB;
|
|
||||||
|
|
||||||
over[0] = over[1] = over[2] = over[3] = (coverage.min.x <= center.x);
|
/* Otherwise: test for overlap */
|
||||||
over[4] = over[5] = over[6] = over[7] = (coverage.max.x > center.x);
|
bool x[2] = { coverage.min.x <= center.x, coverage.max.x > center.x };
|
||||||
over[0] &= (coverage.min.y <= center.y);
|
bool y[2] = { coverage.min.y <= center.y, coverage.max.y > center.y };
|
||||||
over[1] &= (coverage.min.y <= center.y);
|
bool z[2] = { coverage.min.z <= center.z, coverage.max.z > center.z };
|
||||||
over[4] &= (coverage.min.y <= center.y);
|
bool over[8] = { x[0] & y[0] & z[0], x[0] & y[0] & z[1],
|
||||||
over[5] &= (coverage.min.y <= center.y);
|
x[0] & y[1] & z[0], x[0] & y[1] & z[1],
|
||||||
over[2] &= (coverage.max.y > center.y);
|
x[1] & y[0] & z[0], x[1] & y[0] & z[1],
|
||||||
over[3] &= (coverage.max.y > center.y);
|
x[1] & y[1] & z[0], x[1] & y[1] & z[1] };
|
||||||
over[6] &= (coverage.max.y > center.y);
|
|
||||||
over[7] &= (coverage.max.y > center.y);
|
|
||||||
over[0] &= (coverage.min.z <= center.z);
|
|
||||||
over[2] &= (coverage.min.z <= center.z);
|
|
||||||
over[4] &= (coverage.min.z <= center.z);
|
|
||||||
over[6] &= (coverage.min.z <= center.z);
|
|
||||||
over[1] &= (coverage.max.z > center.z);
|
|
||||||
over[3] &= (coverage.max.z > center.z);
|
|
||||||
over[5] &= (coverage.max.z > center.z);
|
|
||||||
over[7] &= (coverage.max.z > center.z);
|
|
||||||
|
|
||||||
/* Recurse */
|
/* Recurse */
|
||||||
for (int child=0; child<8; ++child) {
|
for (int child=0; child<8; ++child) {
|
||||||
if (!over[child])
|
if (!over[child])
|
||||||
continue;
|
continue;
|
||||||
if (!node->children[child]) {
|
if (!node->children[child]) {
|
||||||
node->writeLock();
|
OctreeNode *newNode = new OctreeNode();
|
||||||
node->children[child] = new OctreeNode();
|
if (!atomicCompareAndExchangePtr<OctreeNode>(&node->children[child], newNode, NULL))
|
||||||
node->writeUnlock();
|
delete newNode;
|
||||||
}
|
}
|
||||||
childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
|
const AABB childAABB(childBounds(child, nodeAABB, center));
|
||||||
childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
|
|
||||||
childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
|
|
||||||
childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
|
|
||||||
childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
|
|
||||||
childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
|
|
||||||
insert(node->children[child], childAABB,
|
insert(node->children[child], childAABB,
|
||||||
value, coverage, diag2, depth+1);
|
value, coverage, diag2, depth+1);
|
||||||
}
|
}
|
||||||
|
@ -152,25 +178,20 @@ private:
|
||||||
const AABB &nodeAABB, const Point &p, Functor &functor) const {
|
const AABB &nodeAABB, const Point &p, Functor &functor) const {
|
||||||
const Point center = nodeAABB.getCenter();
|
const Point center = nodeAABB.getCenter();
|
||||||
|
|
||||||
node->readLock();
|
const typename LockFreeList<T>::ListItem *item = node->data.head();
|
||||||
for (size_t i=0; i<node->data.size(); ++i)
|
while (item) {
|
||||||
functor(node->data[i]);
|
functor(item->value);
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
|
||||||
int child = (p.x > center.x ? 4 : 0)
|
int child = (p.x > center.x ? 4 : 0)
|
||||||
+ (p.y > center.y ? 2 : 0)
|
+ (p.y > center.y ? 2 : 0)
|
||||||
+ (p.z > center.z ? 1 : 0);
|
+ (p.z > center.z ? 1 : 0);
|
||||||
|
|
||||||
OctreeNode *childNode = node->children[child];
|
OctreeNode *childNode = node->children[child];
|
||||||
node->readUnlock();
|
|
||||||
|
|
||||||
if (childNode) {
|
if (childNode) {
|
||||||
AABB childAABB;
|
const AABB childAABB(childBounds(child, nodeAABB, center));
|
||||||
childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
|
|
||||||
childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
|
|
||||||
childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
|
|
||||||
childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
|
|
||||||
childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
|
|
||||||
childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
|
|
||||||
lookup(node->children[child], childAABB, p, functor);
|
lookup(node->children[child], childAABB, p, functor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,22 +201,16 @@ private:
|
||||||
Functor &functor) {
|
Functor &functor) {
|
||||||
const Point center = nodeAABB.getCenter();
|
const Point center = nodeAABB.getCenter();
|
||||||
|
|
||||||
node->readLock();
|
const typename LockFreeList<T>::ListItem *item = node->data.head();
|
||||||
for (size_t i=0; i<node->data.size(); ++i)
|
while (item) {
|
||||||
functor(node->data[i]);
|
functor(item->value);
|
||||||
node->readUnlock();
|
item = item->next;
|
||||||
|
}
|
||||||
|
|
||||||
// Potential for much optimization..
|
// Potential for much optimization..
|
||||||
for (int child=0; child<8; ++child) {
|
for (int child=0; child<8; ++child) {
|
||||||
if (node->children[child]) {
|
if (node->children[child]) {
|
||||||
AABB childAABB;
|
const AABB childAABB(childBounds(child, nodeAABB, center));
|
||||||
childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
|
|
||||||
childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
|
|
||||||
childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
|
|
||||||
childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
|
|
||||||
childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
|
|
||||||
childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
|
|
||||||
|
|
||||||
if (childAABB.overlaps(sphere))
|
if (childAABB.overlaps(sphere))
|
||||||
searchSphere(node->children[child], childAABB, sphere, functor);
|
searchSphere(node->children[child], childAABB, sphere, functor);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue