bvh: Add an abstract pager implementation.

Implement a paging implementation for bounding
volume hierarchy nodes. We will need this for
hla clients that need ground queries.
This commit is contained in:
Mathias Froehlich 2012-08-24 21:20:40 +02:00
parent 7a879e2abf
commit cf1bdcef46
15 changed files with 518 additions and 1 deletions

View File

@ -23,6 +23,7 @@
#include "BVHVisitor.hxx" #include "BVHVisitor.hxx"
#include "BVHNode.hxx" #include "BVHNode.hxx"
#include "BVHGroup.hxx" #include "BVHGroup.hxx"
#include "BVHPageNode.hxx"
#include "BVHTransform.hxx" #include "BVHTransform.hxx"
#include "BVHMotionTransform.hxx" #include "BVHMotionTransform.hxx"
#include "BVHLineGeometry.hxx" #include "BVHLineGeometry.hxx"
@ -45,6 +46,8 @@ public:
virtual void apply(BVHGroup& node) virtual void apply(BVHGroup& node)
{ expandBy(node.getBoundingSphere()); } { expandBy(node.getBoundingSphere()); }
virtual void apply(BVHPageNode& node)
{ expandBy(node.getBoundingSphere()); }
virtual void apply(BVHTransform& node) virtual void apply(BVHTransform& node)
{ expandBy(node.getBoundingSphere()); } { expandBy(node.getBoundingSphere()); }
virtual void apply(BVHMotionTransform& node) virtual void apply(BVHMotionTransform& node)

View File

@ -27,6 +27,7 @@
#include "BVHNode.hxx" #include "BVHNode.hxx"
#include "BVHGroup.hxx" #include "BVHGroup.hxx"
#include "BVHPageNode.hxx"
#include "BVHTransform.hxx" #include "BVHTransform.hxx"
#include "BVHMotionTransform.hxx" #include "BVHMotionTransform.hxx"
#include "BVHLineGeometry.hxx" #include "BVHLineGeometry.hxx"
@ -47,6 +48,14 @@ BVHLineSegmentVisitor::apply(BVHGroup& group)
return; return;
group.traverse(*this); group.traverse(*this);
} }
void
BVHLineSegmentVisitor::apply(BVHPageNode& pageNode)
{
if (!intersects(_lineSegment, pageNode.getBoundingSphere()))
return;
pageNode.traverse(*this);
}
void void
BVHLineSegmentVisitor::apply(BVHTransform& transform) BVHLineSegmentVisitor::apply(BVHTransform& transform)

View File

@ -60,6 +60,7 @@ public:
{ return _id; } { return _id; }
virtual void apply(BVHGroup& group); virtual void apply(BVHGroup& group);
virtual void apply(BVHPageNode& node);
virtual void apply(BVHTransform& transform); virtual void apply(BVHTransform& transform);
virtual void apply(BVHMotionTransform& transform); virtual void apply(BVHMotionTransform& transform);
virtual void apply(BVHLineGeometry&); virtual void apply(BVHLineGeometry&);

View File

