diff --git a/include/osgDB/DatabasePager b/include/osgDB/DatabasePager index 6f87c3c3c..163367448 100644 --- a/include/osgDB/DatabasePager +++ b/include/osgDB/DatabasePager @@ -28,10 +28,13 @@ #include #include +#include + #include #include #include + #include #include #include @@ -165,6 +168,15 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl * note, should be only be called from the update thread. */ virtual void registerPagedLODs(osg::Node* subgraph, int frameNumber = 0); + /** Set the incremental compile operation. + * Used to manage the OpenGL object compilation and merging of subgraphs in a way that avoids overloading + * the rendering of frame with too many new objects in one frame. */ + void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); + + /** Get the incremental compile operation. */ + osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation() { return _incrementalCompileOperation.get(); } + + /** Set whether the database pager should pre compile OpenGL objects before allowing * them to be merged into the scene graph. * Pre compilation helps reduce the chances of frame drops, but also slows the @@ -318,7 +330,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl /** Report how many items are in the _dataToCompileList queue */ unsigned int getDataToCompileListSize() const { return _dataToCompileList->size(); } - /** Report how many items are in the _dataToCompileList queue */ + /** Report how many items are in the _dataToMergeList queue */ unsigned int getDataToMergeListSize() const { return _dataToMergeList->size(); } /** Report whether any requests are in the pager.*/ @@ -338,7 +350,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl typedef std::set< osg::ref_ptr > StateSetList; typedef std::vector< osg::ref_ptr > DrawableList; - typedef std::pair DataToCompile; + //typedef std::pair DataToCompile; + typedef osgUtil::IncrementalCompileOperation::CompileData DataToCompile; typedef std::map< unsigned int, DataToCompile > DataToCompileMap; typedef std::set ActiveGraphicsContexts; typedef std::vector< osg::observer_ptr > CompileGraphicsContexts; @@ -358,6 +371,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl virtual bool containsPagedLOD(const osg::observer_ptr& plod) const = 0; }; + protected: virtual ~DatabasePager(); @@ -407,7 +421,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl return _valid && (frameNumber - _frameNumberLastRequest <= 1); } }; - + + struct RequestQueue : public osg::Referenced { public: @@ -470,7 +485,10 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl // forward declare inner helper classes class FindCompileableGLObjectsVisitor; friend class FindCompileableGLObjectsVisitor; - + + struct DatabasePagerCompileCompletedCallback; + friend struct DatabasePagerCompileCompletedCallback; + class FindPagedLODsVisitor; friend class FindPagedLODsVisitor; @@ -568,7 +586,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl return true; } - + void compileCompleted(DatabaseRequest* databaseRequest); + /** Iterate through the active PagedLOD nodes children removing * children which havn't been visited since specified expiryTime. * note, should be only be called from the update thread. */ @@ -620,6 +639,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl // CompileGraphicsContexts _compileGraphicsContexts; bool _doPreCompile; + osg::ref_ptr _incrementalCompileOperation; + double _targetFrameRate; double _minimumTimeAvailableForGLCompileAndDeletePerFrame; unsigned int _maximumNumOfObjectsToCompilePerFrame; diff --git a/include/osgDB/SharedStateManager b/include/osgDB/SharedStateManager index 9246a22e3..7c544ee7c 100644 --- a/include/osgDB/SharedStateManager +++ b/include/osgDB/SharedStateManager @@ -62,10 +62,14 @@ namespace osgDB { void apply(osg::Node& node); void apply(osg::Geode& geode); + // Answers the question "Will this state set be eliminated by // the SharedStateManager because an equivalent one has been // seen already?" Safe to call from the pager thread. bool isShared(osg::StateSet* stateSet); + + bool isShared(osg::Texture* texture); + protected: inline bool shareTexture(osg::Object::DataVariance variance) diff --git a/include/osgUtil/IncrementalCompileOperation b/include/osgUtil/IncrementalCompileOperation index d8f4b0146..36bf95ad9 100644 --- a/include/osgUtil/IncrementalCompileOperation +++ b/include/osgUtil/IncrementalCompileOperation @@ -109,6 +109,8 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation struct CompileCompletedCallback : public osg::Referenced { + /// return true if the callback assumes responsibility for merging any associated subgraphs with the main scene graph + /// return false if callback doesn't handle the merge, and instead requires the IncrementalCompileOperation to handle this for us virtual bool compileCompleted(CompileSet* compileSet) = 0; }; diff --git a/src/osgDB/CMakeLists.txt b/src/osgDB/CMakeLists.txt index 8f304dd10..b3db32ea9 100644 --- a/src/osgDB/CMakeLists.txt +++ b/src/osgDB/CMakeLists.txt @@ -151,6 +151,7 @@ ADD_DEFINITIONS(-DOSG_PLUGIN_EXTENSION=${CMAKE_SHARED_MODULE_SUFFIX}) LINK_INTERNAL(${LIB_NAME} osg + osgUtil OpenThreads ) LINK_EXTERNAL(${LIB_NAME} ${OSGDB_PLATFORM_SPECIFIC_LIBRARIES} ${DL_LIBRARY}) diff --git a/src/osgDB/DatabasePager.cpp b/src/osgDB/DatabasePager.cpp index af70e1712..32704cd91 100644 --- a/src/osgDB/DatabasePager.cpp +++ b/src/osgDB/DatabasePager.cpp @@ -105,6 +105,32 @@ RefPtrAdapter refPtrAdapt(const FuncObj& func) } } + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// CountPagedLODList +// +struct DatabasePager::DatabasePagerCompileCompletedCallback : public osgUtil::IncrementalCompileOperation::CompileCompletedCallback +{ + DatabasePagerCompileCompletedCallback(osgDB::DatabasePager* pager, osgDB::DatabasePager::DatabaseRequest* databaseRequest): + _pager(pager), + _databaseRequest(databaseRequest) {} + + virtual bool compileCompleted(osgUtil::IncrementalCompileOperation::CompileSet* compileSet) + { + _pager->compileCompleted(_databaseRequest.get()); + return true; + } + + osgDB::DatabasePager* _pager; + osg::ref_ptr _databaseRequest; +}; + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// CountPagedLODList +// class DatabasePager::CountPagedLODsVisitor : public osg::NodeVisitor { public: @@ -362,7 +388,6 @@ public: // if texture object attributes exist and need to be // compiled, add the state to the list for later // compilation. - bool compileStateSet = false; for(unsigned int i=0;igetTextureAttributeList().size();++i) { osg::Texture* texture = dynamic_cast(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE)); @@ -380,7 +405,8 @@ public: if (!_pager->isCompiled(texture)) { - compileStateSet = true; + _dataToCompile->_textures.push_back(texture); + if (osg::getNotifyLevel() >= osg::DEBUG_INFO) { OSG_INFO <<"Found compilable texture " << texture << " "; @@ -392,10 +418,6 @@ public: } } } - if (compileStateSet && _dataToCompile) - { - _dataToCompile->first.insert(stateset); - } } } @@ -437,7 +459,7 @@ public: // anything for VBOs, does it? if (_dataToCompile && (drawable->getUseVertexBufferObjects() || drawable->getUseDisplayList()) && !_pager->isCompiled(drawable)) { - _dataToCompile->second.push_back(drawable); + _dataToCompile->_drawables.push_back(drawable); } } @@ -991,13 +1013,21 @@ void DatabasePager::DatabaseThread::run() databaseRequest->_loadedModel->accept(frov); - if (_pager->_doPreCompile && - !_pager->_activeGraphicsContexts.empty()) + if (_pager->_doPreCompile && !dtc->empty()) { - if (!dtc->first.empty() || !dtc->second.empty()) + if (_pager->_incrementalCompileOperation.valid()) { - loadedObjectsNeedToBeCompiled = true; + OSG_NOTICE<<"Using IncrementalCompileOperation"<_loadedModel.get()); + compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(_pager, databaseRequest); + + _pager->_incrementalCompileOperation->add(compileSet); + + loadedObjectsNeedToBeCompiled = true; + } + else if (!_pager->_activeGraphicsContexts.empty()) + { // copy the objects from the compile list to the other graphics context list. for(; itr != _pager->_activeGraphicsContexts.end(); @@ -1012,7 +1042,10 @@ void DatabasePager::DatabaseThread::run() // dataToCompile or dataToMerge lists. if (loadedObjectsNeedToBeCompiled) { - _pager->_dataToCompileList->add(databaseRequest.get()); + if (!_pager->_incrementalCompileOperation) + { + _pager->_dataToCompileList->add(databaseRequest.get()); + } } else { @@ -1314,6 +1347,11 @@ DatabasePager::DatabasePager(const DatabasePager& rhs) } +void DatabasePager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico) +{ + _incrementalCompileOperation = ico; +} + DatabasePager::~DatabasePager() { cancel(); @@ -2052,6 +2090,12 @@ bool DatabasePager::requiresExternalCompileGLObjects(unsigned int contextID) con return osg::GraphicsContext::getCompileContext(contextID)==0; } +void DatabasePager::compileCompleted(DatabaseRequest* databaseRequest) +{ + OSG_NOTICE<<"DatabasePager::compileCompleted("<add(databaseRequest); +} + void DatabasePager::compileAllGLObjects(osg::State& state, bool doFlush) { double availableTime = DBL_MAX; @@ -2089,23 +2133,25 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime, b { DataToCompileMap& dcm = databaseRequest->_dataToCompileMap; DataToCompile& dtc = dcm[state.getContextID()]; - if (!dtc.first.empty() && (elapsedTime+estimatedTextureDuration)get(), state.getContextID()) || (sharedManager && sharedManager->isShared(itr->get()))) { @@ -2114,7 +2160,7 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime, b } double startCompileTime = timer.delta_s(start_tick,timer.tick()); - (*itr)->compileGLObjects(state); + (*itr)->apply(state); #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) GLint p; @@ -2130,19 +2176,20 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime, b } if (osg::getNotifyLevel() >= osg::DEBUG_INFO && numObjectsCompiled > objTemp) - OSG_INFO<< _frameNumber << " compiled " + OSG_NOTICE<< _frameNumber << " compiled " << numObjectsCompiled - objTemp << " StateSets" << std::endl; // remove the compiled statesets from the list. - sslist.erase(sslist.begin(),itr); + textures.erase(textures.begin(),itr); } - if (!dtc.second.empty() && (compileAll || ((elapsedTime+estimatedDrawableDuration)second.first.empty())) allCompiled=false; - if (!(itr->second.second.empty())) allCompiled=false; + if (!(itr->second.empty())) allCompiled=false; } - //if (numObjectsCompiled > 0) - //OSG_NOTICE<< _frameNumber << "compiled " << numObjectsCompiled << " objects" << std::endl; + if (numObjectsCompiled > 0) + OSG_NOTICE<< "Framenumber "<<_frameNumber << ": compiled " << numObjectsCompiled << " objects" << std::endl; if (allCompiled) { diff --git a/src/osgDB/SharedStateManager.cpp b/src/osgDB/SharedStateManager.cpp index 740afe31d..593c7816d 100644 --- a/src/osgDB/SharedStateManager.cpp +++ b/src/osgDB/SharedStateManager.cpp @@ -108,7 +108,7 @@ void SharedStateManager::apply(osg::Geode& geode) } } -bool SharedStateManager::isShared(osg::StateSet *ss) +bool SharedStateManager::isShared(osg::StateSet* ss) { if (shareStateSet(ss->getDataVariance())) { @@ -119,6 +119,17 @@ bool SharedStateManager::isShared(osg::StateSet *ss) return false; } +bool SharedStateManager::isShared(osg::Texture* texture) +{ + if (shareTexture(texture->getDataVariance())) + { + OpenThreads::ScopedLock lock(_listMutex); + return find(texture) != 0; + } + else + return false; +} + //---------------------------------------------------------------- // SharedStateManager::find //---------------------------------------------------------------- diff --git a/src/osgViewer/View.cpp b/src/osgViewer/View.cpp index 6af2b90c4..8573050a7 100644 --- a/src/osgViewer/View.cpp +++ b/src/osgViewer/View.cpp @@ -1601,6 +1601,11 @@ void View::assignSceneDataToCameras() { // OSG_NOTICE<<"View::assignSceneDataToCameras()"<getDatabasePager() && getViewerBase()) + { + _scene->getDatabasePager()->setIncrementalCompileOperation(getViewerBase()->getIncrementalCompileOperation()); + } + osg::Node* sceneData = _scene.valid() ? _scene->getSceneData() : 0; if (_cameraManipulator.valid()) diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index fd7f499cc..691abff3b 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -66,6 +66,11 @@ Viewer::Viewer(osg::ArgumentParser& arguments) //arguments.getApplicationUsage()->addCommandLineOption("--collar",""); //arguments.getApplicationUsage()->addCommandLineOption("--im",""); + if (arguments.read("--ico")) + { + setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation()); + } + std::string filename; bool readConfig = false; while (arguments.read("-c",filename)) diff --git a/src/osgViewer/ViewerBase.cpp b/src/osgViewer/ViewerBase.cpp index 57f1828b7..2cbd6bac9 100644 --- a/src/osgViewer/ViewerBase.cpp +++ b/src/osgViewer/ViewerBase.cpp @@ -563,6 +563,17 @@ void ViewerBase::setIncrementalCompileOperation(osgUtil::IncrementalCompileOpera // assign new operation _incrementalCompileOperation = ico; + Scenes scenes; + getScenes(scenes,false); + for(Scenes::iterator itr = scenes.begin(); + itr != scenes.end(); + ++itr) + { + osgDB::DatabasePager* dp = (*itr)->getDatabasePager(); + dp->setIncrementalCompileOperation(ico); + } + + if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); }