From 7507242891d9dca8460e8f4ef203ffc71f5e571f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 21 Dec 2010 09:36:03 +0000 Subject: [PATCH] Cleaned up the frame number increment. --- include/osgDB/DatabasePager | 21 +- src/osgDB/DatabasePager.cpp | 425 +++++++++++++++--------------------- 2 files changed, 188 insertions(+), 258 deletions(-) diff --git a/include/osgDB/DatabasePager b/include/osgDB/DatabasePager index b7efedf7c..1c45dceab 100644 --- a/include/osgDB/DatabasePager +++ b/include/osgDB/DatabasePager @@ -266,14 +266,14 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl class CountPagedLODsVisitor; + typedef std::list< osg::ref_ptr > ObjectList; + struct PagedLODList : public osg::Referenced { virtual PagedLODList* clone() = 0; virtual void clear() = 0; virtual unsigned int size() = 0; - virtual void moveInactivePagedLODTo(PagedLODList& inactivePagedLODList, const osg::FrameStamp& framestamp) = 0; - virtual void moveActivePagedLODTo(PagedLODList& activePagedLODList, const osg::FrameStamp& framestamp) = 0; - virtual void removeExpiredChildren(int& numberChildrenToRemove, double expiryTime, int expiryFrame, osg::NodeList& childrenRemoved) = 0; + virtual void removeExpiredChildren(int numberChildrenToRemove, double expiryTime, int expiryFrame, ObjectList& childrenRemoved, bool visitActive) = 0; virtual void removeNodes(osg::NodeList& nodesToRemove) = 0; virtual void insertPagedLOD(const osg::observer_ptr& plod) = 0; virtual bool containsPagedLOD(const osg::observer_ptr& plod) const = 0; @@ -300,8 +300,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl _frameNumberLastRequest(0), _timestampLastRequest(0.0), _priorityLastRequest(0.0f), - _numOfRequests(0), - _requestQueue(0) + _numOfRequests(0) {} void invalidate(); @@ -318,10 +317,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl float _priorityLastRequest; unsigned int _numOfRequests; osg::ObserverNodePath _observerNodePath; - osg::Group* _groupForAddingLoadedSubgraph; osg::ref_ptr _loadedModel; osg::ref_ptr _loadOptions; - RequestQueue* _requestQueue; osg::observer_ptr _compileSet; @@ -352,9 +349,9 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl void invalidate(DatabaseRequest* dr); - bool empty() const { return size()==0; } + bool empty(); - unsigned int size() const { return _size; } + unsigned int size(); void clear(); @@ -363,7 +360,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl void swap(RequestList& requestList); DatabasePager* _pager; - volatile unsigned int _size; RequestList _requestList; OpenThreads::Mutex _requestMutex; int _frameNumberLastPruned; @@ -374,7 +370,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl typedef std::vector< osg::ref_ptr > DatabaseThreadList; - typedef std::vector< osg::ref_ptr > ObjectList; struct ReadQueue : public RequestQueue { @@ -410,6 +405,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl OpenThreads::Mutex _run_mutex; + OpenThreads::Mutex _dr_mutex; bool _startThreadCalled; void compileCompleted(DatabaseRequest* databaseRequest); @@ -431,7 +427,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl int _numFramesActive; mutable OpenThreads::Mutex _numFramesActiveMutex; - int _frameNumber; + volatile int _frameNumber; osg::ref_ptr _fileRequestQueue; osg::ref_ptr _httpRequestQueue; @@ -449,7 +445,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl osg::ref_ptr _activePagedLODList; - osg::ref_ptr _inactivePagedLODList; unsigned int _targetMaximumNumberOfPageLOD; diff --git a/src/osgDB/DatabasePager.cpp b/src/osgDB/DatabasePager.cpp index 2e3f34668..98947684c 100644 --- a/src/osgDB/DatabasePager.cpp +++ b/src/osgDB/DatabasePager.cpp @@ -174,7 +174,7 @@ public: } - typedef std::set PagedLODset; + typedef std::set > PagedLODset; PagedLODset _pagedLODs; int _numPagedLODs; }; @@ -195,103 +195,59 @@ public: virtual PagedLODList* clone() { return new SetBasedPagedLODList(); } virtual void clear() { _pagedLODs.clear(); } virtual unsigned int size() { return _pagedLODs.size(); } - virtual void moveInactivePagedLODTo(PagedLODList& inactivePagedLODList, const osg::FrameStamp& frameStamp) + + virtual void removeExpiredChildren( + int numberChildrenToRemove, double expiryTime, int expiryFrame, + DatabasePager::ObjectList& childrenRemoved, bool visitActive) { + int leftToRemove = numberChildrenToRemove; for(PagedLODs::iterator itr = _pagedLODs.begin(); - itr != _pagedLODs.end(); + itr!=_pagedLODs.end() && leftToRemove >= 0; ) { osg::ref_ptr plod; if (itr->lock(plod)) { - int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal(); - if (delta>1) - { -#if 0 - if (_releaseDelay!=DBL_MAX) - { - plod->releaseGLObjects(); - } -#endif - inactivePagedLODList.insertPagedLOD(*itr); - - PagedLODs::iterator pitr = itr; - ++itr; - _pagedLODs.erase(pitr); - } - else + int delta = expiryFrame - plod->getFrameNumberOfLastTraversal(); + if ((visitActive && delta > 0) || (!visitActive && delta <= 0)) { ++itr; + continue; } - } - else - { - OSG_INFO<<"DatabasePager::removeExpiredSubgraphs(), removing PagedLOD from _activePagedLODLists"< plod; - if (itr->lock(plod)) - { - int delta = frameStamp.getFrameNumber() - plod->getFrameNumberOfLastTraversal(); - if (delta>1) + DatabasePager::CountPagedLODsVisitor countPagedLODsVisitor; + osg::NodeList expiredChildren; // expired PagedLODs + countPagedLODsVisitor.removeExpiredChildrenAndCountPagedLODs( + plod.get(), expiryTime, expiryFrame, expiredChildren); + // Clear any expired PagedLODs out of the set + for (DatabasePager::CountPagedLODsVisitor::PagedLODset::iterator + citr = countPagedLODsVisitor._pagedLODs.begin(), + end = countPagedLODsVisitor._pagedLODs.end(); + citr != end; + ++citr) { - ++itr; + osg::observer_ptr clod(*citr); + // This child PagedLOD cannot be equal to the + // PagedLOD pointed to by itr because it must be + // in itr's subgraph. Therefore erasing it doesn't + // invalidate itr. + if (_pagedLODs.erase(clod) > 0) + leftToRemove--; } - else - { - activePagedLODList.insertPagedLOD(*itr); - - PagedLODs::iterator pitr = itr; - ++itr; - _pagedLODs.erase(pitr); - } - } - else - { - OSG_INFO<<"DatabasePager::removeExpiredSubgraphs(), removing PagedLOD from _inactivePagedLODLists"< countPagedLODsVisitor._numPagedLODs; - ) - { - osg::ref_ptr plod; - if (itr->lock(plod) && countPagedLODsVisitor._pagedLODs.count(plod.get())==0) - { - countPagedLODsVisitor.removeExpiredChildrenAndCountPagedLODs(plod.get(), expiryTime, expiryFrame, childrenRemoved); - + childrenRemoved.insert(childrenRemoved.end(), + expiredChildren.begin(), + expiredChildren.end()); // advance the iterator to the next element ++itr; } else { - PagedLODs::iterator pitr = itr; - ++itr; - _pagedLODs.erase(pitr); + _pagedLODs.erase(itr++); + // numberChildrenToRemove includes possibly expired + // observer pointers. + leftToRemove--; OSG_INFO<<"DatabasePager::removeExpiredSubgraphs() _inactivePagedLOD has been invalidated, but ignored"<_compileSet="<_compileSet.get()< compileSet; if (dr->_compileSet.lock(compileSet) && _pager->getIncrementalCompileOperation()) { @@ -532,13 +485,15 @@ bool DatabasePager::RequestQueue::pruneOldRequestsAndCheckIfEmpty() { OpenThreads::ScopedLock lock(_requestMutex); - if (_frameNumberLastPruned != _pager->_frameNumber) + int frameNumber = _pager->_frameNumber; + if (_frameNumberLastPruned != frameNumber) { for(RequestQueue::RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ) { - if ((*citr)->isRequestCurrent(_pager->_frameNumber)) + OpenThreads::ScopedLock drLock(_pager->_dr_mutex); + if ((*citr)->isRequestCurrent(frameNumber)) { ++citr; } @@ -548,16 +503,10 @@ bool DatabasePager::RequestQueue::pruneOldRequestsAndCheckIfEmpty() OSG_INFO<<"DatabasePager::RequestQueue::pruneOldRequestsAndCheckIfEmpty(): Pruning "<<(*citr)<_requestQueue = this; - - if (_requestList.size()!=_size) - { - OSG_NOTICE<<"DatabasePager::add(): Error, _size = "<<_size<<" _requestList.size()="<<_requestList.size()< lock(_requestMutex); _requestList.swap(requestList); - _size = _requestList.size(); } void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr& databaseRequest) @@ -649,11 +593,14 @@ void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr& datab RequestQueue::RequestList::iterator selected_itr = _requestList.end(); + int frameNumber = _pager->_frameNumber; + for(RequestQueue::RequestList::iterator citr = _requestList.begin(); citr != _requestList.end(); ) { - if ((*citr)->isRequestCurrent(_pager->_frameNumber)) + OpenThreads::ScopedLock drLock(_pager->_dr_mutex); + if ((*citr)->isRequestCurrent(frameNumber)) { if (selected_itr==_requestList.end() || highPriority(*citr, *selected_itr)) { @@ -668,19 +615,16 @@ void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr& datab OSG_INFO<<"DatabasePager::RequestQueue::takeFirst(): Pruning "<<(*citr)<_frameNumber; + _frameNumberLastPruned = frameNumber; if (selected_itr != _requestList.end()) { databaseRequest = *selected_itr; - databaseRequest->_requestQueue = 0; _requestList.erase(selected_itr); - --_size; OSG_INFO<<" DatabasePager::RequestQueue::takeFirst() Found DatabaseRequest size()="<<_requestList.size()<& datab OSG_INFO<<" DatabasePager::RequestQueue::takeFirst() No suitable DatabaseRequest found size()="<<_requestList.size()<_fileName<add(databaseRequest.get()); databaseRequest = 0; } @@ -934,41 +881,46 @@ void DatabasePager::DatabaseThread::run() // assume that readNode is thread safe... ReaderWriter::ReadResult rr = readFromFileCache ? - fileCache->readNode(databaseRequest->_fileName, databaseRequest->_loadOptions.get(), false) : - Registry::instance()->readNode(databaseRequest->_fileName, databaseRequest->_loadOptions.get(), false); + fileCache->readNode(fileName, dr_loadOptions.get(), false) : + Registry::instance()->readNode(fileName, dr_loadOptions.get(), false); - if (rr.validNode()) databaseRequest->_loadedModel = rr.getNode(); - if (rr.error()) OSG_WARN<<"Error in reading file "<_fileName<<" : "<_fileName << std::endl; + osg::ref_ptr loadedModel; + if (rr.validNode()) loadedModel = rr.getNode(); + if (rr.error()) OSG_WARN<<"Error in reading file "<_loadedModel.valid() && + if (loadedModel.valid() && fileCache.valid() && - fileCache->isFileAppropriateForFileCache(databaseRequest->_fileName) && + fileCache->isFileAppropriateForFileCache(fileName) && !readFromFileCache) { - fileCache->writeNode(*(databaseRequest->_loadedModel), databaseRequest->_fileName, databaseRequest->_loadOptions.get()); + fileCache->writeNode(*(loadedModel), fileName, dr_loadOptions.get()); } - - if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)>1) - { - OSG_INFO<<_name<<": Warning DatabaseRquest no longer required."<_loadedModel = 0; - } - - // take a refNodePath to ensure that none of the nodes go out of scope while we are using them. osg::RefNodePath refNodePath; - if (!databaseRequest->_observerNodePath.getRefNodePath(refNodePath)) { - OSG_INFO<<_name<<": Warning node in parental chain has been deleted, discarding load."<_loadedModel = 0; + OpenThreads::ScopedLock drLock(_pager->_dr_mutex); + if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)>1) + { + OSG_INFO<<_name<<": Warning DatabaseRquest no longer required."<_observerNodePath.getRefNodePath(refNodePath)) + { + OSG_INFO<<_name<<": Warning node in parental chain has been deleted, discarding load."<delta_m(before,osg::Timer::instance()->tick())<<" ms"<_loadedModel.valid()) + if (loadedModel.valid()) { - databaseRequest->_loadedModel->getBound(); + loadedModel->getBound(); // find all the compileable rendering objects DatabasePager::FindCompileableGLObjectsVisitor frov(_pager->_changeAutoUnRef, _pager->_valueAutoUnRef, @@ -977,7 +929,9 @@ void DatabasePager::DatabaseThread::run() _pager); // push the soon to be parent on the nodepath of the NodeVisitor so that - // during traversal one can test for where it'll be in the overall scene graph + // during traversal one can test for where it'll be in the overall scene graph + // This is the benefit for osgTerrain::TerrainTile, so + // that it will find its Terrain node on its first traversal. for(osg::RefNodePath::iterator rnp_itr = refNodePath.begin(); rnp_itr != refNodePath.end(); ++rnp_itr) @@ -985,19 +939,27 @@ void DatabasePager::DatabaseThread::run() frov.pushOntoNodePath(rnp_itr->get()); } - databaseRequest->_loadedModel->accept(frov); + loadedModel->accept(frov); bool loadedObjectsNeedToBeCompiled = (_pager->_doPreCompile && frov.requiresCompilation() && _pager->_incrementalCompileOperation.valid()); // move the databaseRequest from the front of the fileRequest to the end of // dataToCompile or dataToMerge lists. + osgUtil::IncrementalCompileOperation::CompileSet* compileSet = 0; if (loadedObjectsNeedToBeCompiled) { // OSG_NOTICE<<"Using IncrementalCompileOperation"<_loadedModel.get()); + compileSet = new osgUtil::IncrementalCompileOperation::CompileSet(loadedModel.get()); compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(_pager, databaseRequest.get()); - + } + { + OpenThreads::ScopedLock drLock(_pager->_dr_mutex); + databaseRequest->_loadedModel = loadedModel; + databaseRequest->_compileSet = compileSet; + } + if (loadedObjectsNeedToBeCompiled) + { _pager->_incrementalCompileOperation->add(compileSet); databaseRequest->_compileSet = compileSet; @@ -1008,6 +970,7 @@ void DatabasePager::DatabaseThread::run() { _pager->_dataToMergeList->add(databaseRequest.get()); } + } // _pager->_dataToCompileList->pruneOldRequestsAndCheckIfEmpty(); @@ -1156,7 +1119,6 @@ DatabasePager::DatabasePager() } _activePagedLODList = new SetBasedPagedLODList; - _inactivePagedLODList = new SetBasedPagedLODList; } DatabasePager::DatabasePager(const DatabasePager& rhs) @@ -1199,7 +1161,6 @@ DatabasePager::DatabasePager(const DatabasePager& rhs) } _activePagedLODList = rhs._activePagedLODList->clone(); - _inactivePagedLODList = rhs._inactivePagedLODList->clone(); #if 1 // need to set the display list manager to be able to reuse display lists @@ -1362,7 +1323,6 @@ void DatabasePager::clear() // note, no need to use a mutex as the list is only accessed from the update thread. _activePagedLODList->clear(); - _inactivePagedLODList->clear(); // ?? // _activeGraphicsContexts @@ -1443,58 +1403,44 @@ void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* grou if (databaseRequestRef.valid()) { DatabaseRequest* databaseRequest = dynamic_cast(databaseRequestRef.get()); - if (databaseRequest && !(databaseRequest->valid())) - { - OSG_INFO<<"DatabaseRequest has been previously invalidated whilst still attached to scene graph."<_requestQueue; - if (requestQueue) + OpenThreads::ScopedLock drLock(_dr_mutex); + if (!(databaseRequest->valid())) { - OpenThreads::ScopedLock lock(requestQueue->_requestMutex); - - databaseRequest->_valid = true; - databaseRequest->_frameNumberLastRequest = frameNumber; - databaseRequest->_timestampLastRequest = timestamp; - databaseRequest->_priorityLastRequest = priority; - ++(databaseRequest->_numOfRequests); + OSG_INFO<<"DatabaseRequest has been previously invalidated whilst still attached to scene graph."<_valid = true; databaseRequest->_frameNumberLastRequest = frameNumber; databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; ++(databaseRequest->_numOfRequests); - } - foundEntry = true; + foundEntry = true; - if (databaseRequestRef->referenceCount()==1) - { - OSG_INFO<<"DatabasePager::requestNodeFile("<referenceCount()==1) + { + OSG_INFO<<"DatabasePager::requestNodeFile("<_valid = true; - databaseRequest->_frameNumberFirstRequest = frameNumber; - databaseRequest->_timestampFirstRequest = timestamp; - databaseRequest->_priorityFirstRequest = priority; - databaseRequest->_frameNumberLastRequest = frameNumber; - databaseRequest->_timestampLastRequest = timestamp; - databaseRequest->_priorityLastRequest = priority; - databaseRequest->_observerNodePath.setNodePathTo(group); - databaseRequest->_groupForAddingLoadedSubgraph = group; - databaseRequest->_loadOptions = loadOptions; - databaseRequest->_requestQueue = _fileRequestQueue.get(); - - _fileRequestQueue->add(databaseRequest); - } + databaseRequest->_frameNumberLastRequest = frameNumber; + databaseRequest->_timestampLastRequest = timestamp; + databaseRequest->_priorityLastRequest = priority; + databaseRequest->_observerNodePath.setNodePathTo(group); + databaseRequest->_loadOptions = loadOptions; + requeue = true; + } + } } + if (requeue) + _fileRequestQueue->add(databaseRequest); } if (!foundEntry) @@ -1518,13 +1464,10 @@ void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* grou databaseRequest->_timestampLastRequest = timestamp; databaseRequest->_priorityLastRequest = priority; databaseRequest->_observerNodePath.setNodePathTo(group); - databaseRequest->_groupForAddingLoadedSubgraph = group; databaseRequest->_loadOptions = loadOptions; - databaseRequest->_requestQueue = _fileRequestQueue.get(); _fileRequestQueue->addNoLock(databaseRequest.get()); } - } if (!_startThreadCalled) @@ -1586,8 +1529,14 @@ void DatabasePager::setDatabasePagerThreadPause(bool pause) if (_databasePagerThreadPaused == pause) return; _databasePagerThreadPaused = pause; - _fileRequestQueue->updateBlock(); - _httpRequestQueue->updateBlock(); + { + OpenThreads::ScopedLock lock(_fileRequestQueue->_requestMutex); + _fileRequestQueue->updateBlock(); + } + { + OpenThreads::ScopedLock lock(_httpRequestQueue->_requestMutex); + _httpRequestQueue->updateBlock(); + } } @@ -1655,12 +1604,14 @@ void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp) ++itr) { DatabaseRequest* databaseRequest = itr->get(); - + // No need to take _dr_mutex. The pager threads are done with + // the request; the cull traversal -- which might redispatch + // the request -- can't run at the sametime as this update traversal. osg::RefNodePath refNodePath; if (databaseRequest->_observerNodePath.getRefNodePath(refNodePath)) { // OSG_NOTICE<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<_groupForAddingLoadedSubgraph; + osg::Group* group = static_cast(refNodePath.back().get()); if (osgDB::Registry::instance()->getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get()); @@ -1685,8 +1636,7 @@ void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp) // Check if parent plod was already registered if not start visitor from parent if( plod && - !_activePagedLODList->containsPagedLOD( plod ) && - !_inactivePagedLODList->containsPagedLOD( plod ) ) + !_activePagedLODList->containsPagedLOD( plod ) ) { registerPagedLODs(plod, frameNumber); } @@ -1747,13 +1697,9 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp) osg::Timer_t startTick = osg::Timer::instance()->tick(); - _activePagedLODList->moveInactivePagedLODTo(*_inactivePagedLODList, frameStamp); - - _inactivePagedLODList->moveActivePagedLODTo(*_activePagedLODList, frameStamp); - - int inactivePLOD = _inactivePagedLODList->size(); - unsigned int numPagedLODs = _activePagedLODList->size() + inactivePLOD; - + // numPagedLODs >= actual number of PagedLODs. There can be + // invalid observer pointers in _activePagedLODList. + unsigned int numPagedLODs = _activePagedLODList->size(); osg::Timer_t end_a_Tick = osg::Timer::instance()->tick(); double time_a = osg::Timer::instance()->delta_m(startTick,end_a_Tick); @@ -1770,20 +1716,23 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp) } int numToPrune = numPagedLODs - _targetMaximumNumberOfPageLOD; - if (numToPrune > inactivePLOD) - { - numToPrune = inactivePLOD; - } - - osg::NodeList childrenRemoved; - childrenRemoved.reserve(numToPrune); + ObjectList childrenRemoved; double expiryTime = frameStamp.getReferenceTime() - 0.1; int expiryFrame = frameStamp.getFrameNumber() - 1; - if (numToPrune>0) _inactivePagedLODList->removeExpiredChildren(numToPrune, expiryTime, expiryFrame, childrenRemoved); - if (numToPrune>0) _activePagedLODList->removeExpiredChildren(numToPrune, expiryTime, expiryFrame, childrenRemoved); + // First traverse inactive PagedLODs, as their children will + // certainly have expired. Then traverse active nodes if we still + // need to prune. + //OSG_NOTICE<<"numToPrune "<0) + _activePagedLODList->removeExpiredChildren( + numToPrune, expiryTime, expiryFrame, childrenRemoved, false); + numToPrune = _activePagedLODList->size() - _targetMaximumNumberOfPageLOD; + if (numToPrune>0) + _activePagedLODList->removeExpiredChildren( + numToPrune, expiryTime, expiryFrame, childrenRemoved, true); osg::Timer_t end_b_Tick = osg::Timer::instance()->tick(); double time_b = osg::Timer::instance()->delta_m(end_a_Tick,end_b_Tick); @@ -1792,36 +1741,22 @@ void DatabasePager::removeExpiredSubgraphs(const osg::FrameStamp& frameStamp) s_total_time_stage_b += time_b; if (s_total_max_stage_b