]> git.mxchange.org Git - simgear.git/commitdiff
bvh: Add an abstract pager implementation.
authorMathias Froehlich <Mathias.Froehlich@web.de>
Fri, 24 Aug 2012 19:20:40 +0000 (21:20 +0200)
committerMathias Froehlich <Mathias.Froehlich@web.de>
Fri, 24 Aug 2012 19:25:17 +0000 (21:25 +0200)
Implement a paging implementation for bounding
volume hierarchy nodes. We will need this for
hla clients that need ground queries.

15 files changed:
simgear/bvh/BVHBoundingBoxVisitor.hxx
simgear/bvh/BVHLineSegmentVisitor.cxx
simgear/bvh/BVHLineSegmentVisitor.hxx
simgear/bvh/BVHNearestPointVisitor.hxx
simgear/bvh/BVHNode.hxx
simgear/bvh/BVHPageNode.cxx [new file with mode: 0644]
simgear/bvh/BVHPageNode.hxx [new file with mode: 0644]
simgear/bvh/BVHPageRequest.cxx [new file with mode: 0644]
simgear/bvh/BVHPageRequest.hxx [new file with mode: 0644]
simgear/bvh/BVHPager.cxx [new file with mode: 0644]
simgear/bvh/BVHPager.hxx [new file with mode: 0644]
simgear/bvh/BVHSubTreeCollector.cxx
simgear/bvh/BVHSubTreeCollector.hxx
simgear/bvh/BVHVisitor.hxx
simgear/bvh/CMakeLists.txt

index d37779c367b519fde3374bccd3f7ef056354b853..c14ff9c26991d18d9ac73c3b54b4bab9fc0d8438 100644 (file)
@@ -23,6 +23,7 @@
 #include "BVHVisitor.hxx"
 #include "BVHNode.hxx"
 #include "BVHGroup.hxx"
+#include "BVHPageNode.hxx"
 #include "BVHTransform.hxx"
 #include "BVHMotionTransform.hxx"
 #include "BVHLineGeometry.hxx"
@@ -45,6 +46,8 @@ public:
     
     virtual void apply(BVHGroup& node)
     { expandBy(node.getBoundingSphere()); }
+    virtual void apply(BVHPageNode& node)
+    { expandBy(node.getBoundingSphere()); }
     virtual void apply(BVHTransform& node)
     { expandBy(node.getBoundingSphere()); }
     virtual void apply(BVHMotionTransform& node)
index 1b93cd090bb8e9cf93595a42c5310527223d8261..86fdd659c76aebdbcaf15aea0e44124b1df47c87 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "BVHNode.hxx"
 #include "BVHGroup.hxx"
+#include "BVHPageNode.hxx"
 #include "BVHTransform.hxx"
 #include "BVHMotionTransform.hxx"
 #include "BVHLineGeometry.hxx"
@@ -47,6 +48,14 @@ BVHLineSegmentVisitor::apply(BVHGroup& group)
         return;
     group.traverse(*this);
 }
+
+void
+BVHLineSegmentVisitor::apply(BVHPageNode& pageNode)
+{
+    if (!intersects(_lineSegment, pageNode.getBoundingSphere()))
+        return;
+    pageNode.traverse(*this);
+}
     
 void
 BVHLineSegmentVisitor::apply(BVHTransform& transform)
index 40783ef3af4305ac134909fa562097789e34b55a..aa681a28c771496de8bb4fd7dbe5675259e8cdc5 100644 (file)
@@ -60,6 +60,7 @@ public:
     { return _id; }
 
     virtual void apply(BVHGroup& group);
+    virtual void apply(BVHPageNode& node);
     virtual void apply(BVHTransform& transform);
     virtual void apply(BVHMotionTransform& transform);
     virtual void apply(BVHLineGeometry&);
index 5b5e1975291b05cc5959dd578eefc417665b5ecf..7b3a5bbf4f650b2f7c4a64d07cb6e1577678f7b0 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "BVHNode.hxx"
 #include "BVHGroup.hxx"
+#include "BVHPageNode.hxx"
 #include "BVHTransform.hxx"
 #include "BVHLineGeometry.hxx"
 #include "BVHStaticGeometry.hxx"
@@ -52,6 +53,12 @@ public:
             return;
         leaf.traverse(*this);
     }