@ -24,6 +24,7 @@
#include "BVHNode.hxx" #include "BVHNode.hxx"
#include "BVHGroup.hxx" #include "BVHGroup.hxx"
#include "BVHPageNode.hxx"
#include "BVHTransform.hxx" #include "BVHTransform.hxx"
#include "BVHLineGeometry.hxx" #include "BVHLineGeometry.hxx"
#include "BVHStaticGeometry.hxx" #include "BVHStaticGeometry.hxx"
@ -52,6 +53,12 @@ public:
return; return;
leaf.traverse(*this); leaf.traverse(*this);
} }
virtual void apply(BVHPageNode& leaf)
{
if (!intersects(_sphere, leaf.getBoundingSphere()))
return;
leaf.traverse(*this);
}
virtual void apply(BVHTransform& transform) virtual void apply(BVHTransform& transform)
{ {
if (!intersects(_sphere, transform.getBoundingSphere())) if (!intersects(_sphere, transform.getBoundingSphere()))

View File

@ -26,6 +26,7 @@ namespace simgear {
class BVHGroup; class BVHGroup;
class BVHVisitor; class BVHVisitor;
class BVHPageNode;
// Base for the tree nodes // Base for the tree nodes
class BVHNode : public SGReferenced { class BVHNode : public SGReferenced {
@ -55,6 +56,7 @@ public:
protected: protected:
friend class BVHGroup; friend class BVHGroup;
friend class BVHPageNode;
void addParent(BVHNode* parent); void addParent(BVHNode* parent);
void removeParent(BVHNode* parent); void removeParent(BVHNode* parent);

View File

@ -0,0 +1,40 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "BVHPageNode.hxx"
#include "BVHPager.hxx"
namespace simgear {
BVHPageNode::BVHPageNode() :
_useStamp(0),
_requested(false)
{
}
BVHPageNode::~BVHPageNode()
{
}
void
BVHPageNode::accept(BVHVisitor& visitor)
{
visitor.apply(*this);
}
}

View File

@ -0,0 +1,66 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef BVHPageNode_hxx
#define BVHPageNode_hxx
#include <list>
#include <simgear/structure/SGSharedPtr.hxx>
#include "BVHGroup.hxx"
#include "BVHVisitor.hxx"
namespace simgear {
class BVHPager;
class BVHPageRequest;
class BVHPageNode : public BVHGroup {
public:
BVHPageNode();
virtual ~BVHPageNode();
virtual void accept(BVHVisitor& visitor);
/// Return the usage stamp of the last access
unsigned getUseStamp() const
{ return _useStamp; }
virtual SGSphered computeBoundingSphere() const = 0;
virtual BVHPageRequest* newRequest() = 0;
protected:
virtual void invalidateBound() = 0;
bool getRequested() const
{ return _requested; }
void setRequested(bool requested)
{ _requested = requested; }
private:
friend class BVHPager;
std::list<SGSharedPtr<BVHPageNode> >::iterator _iterator;
unsigned _useStamp;
bool _requested;
};
}
#endif

View File

@ -0,0 +1,26 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "BVHPageRequest.hxx"
namespace simgear {
BVHPageRequest::~BVHPageRequest()
{
}
}

View File

@ -0,0 +1,42 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef BVHPageRequest_hxx
#define BVHPageRequest_hxx
#include <simgear/structure/SGReferenced.hxx>
namespace simgear {
class BVHPageNode;
class BVHPageRequest : public SGReferenced {
public:
virtual ~BVHPageRequest();
/// Happens in the pager thread, do not modify the calling bvh tree
virtual void load() = 0;
/// Happens in the bvh main thread where the bvh is actually used.
/// So inside here it is safe to modify the paged node
virtual void insert() = 0;
/// The page node this request is for
virtual BVHPageNode* getPageNode() = 0;
};
}
#endif

236
simgear/bvh/BVHPager.cxx Normal file
View File

@ -0,0 +1,236 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include "BVHPager.hxx"
#include <list>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include "BVHPageNode.hxx"
#include "BVHPageRequest.hxx"
namespace simgear {
struct BVHPager::_PrivateData : protected SGThread {
typedef SGSharedPtr<BVHPageRequest> _Request;
typedef std::list<_Request> _RequestList;
typedef std::list<SGSharedPtr<BVHPageNode> > _PageNodeList;
struct _LockedQueue {
void _push(const _Request& request)
{
SGGuard<SGMutex> scopeLock(_mutex);
_requestList.push_back(request);
}
_Request _pop()
{
SGGuard<SGMutex> scopeLock(_mutex);
if (_requestList.empty())
return _Request();
_Request request;
request.swap(_requestList.front());
_requestList.pop_front();
return request;
}
private:
SGMutex _mutex;
_RequestList _requestList;
};
struct _WorkQueue {
void _stop()
{
_push(_Request());
}
void _push(const _Request& request)
{
SGGuard<SGMutex> scopeLock(_mutex);
bool needSignal = _requestList.empty();
_requestList.push_back(request);
if (needSignal)
_waitCondition.signal();
}
_Request _pop()
{
SGGuard<SGMutex> scopeLock(_mutex);
while (_requestList.empty())
_waitCondition.wait(_mutex);
_Request request;
request.swap(_requestList.front());
_requestList.pop_front();
return request;
}
private:
SGMutex _mutex;
SGWaitCondition _waitCondition;
_RequestList _requestList;
};
_PrivateData() :
_started(false),
_useStamp(0)
{
}
virtual ~_PrivateData()
{
_stop();
}
virtual void run()
{
for (;;) {
_Request request = _pendingRequests._pop();
// This means stop working
if (!request.valid())
return;
request->load();
_processedRequests._push(request);
}
}
bool _start()
{
if (_started)
return true;
if (!start())
return false;
_started = true;
return true;
}
void _stop()
{
if (!_started)
return;
// send a stop request ...
_pendingRequests._stop();
// ... and wait for the thread to finish
join();
_started = false;
}
void _use(BVHPageNode& pageNode)
{
if (pageNode._requested) {
// move it forward in the lru list
_pageNodeList.splice(_pageNodeList.end(), _pageNodeList,
pageNode._iterator);
} else {
_Request request = pageNode.newRequest();
if (!request.valid())
return;
pageNode._iterator = _pageNodeList.insert(_pageNodeList.end(),
&pageNode);
pageNode._requested = true;
if (_started) {
_pendingRequests._push(request);
} else {
request->load();
request->insert();
}
}
pageNode._useStamp = _useStamp;
}
void _update(unsigned expiry)
{
// Insert all processed requests
for (;;) {
SGSharedPtr<BVHPageRequest> request;
request = _processedRequests._pop();
if (!request.valid())
break;
request->insert();
}
// ... and throw away stuff that is not used for a long time
unsigned useStamp = _useStamp - expiry;
_PageNodeList::iterator i = _pageNodeList.begin();
while (i != _pageNodeList.end()) {
// Ok, this means if the highest bit in the below difference
// is set which is aequivalent to having a negative difference
// but being wraparound save.
unsigned diff = (*i)->_useStamp - useStamp;
// test the sign bit of the difference
if (!(diff & (~((~0u) >> 1))))
break;
(*i)->clear();
(*i)->_requested = false;
i = _pageNodeList.erase(i);
}
}
bool _started;
unsigned _useStamp;
_WorkQueue _pendingRequests;
_LockedQueue _processedRequests;
// Store the rcu list of loaded nodes so that they can expire
_PageNodeList _pageNodeList;
};
BVHPager::BVHPager() :
_privateData(new _PrivateData)
{
}
BVHPager::~BVHPager()
{
delete _privateData;
_privateData = 0;
}
bool
BVHPager::start()
{
return _privateData->_start();
}
void
BVHPager::stop()
{
_privateData->_stop();
}
void
BVHPager::use(BVHPageNode& pageNode)
{
_privateData->_use(pageNode);
}
void
BVHPager::update(unsigned expiry)
{
_privateData->_update(expiry);
}
void
BVHPager::setUseStamp(unsigned stamp)
{
_privateData->_useStamp = stamp;
}
unsigned
BVHPager::getUseStamp() const
{
return _privateData->_useStamp;
}
}

60
simgear/bvh/BVHPager.hxx Normal file
View File

@ -0,0 +1,60 @@
// Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef BVHPager_hxx
#define BVHPager_hxx
#include <simgear/structure/SGSharedPtr.hxx>
namespace simgear {
class BVHPageNode;
class BVHPageRequest;
class BVHPager {
public:
BVHPager();
~BVHPager();
/// Starts the pager thread
bool start();
/// Stops the pager thread
void stop();
/// Use this page node, if loaded make it as used, if not loaded schedule
void use(BVHPageNode& pageNode);
/// Call this from the main thread to incorporate the processed page
/// requests into the bounding volume tree
void update(unsigned expiry);
/// The usage stamp to mark usage of BVHPageNodes
void setUseStamp(unsigned stamp);
unsigned getUseStamp() const;
private:
BVHPager(const BVHPager&);
BVHPager& operator=(const BVHPager&);
struct _PrivateData;
_PrivateData* _privateData;
};
}
#endif

View File

@ -59,6 +59,22 @@ BVHSubTreeCollector::apply(BVHGroup& group)
popNodeList(parentNodeList); popNodeList(parentNodeList);
} }
void
BVHSubTreeCollector::apply(BVHPageNode& group)
{
if (!intersects(_sphere, group.getBoundingSphere()))
return;
// The _nodeList content is somehow the 'return value' of the subtree.
// Set it to zero to see if we have something to collect down there.
NodeList parentNodeList;
pushNodeList(parentNodeList);
group.traverse(*this);
popNodeList(parentNodeList);
}
void void
BVHSubTreeCollector::apply(BVHTransform& transform) BVHSubTreeCollector::apply(BVHTransform& transform)
{ {

View File

@ -43,6 +43,7 @@ public:
virtual ~BVHSubTreeCollector(); virtual ~BVHSubTreeCollector();
virtual void apply(BVHGroup&); virtual void apply(BVHGroup&);
virtual void apply(BVHPageNode&);
virtual void apply(BVHTransform&); virtual void apply(BVHTransform&);
virtual void apply(BVHMotionTransform&); virtual void apply(BVHMotionTransform&);
virtual void apply(BVHLineGeometry&); virtual void apply(BVHLineGeometry&);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de // Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public // modify it under the terms of the GNU Library General Public
@ -23,6 +23,7 @@ namespace simgear {
class BVHStaticData; class BVHStaticData;
class BVHGroup; class BVHGroup;
class BVHPageNode;
class BVHTransform; class BVHTransform;
class BVHMotionTransform; class BVHMotionTransform;
class BVHStaticGeometry; class BVHStaticGeometry;
@ -41,6 +42,7 @@ public:
// High level nodes to handle // High level nodes to handle
virtual void apply(BVHGroup&) = 0; virtual void apply(BVHGroup&) = 0;
virtual void apply(BVHPageNode&) = 0;
virtual void apply(BVHTransform&) = 0; virtual void apply(BVHTransform&) = 0;
virtual void apply(BVHMotionTransform&) = 0; virtual void apply(BVHMotionTransform&) = 0;
virtual void apply(BVHLineGeometry&) = 0; virtual void apply(BVHLineGeometry&) = 0;

View File

@ -8,6 +8,9 @@ set(HEADERS
BVHMotionTransform.hxx BVHMotionTransform.hxx
BVHNearestPointVisitor.hxx BVHNearestPointVisitor.hxx
BVHNode.hxx BVHNode.hxx
BVHPageNode.hxx
BVHPageRequest.hxx
BVHPager.hxx
BVHStaticBinary.hxx BVHStaticBinary.hxx
BVHStaticData.hxx BVHStaticData.hxx
BVHStaticGeometry.hxx BVHStaticGeometry.hxx
@ -27,6 +30,9 @@ set(SOURCES
BVHLineSegmentVisitor.cxx BVHLineSegmentVisitor.cxx
BVHMotionTransform.cxx BVHMotionTransform.cxx
BVHNode.cxx BVHNode.cxx
BVHPageNode.cxx
BVHPageRequest.cxx
BVHPager.cxx
BVHStaticBinary.cxx BVHStaticBinary.cxx
BVHStaticGeometry.cxx BVHStaticGeometry.cxx
BVHStaticLeaf.cxx BVHStaticLeaf.cxx