From 8bce22343b9ed55c4efad183b9a325e961a2ed04 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 18 Sep 2004 19:28:45 +0000 Subject: [PATCH] Various improvements to the DatabasePager with the aim to achieve constant framerates and minimizing memory consumption. --- include/osg/StateAttribute | 2 +- include/osgDB/DatabasePager | 27 ++++- src/osgDB/DatabasePager.cpp | 230 +++++++++++++++++++----------------- 3 files changed, 142 insertions(+), 117 deletions(-) diff --git a/include/osg/StateAttribute b/include/osg/StateAttribute index ac64a4d60..0644a12de 100644 --- a/include/osg/StateAttribute +++ b/include/osg/StateAttribute @@ -20,7 +20,7 @@ #include -// #define THREAD_SAFE_GLOBJECT_DELETE_LISTS 1 +#define THREAD_SAFE_GLOBJECT_DELETE_LISTS 1 namespace osg { diff --git a/include/osgDB/DatabasePager b/include/osgDB/DatabasePager index 52d5c3f76..150deb5a5 100644 --- a/include/osgDB/DatabasePager +++ b/include/osgDB/DatabasePager @@ -36,14 +36,14 @@ class Block: public osg::Referenced { public: Block():_released(false) {} - void block() + inline void block() { OpenThreads::ScopedLock mutlock(_mut); if( !_released ) _cond.wait(&_mut); } - void release() + inline void release() { OpenThreads::ScopedLock mutlock(_mut); if (!_released) @@ -53,11 +53,20 @@ class Block: public osg::Referenced { } } - void reset() + inline void reset() { OpenThreads::ScopedLock mutlock(_mut); _released = false; } + + inline void set(bool doRelease) + { + if (doRelease!=_released) + { + if (doRelease) release(); + else reset(); + } + } protected: @@ -184,7 +193,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl public: - typedef std::vector< osg::ref_ptr > PagedLODList; + typedef std::set< osg::ref_ptr > PagedLODList; typedef std::vector< osg::ref_ptr > StateSetList; typedef std::vector< osg::ref_ptr > DrawableList; @@ -221,6 +230,15 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl protected : virtual ~DatabasePager(); + + osg::ref_ptr _databasePagerThreadBlock; + + inline void updateDatabasePagerThreadBlock() + { + _databasePagerThreadBlock->set( + !_fileRequestList.empty() || !_childrenToDeleteList.empty()); + } + bool _useFrameBlock; osg::ref_ptr _frameBlock; @@ -231,7 +249,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl DatabaseRequestList _fileRequestList; OpenThreads::Mutex _fileRequestListMutex; - osg::ref_ptr _fileRequestListEmptyBlock; DatabaseRequestList _dataToCompileList; OpenThreads::Mutex _dataToCompileListMutex; diff --git a/src/osgDB/DatabasePager.cpp b/src/osgDB/DatabasePager.cpp index 697338d64..5ca2d4979 100644 --- a/src/osgDB/DatabasePager.cpp +++ b/src/osgDB/DatabasePager.cpp @@ -1,4 +1,4 @@ -#include + #include #include #include @@ -23,7 +23,7 @@ DatabasePager::DatabasePager() _useFrameBlock = false; _frameNumber = 0; _frameBlock = new Block; - _fileRequestListEmptyBlock = new Block; + _databasePagerThreadBlock = new Block; _threadPriorityDuringFrame = PRIORITY_MIN; _threadPriorityOutwithFrame = PRIORITY_MIN; @@ -61,9 +61,9 @@ DatabasePager::~DatabasePager() cancel(); //join(); - // release the frameBlock and _fileRequestListEmptyBlock incase its holding up thread cancelation. + // release the frameBlock and _databasePagerThreadBlock incase its holding up thread cancelation. _frameBlock->release(); - _fileRequestListEmptyBlock->release(); + _databasePagerThreadBlock->release(); // then wait for the the thread to stop running. while(isRunning()) @@ -160,9 +160,9 @@ void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* grou databaseRequest->_priorityLastRequest = priority; databaseRequest->_groupForAddingLoadedSubgraph = group; - if (_fileRequestList.empty()) _fileRequestListEmptyBlock->release(); - _fileRequestList.push_back(databaseRequest); + + updateDatabasePagerThreadBlock(); } _fileRequestListMutex.unlock(); @@ -313,7 +313,7 @@ void DatabasePager::run() do { - _fileRequestListEmptyBlock->block(); + _databasePagerThreadBlock->block(); if (_useFrameBlock) { @@ -325,12 +325,22 @@ void DatabasePager::run() // if (_deleteRemovedSubgraphsInDatabaseThread) { + osg::ref_ptr obj = 0; _childrenToDeleteListMutex.lock(); if (!_childrenToDeleteList.empty()) { - //std::cout<<"In DatabasePager thread deleting "<<_childrenToDeleteList.size()<<" objects"<tick(); + obj = _childrenToDeleteList.back(); + _childrenToDeleteList.pop_back(); + //osg::notify(osg::NOTICE)<<"Done DatabasePager thread deleted in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<<" objects"<_fileName<<")"<tick(); + // osg::notify(osg::NOTICE)<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick(); databaseRequest->_loadedModel = osgDB::readNodeFile(databaseRequest->_fileName); - osg::notify(osg::INFO)<<" node read in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<delta_m(before,osg::Timer::instance()->tick())<<" ms"<reset(); + updateDatabasePagerThreadBlock(); _fileRequestListMutex.unlock(); @@ -433,7 +443,7 @@ void DatabasePager::run() _fileRequestList.erase(_fileRequestList.begin()); - if (_fileRequestList.empty()) _fileRequestListEmptyBlock->reset(); + updateDatabasePagerThreadBlock(); _fileRequestListMutex.unlock(); @@ -470,6 +480,7 @@ void DatabasePager::addLoadedDataToSceneGraph(double timeStamp) { DatabaseRequest* databaseRequest = itr->get(); + // osg::notify(osg::NOTICE)<<"Merging "<<_frameNumber-(*itr)->_frameNumberLastRequest<getSharedStateManager()) osgDB::Registry::instance()->getSharedStateManager()->share(databaseRequest->_loadedModel.get()); @@ -491,120 +502,71 @@ void DatabasePager::addLoadedDataToSceneGraph(double timeStamp) } -/** Helper class used internally to force the release of texture objects - * and displace lists.*/ -class ReleaseTexturesAndDrawablesVisitor : public osg::NodeVisitor +/** Helper class used clean up PagedLODList.*/ +class CleanUpPagedLODVisitor : public osg::NodeVisitor { public: - ReleaseTexturesAndDrawablesVisitor(): - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + CleanUpPagedLODVisitor(DatabasePager::PagedLODList& pagedLODList): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _pagedLODList(pagedLODList) {} + + virtual void apply(osg::PagedLOD& node) { - } - - void releaseGLObjects(DatabasePager::ObjectList& objectsToDelete) - { - for(TextureSet::iterator titr=_textureSet.begin(); - titr!=_textureSet.end(); - ++titr) - { - if ((*titr)->referenceCount()==1) - { - osg::Texture* texture = const_cast(titr->get()); - texture->releaseGLObjects(); - objectsToDelete.push_back(texture); - } - } - - for(DrawableSet::iterator ditr=_drawableSet.begin(); - ditr!=_drawableSet.end(); - ++ditr) - { - if ((*ditr)->referenceCount()==1) - { - osg::Drawable* drawable = const_cast(ditr->get()); - drawable->releaseGLObjects(); - objectsToDelete.push_back(drawable); - } - } - } - - inline void apply(osg::StateSet* stateset) - { - if (stateset) - { - // search for the existance of any texture object attributes - bool foundTextureState = false; - osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList(); - for(osg::StateSet::TextureAttributeList::iterator itr=tal.begin(); - itr!=tal.end() && !foundTextureState; - ++itr) - { - osg::StateSet::AttributeList& al = *itr; - osg::StateSet::AttributeList::iterator alitr = al.find(osg::StateAttribute::TEXTURE); - if (alitr!=al.end()) - { - // found texture, so place it in the texture list. - osg::Texture* texture = static_cast(alitr->second.first.get()); - _textureSet.insert(texture); - } - - } - } - } - - inline void apply(osg::Drawable* drawable) - { - apply(drawable->getStateSet()); - - _drawableSet.insert(drawable); - } - - virtual void apply(osg::Node& node) - { - apply(node.getStateSet()); - + DatabasePager::PagedLODList::iterator pitr = _pagedLODList.find(&node); + if (pitr != _pagedLODList.end()) _pagedLODList.erase(pitr); traverse(node); } + + DatabasePager::PagedLODList& _pagedLODList; - virtual void apply(osg::Geode& geode) - { - apply(geode.getStateSet()); - - for(unsigned int i=0;i > DrawableSet; - typedef std::set< osg::ref_ptr > TextureSet; - - TextureSet _textureSet; - DrawableSet _drawableSet; }; void DatabasePager::removeExpiredSubgraphs(double currentFrameTime) { + // osg::notify(osg::NOTICE)<<"DatabasePager::removeExpiredSubgraphs()"<get(); - plod->removeExpiredChildren(expiryTime,childrenRemoved); + const osg::PagedLOD* plod = itr->get(); + const_cast(plod)->removeExpiredChildren(expiryTime,childrenRemoved); } + if (!childrenRemoved.empty()) + { + // clean up local ref's to paged lods + CleanUpPagedLODVisitor cuplv(_pagedLODList); + for (osg::NodeList::iterator critr = childrenRemoved.begin(); + critr!=childrenRemoved.end(); + ++critr) + { + (*critr)->accept(cuplv); + } - if (osgDB::Registry::instance()->getSharedStateManager()) - osgDB::Registry::instance()->getSharedStateManager()->prune(); + // pass the objects across to the database pager delete list + { + OpenThreads::ScopedLock lock(_childrenToDeleteListMutex); + for (osg::NodeList::iterator critr = childrenRemoved.begin(); + critr!=childrenRemoved.end(); + ++critr) + { + _childrenToDeleteList.push_back(critr->get()); + } + updateDatabasePagerThreadBlock(); + } + + childrenRemoved.clear(); + } +#if 0 if (_deleteRemovedSubgraphsInDatabaseThread) { @@ -644,6 +606,7 @@ void DatabasePager::removeExpiredSubgraphs(double currentFrameTime) osg::PagedLOD* plod = _pagedLODList[i].get(); if (plod->referenceCount()==1) { + osg::notify(osg::NOTICE)<<"PagedLOD "<referenceCount()<getSharedStateManager()) + osgDB::Registry::instance()->getSharedStateManager()->prune(); + // update the Registry object cache. osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExtenalReferences(currentFrameTime); osgDB::Registry::instance()->removeExpiredObjectsInCache(expiryTime); @@ -669,7 +637,7 @@ public: virtual void apply(osg::PagedLOD& plod) { - _pagedLODList.push_back(&plod); + _pagedLODList.insert(&plod); traverse(plod); } @@ -707,6 +675,8 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime) const osg::Timer& timer = *osg::Timer::instance(); osg::Timer_t start_tick = timer.tick(); double elapsedTime = 0.0; + double estimatedTextureDuration = 0.0; + double estimatedDrawableDuration = 0.0; osg::ref_ptr databaseRequest; @@ -715,6 +685,22 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime) if (!_dataToCompileList.empty()) { std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor()); + + DatabaseRequestList::iterator litr; + int i=0; + for(litr = _dataToCompileList.begin(); + (litr != _dataToCompileList.end()) && (_frameNumber == (*litr)->_frameNumberLastRequest); + ++litr,i++) + { + //osg::notify(osg::NOTICE)<<"Compile "<<_frameNumber-(*litr)->_frameNumberLastRequest<_dataToCompileMap; DataToCompile& dtc = dcm[state.getContextID()]; - if (!dtc.first.empty() && elapsedTimecompileGLObjects(state); + + GLint p; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_RESIDENT, &p); + elapsedTime = timer.delta_s(start_tick,timer.tick()); + + + // estimate the duration of the compile based on current compile duration. + estimatedTextureDuration = (elapsedTime-startCompileTime); } // remove the compiled stateset from the list. sslist.erase(sslist.begin(),itr); } - if (!dtc.second.empty() && elapsedTimecompileGLObjects(state); elapsedTime = timer.delta_s(start_tick,timer.tick()); + + // estimate the duration of the compile based on current compile duration. + estimatedDrawableDuration = (elapsedTime-startCompileTime); } // remove the compiled drawables from the list. dwlist.erase(dwlist.begin(),itr); @@ -807,5 +812,8 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime) } availableTime -= elapsedTime; + + //osg::notify(osg::NOTICE)<<"estimatedTextureDuration="<