+    virtual void apply(BVHPageNode& leaf)
+    {
+        if (!intersects(_sphere, leaf.getBoundingSphere()))
+            return;
+        leaf.traverse(*this);
+    }
     virtual void apply(BVHTransform& transform)
     {
         if (!intersects(_sphere, transform.getBoundingSphere()))
index 10a0a957f3ae305aca373a0e8b6abbcf9631769d..755dd1a9408259f5fe28408460f273fd72d3f0ab 100644 (file)
@@ -26,6 +26,7 @@ namespace simgear {
 
 class BVHGroup;
 class BVHVisitor;
+class BVHPageNode;
 
 // Base for the tree nodes
 class BVHNode : public SGReferenced {
@@ -55,6 +56,7 @@ public:
     
 protected:
     friend class BVHGroup;
+    friend class BVHPageNode;
     void addParent(BVHNode* parent);
     void removeParent(BVHNode* parent);
     
diff --git a/simgear/bvh/BVHPageNode.cxx b/simgear/bvh/BVHPageNode.cxx
new file mode 100644 (file)
index 0000000..44c0d60
--- /dev/null
@@ -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);
+}
+
+}
diff --git a/simgear/bvh/BVHPageNode.hxx b/simgear/bvh/BVHPageNode.hxx
new file mode 100644 (file)
index 0000000..86fa576
--- /dev/null
@@ -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
diff --git a/simgear/bvh/BVHPageRequest.cxx b/simgear/bvh/BVHPageRequest.cxx
new file mode 100644 (file)
index 0000000..cecd4e0
--- /dev/null
@@ -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()
+{
+}
+
+}
diff --git a/simgear/bvh/BVHPageRequest.hxx b/simgear/bvh/BVHPageRequest.hxx
new file mode 100644 (file)
index 0000000..ab7f718
--- /dev/null
@@ -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
diff --git a/simgear/bvh/BVHPager.cxx b/simgear/bvh/BVHPager.cxx
new file mode 100644 (file)
index 0000000..668be8b
--- /dev/null
@@ -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;
+}
+
+}
diff --git a/simgear/bvh/BVHPager.hxx b/simgear/bvh/BVHPager.hxx
new file mode 100644 (file)
index 0000000..7e2e52e
--- /dev/null
@@ -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
index 5c8a915ce431c989366976cac03cd39da6c904de..6928dc7be3e017dbed81fda50a6e012ae2e644e5 100644 (file)
@@ -59,6 +59,22 @@ BVHSubTreeCollector::apply(BVHGroup& group)
     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
 BVHSubTreeCollector::apply(BVHTransform& transform)
 {
index aa3e1124ecb43f82d4e4212fdb52240bea2eb4eb..72f64ace5b98c931ab9ca9ee1e0a0b771859f7ad 100644 (file)
@@ -43,6 +43,7 @@ public:
     virtual ~BVHSubTreeCollector();
     
     virtual void apply(BVHGroup&);
+    virtual void apply(BVHPageNode&);
     virtual void apply(BVHTransform&);
     virtual void apply(BVHMotionTransform&);
     virtual void apply(BVHLineGeometry&);
index f74f445691bd508052759ea905af3fe2a3bf0a3d..b8a5c3bb70569b77f91bd17d56d7b1bcd82e3dda 100644 (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
 // modify it under the terms of the GNU Library General Public
@@ -23,6 +23,7 @@ namespace simgear {
 class BVHStaticData;
 
 class BVHGroup;
+class BVHPageNode;
 class BVHTransform;
 class BVHMotionTransform;
 class BVHStaticGeometry;
@@ -41,6 +42,7 @@ public:
 
     // High level nodes to handle
     virtual void apply(BVHGroup&) = 0;
+    virtual void apply(BVHPageNode&) = 0;
     virtual void apply(BVHTransform&) = 0;
     virtual void apply(BVHMotionTransform&) = 0;
     virtual void apply(BVHLineGeometry&) = 0;
index ee6f9eb5915247787fc381dc8fb156aa13cc198e..b5b477087e15c2b77f88e4dce0ff0b29e1c0bd17 100644 (file)
@@ -8,6 +8,9 @@ set(HEADERS
     BVHMotionTransform.hxx
     BVHNearestPointVisitor.hxx
     BVHNode.hxx
+    BVHPageNode.hxx
+    BVHPageRequest.hxx
+    BVHPager.hxx
     BVHStaticBinary.hxx
     BVHStaticData.hxx
     BVHStaticGeometry.hxx
@@ -27,6 +30,9 @@ set(SOURCES
     BVHLineSegmentVisitor.cxx
     BVHMotionTransform.cxx
     BVHNode.cxx
+    BVHPageNode.cxx
+    BVHPageRequest.cxx
+    BVHPager.cxx
     BVHStaticBinary.cxx
     BVHStaticGeometry.cxx
     BVHStaticLeaf.cxx