From 7473b06275c7fcdd0f389bd5dc82bf78a5fa6133 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 8 Mar 2009 12:00:36 +0000 Subject: [PATCH] Preliminary work on general purpose incremental compile support in osgViewer. --- examples/osgterrain/osgterrain.cpp | 123 ++++++++++++---------- include/osgUtil/GLObjectsVisitor | 106 ++++++++++++++++++- include/osgViewer/ViewerBase | 43 +++++--- src/osg/GraphicsContext.cpp | 4 +- src/osgUtil/GLObjectsVisitor.cpp | 164 +++++++++++++++++++++++++++++ src/osgViewer/CompositeViewer.cpp | 10 ++ src/osgViewer/Viewer.cpp | 12 ++- src/osgViewer/ViewerBase.cpp | 17 ++- 8 files changed, 405 insertions(+), 74 deletions(-) diff --git a/examples/osgterrain/osgterrain.cpp b/examples/osgterrain/osgterrain.cpp index ad8ae8733..52ee24998 100644 --- a/examples/osgterrain/osgterrain.cpp +++ b/examples/osgterrain/osgterrain.cpp @@ -57,16 +57,35 @@ typedef std::vector< osg::ref_ptr > GraphicsThreads; +struct ReleaseBlockOnCompileCompleted : public osgUtil::IncrementalCompileOperation::CompileCompletedCallback +{ + + ReleaseBlockOnCompileCompleted(osg::RefBlockCount* block): + _block(block) {} + + virtual bool compileCompleted(osgUtil::IncrementalCompileOperation::CompileSet* compileSet) + { + if (_block.valid()) _block->completed(); + + // tell IncrementalCompileOperation that it's now safe to remove the compileSet + + osg::notify(osg::NOTICE)<<"compileCompleted("< _block; +}; class LoadAndCompileOperation : public osg::Operation { public: - LoadAndCompileOperation(const std::string& filename, GraphicsThreads& graphicsThreads, osg::RefBlockCount* block): + LoadAndCompileOperation(const std::string& filename, osgUtil::IncrementalCompileOperation* ico , osg::RefBlockCount* block): Operation("Load and compile Operation", false), _filename(filename), - _graphicsThreads(graphicsThreads), + _incrementalCompileOperation(ico), _block(block) {} virtual void operator () (osg::Object* object) @@ -74,28 +93,28 @@ public: // osg::notify(osg::NOTICE)<<"LoadAndCompileOperation "<<_filename< compileOperation = new osgUtil::GLObjectsOperation(_loadedModel.get()); - - for(GraphicsThreads::iterator gitr = _graphicsThreads.begin(); - gitr != _graphicsThreads.end(); - ++gitr) - { - (*gitr)->add( compileOperation.get() ); - // requiresBarrier = true; - } - } - if (_block.valid()) _block->completed(); + if (_loadedModel.valid() && _incrementalCompileOperation.valid()) + { + osg::ref_ptr compileSet = + new osgUtil::IncrementalCompileOperation::CompileSet(_loadedModel); + + compileSet->_compileCompletedCallback = new ReleaseBlockOnCompileCompleted(_block.get()); + + _incrementalCompileOperation->add(compileSet.get()); + } + else + { + if (_block.valid()) _block->completed(); + } // osg::notify(osg::NOTICE)<<"done LoadAndCompileOperation "<<_filename< _loadedModel; - osg::ref_ptr _block; + std::string _filename; + osg::ref_ptr _loadedModel; + osg::ref_ptr _incrementalCompileOperation; + osg::ref_ptr _block; }; @@ -108,9 +127,10 @@ public: typedef std::vector< osg::ref_ptr > Nodes; - MasterOperation(const std::string& filename): + MasterOperation(const std::string& filename, osgUtil::IncrementalCompileOperation* ico): Operation("Master reading operation",true), - _filename(filename) + _filename(filename), + _incrementalCompileOperation(ico) { } @@ -256,9 +276,6 @@ public: if (gt) threads.push_back(gt); } - bool requiresBarrier = false; - - if (_operationQueue.valid()) { // osg::notify(osg::NOTICE)<<"Using OperationQueue"< loadAndCompile = new LoadAndCompileOperation( *nitr, threads, _endOfLoadBlock.get() ); + osg::ref_ptr loadAndCompile = new LoadAndCompileOperation( *nitr, _incrementalCompileOperation.get(), _endOfLoadBlock.get() ); loadAndCompileList.push_back(loadAndCompile); _operationQueue->add( loadAndCompile.get() ); } @@ -300,7 +317,6 @@ public: if ((*litr)->_loadedModel.valid()) { nodesToAdd[(*litr)->_filename] = (*litr)->_loadedModel; - requiresBarrier = true; } } @@ -308,6 +324,11 @@ public: else { + + _endOfLoadBlock = new osg::RefBlockCount(newFiles.size()); + + _endOfLoadBlock->reset(); + for(Files::iterator nitr = newFiles.begin(); nitr != newFiles.end(); ++nitr) @@ -318,38 +339,30 @@ public: { nodesToAdd[*nitr] = loadedModel; - osg::ref_ptr compileOperation = new osgUtil::GLObjectsOperation(loadedModel.get()); - - for(GraphicsThreads::iterator gitr = threads.begin(); - gitr != threads.end(); - ++gitr) + if (_incrementalCompileOperation.valid()) { - (*gitr)->add( compileOperation.get() ); - requiresBarrier = true; + osg::ref_ptr compileSet = + new osgUtil::IncrementalCompileOperation::CompileSet(loadedModel.get()); + + compileSet->_compileCompletedCallback = new ReleaseBlockOnCompileCompleted(_endOfLoadBlock.get()); + + _incrementalCompileOperation->add(compileSet.get()); + } + else + { + _endOfLoadBlock->completed(); } } + else + { + _endOfLoadBlock->completed(); + } } + + _endOfLoadBlock->block(); + } - if (requiresBarrier) - { - _endOfCompilebarrier = new osg::BarrierOperation(threads.size()+1); - _endOfCompilebarrier->setKeep(false); - - for(GraphicsThreads::iterator gitr = threads.begin(); - gitr != threads.end(); - ++gitr) - { - (*gitr)->add(_endOfCompilebarrier.get()); - } - - // osg::notify(osg::NOTICE)<<"Waiting for Compile to complete"<block(); - - // osg::notify(osg::NOTICE)<<"done ... Waiting for Compile to complete"< _incrementalCompileOperation; osg::ref_ptr _endOfCompilebarrier; osg::ref_ptr _endOfLoadBlock; @@ -618,6 +632,9 @@ int main(int argc, char** argv) // add the record camera path handler viewer.addEventHandler(new osgViewer::RecordCameraPathHandler); + // attach an IncrementaCompileOperation to allow the master loading + // to be handled with an incremental compile to avoid frame drops when large objects are added. + viewer.setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation()); double x = 0.0; double y = 0.0; @@ -631,7 +648,7 @@ int main(int argc, char** argv) std::string masterFilename; while(arguments.read("-m",masterFilename)) { - masterOperation = new MasterOperation(masterFilename); + masterOperation = new MasterOperation(masterFilename, viewer.getIncrementalCompileOperation()); } diff --git a/include/osgUtil/GLObjectsVisitor b/include/osgUtil/GLObjectsVisitor index 343586f99..1b20394f1 100644 --- a/include/osgUtil/GLObjectsVisitor +++ b/include/osgUtil/GLObjectsVisitor @@ -123,13 +123,117 @@ class OSGUTIL_EXPORT GLObjectsOperation : public osg::GraphicsOperation GLObjectsOperation(osg::Node* subgraph, GLObjectsVisitor::Mode mode = GLObjectsVisitor::COMPILE_DISPLAY_LISTS|GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES|GLObjectsVisitor::CHECK_BLACK_LISTED_MODES); virtual void operator () (osg::GraphicsContext* context); - + protected: osg::ref_ptr _subgraph; GLObjectsVisitor::Mode _mode; }; +class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation +{ + public: + + IncrementalCompileOperation(); + + typedef std::vector Contexts; + void assignContexts(Contexts& contexts); + void removeContexts(Contexts& contexts); + + void addGraphicsContext(osg::GraphicsContext* gc); + void removeGraphicsContext(osg::GraphicsContext* gc); + + + /** Merge subgraphs that have been compiled.*/ + void mergeCompiledSubgraphs(); + + virtual void operator () (osg::GraphicsContext* context); + + + + struct CompileData : public osg::Referenced + { + typedef std::list< osg::ref_ptr > Textures; + typedef std::list< osg::ref_ptr > Drawables; + typedef std::list< osg::ref_ptr > Programs; + + bool empty() const { return _textures.empty() && _drawables.empty() && _programs.empty(); } + + Textures _textures; + Drawables _drawables; + Programs _programs; + }; + + class CompileSet; + typedef std::set ContextSet; + typedef std::map > CompileMap; + + struct CompileCompletedCallback : public osg::Referenced + { + virtual bool compileCompleted(CompileSet* compileSet) = 0; + }; + + class CompileSet : public osg::Referenced + { + public: + + + CompileSet() {} + + CompileSet(osg::Node*subgraphToCompile): + _subgraphToCompile(subgraphToCompile) {} + + CompileSet(osg::Group* attachmentPoint, osg::Node*subgraphToCompile): + _attachmentPoint(attachmentPoint), + _subgraphToCompile(subgraphToCompile) {} + + void buildCompileMap(ContextSet& context); + + osg::ref_ptr _attachmentPoint; + osg::ref_ptr _subgraphToCompile; + osg::ref_ptr _compileCompletedCallback; + CompileMap _compileMap; + + // protected: + + virtual ~CompileSet() {} + }; + + typedef std::list< osg::ref_ptr > CompileSets; + + + /** Add a subgraph to be compiled.*/ + void add(osg::Node* subgraphToCompile); + + /** Add a subgraph to be compiled and add automatically to attachPoint on call to mergeCompiledSubgraphs.*/ + void add(osg::Group* attachmentPoint, osg::Node* subgraphToCompile); + + /** Add a CompileSet to be compiled.*/ + void add(CompileSet* compileSet, bool callBuildCompileMap=true); + + + OpenThreads::Mutex& getToCompiledMutex() { return _toCompileMutex; } + CompileSets& getToCompile() { return _compiled; } + + OpenThreads::Mutex& getCompiledMutex() { return _compiledMutex; } + CompileSets& getCompiled() { return _compiled; } + + protected: + + virtual ~IncrementalCompileOperation(); + + + OpenThreads::Mutex _toCompileMutex; + CompileSets _toCompile; + + OpenThreads::Mutex _compiledMutex; + CompileSets _compiled; + + ContextSet _contexts; + +}; + + } #endif diff --git a/include/osgViewer/ViewerBase b/include/osgViewer/ViewerBase index 35074c5a5..cb43f386d 100644 --- a/include/osgViewer/ViewerBase +++ b/include/osgViewer/ViewerBase @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -184,6 +185,15 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object /** Get the graphics operation to call on realization of the viewers graphics windows.*/ osg::Operation* getRealizeOperation() { return _realizeOperation.get(); } + + + /** 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(); } /** Check to see if windows are still open, if not set viewer done to true. */ @@ -260,29 +270,30 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object virtual void viewerInit() = 0; - bool _firstFrame; - bool _done; - int _keyEventSetsDone; - bool _quitEventSetsDone; - bool _releaseContextAtEndOfFrameHint; + bool _firstFrame; + bool _done; + int _keyEventSetsDone; + bool _quitEventSetsDone; + bool _releaseContextAtEndOfFrameHint; - ThreadingModel _threadingModel; - bool _threadsRunning; + ThreadingModel _threadingModel; + bool _threadsRunning; - BarrierPosition _endBarrierPosition; + BarrierPosition _endBarrierPosition; - osg::ref_ptr _startRenderingBarrier; - osg::ref_ptr _endRenderingDispatchBarrier; - osg::ref_ptr _endDynamicDrawBlock; + osg::ref_ptr _startRenderingBarrier; + osg::ref_ptr _endRenderingDispatchBarrier; + osg::ref_ptr _endDynamicDrawBlock; - osg::ref_ptr _eventVisitor; + osg::ref_ptr _eventVisitor; - osg::ref_ptr _updateOperations; - osg::ref_ptr _updateVisitor; + osg::ref_ptr _updateOperations; + osg::ref_ptr _updateVisitor; - osg::ref_ptr _realizeOperation; + osg::ref_ptr _realizeOperation; + osg::ref_ptr _incrementalCompileOperation; - osg::observer_ptr _currentContext; + osg::observer_ptr _currentContext; }; } diff --git a/src/osg/GraphicsContext.cpp b/src/osg/GraphicsContext.cpp index 4a9b73c6a..f8949b374 100644 --- a/src/osg/GraphicsContext.cpp +++ b/src/osg/GraphicsContext.cpp @@ -317,7 +317,7 @@ GraphicsContext::GraphicsContexts GraphicsContext::getRegisteredGraphicsContexts GraphicsContext* GraphicsContext::getOrCreateCompileContext(unsigned int contextID) { - osg::notify(osg::INFO)<<"GraphicsContext::createCompileContext."< lock(s_contextIDMapMutex); @@ -349,7 +349,7 @@ GraphicsContext* GraphicsContext::getOrCreateCompileContext(unsigned int context { OpenThreads::ScopedLock lock(s_contextIDMapMutex); s_contextIDMap[contextID]._compileContext = gc; - osg::notify(osg::INFO)<<" succeeded GraphicsContext::createCompileContext."< #include #include +#include using namespace osg; using namespace osgUtil; + +///////////////////////////////////////////////////////////////// +// +// GLObjectsVisitor +// GLObjectsVisitor::GLObjectsVisitor(Mode mode) { setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); @@ -145,6 +151,11 @@ void GLObjectsVisitor::apply(osg::StateSet& stateset) } } +///////////////////////////////////////////////////////////////// +// +// GLObjectsVisitor +// + GLObjectsOperation::GLObjectsOperation(GLObjectsVisitor::Mode mode): osg::GraphicsOperation("GLObjectOperation",false), _mode(mode) @@ -182,3 +193,156 @@ void GLObjectsOperation::operator () (osg::GraphicsContext* context) } // osg::notify(osg::NOTICE)<<"GLObjectsOperation::after >>>>>>>>>>> "<add(this); + _contexts.insert(gc); + } +} + +void IncrementalCompileOperation::removeGraphicsContext(osg::GraphicsContext* gc) +{ + if (_contexts.count(gc)!=0) + { + gc->remove(this); + _contexts.erase(gc); + } +} + +void IncrementalCompileOperation::add(osg::Node* subgraphToCompile) +{ + osg::notify(osg::NOTICE)<<"IncrementalCompileOperation::add("<buildCompileMap(_contexts); + + osg::notify(osg::NOTICE)<<"IncrementalCompileOperation::add(CompileSet = "< lock(_toCompileMutex); + _toCompile.push_back(compileSet); +} + +void IncrementalCompileOperation::mergeCompiledSubgraphs() +{ + osg::notify(osg::NOTICE)<<"IncrementalCompileOperation::mergeCompiledSubgraphs()"< compilded_lock(_compiledMutex); + + for(CompileSets::iterator itr = _compiled.begin(); + itr != _compiled.end(); + ++itr) + { + CompileSet* cs = itr->get(); + if (cs->_attachmentPoint.valid()) + { + cs->_attachmentPoint->addChild(cs->_subgraphToCompile.get()); + } + } + + _compiled.clear(); +} + +void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& context) +{ +} + +void IncrementalCompileOperation::operator () (osg::GraphicsContext* context) +{ + osg::notify(osg::NOTICE)<<"IncrementalCompileOperation::operator () ("< toCompile_lock(_toCompileMutex); + for(CompileSets::iterator itr = _toCompile.begin(); + itr != _toCompile.end(); + ) + { + CompileSet* cs = itr->get(); + CompileMap& cm = cs->_compileMap; + CompileData* cd = cm[context].get(); + + if (cd) + { + // compile textures + cd->_textures.clear(); + + // compile drawables + cd->_drawables.clear(); + + // compile programs + cd->_programs.clear(); + } + + if (!cd || cd->empty()) + { + if (cs->_compileCompletedCallback.valid()) + { + if (cs->_compileCompletedCallback->compileCompleted(cs)) + { + // callback will handle merging of subgraph so no need to place CompileSet in merge. + } + else + { + OpenThreads::ScopedLock compilded_lock(_compiledMutex); + _compiled.push_back(cs); + } + } + + // remove from toCompileSet; + itr = _toCompile.erase(itr); + } + else + { + ++itr; + } + } +} diff --git a/src/osgViewer/CompositeViewer.cpp b/src/osgViewer/CompositeViewer.cpp index 53c64700b..3d94f3385 100644 --- a/src/osgViewer/CompositeViewer.cpp +++ b/src/osgViewer/CompositeViewer.cpp @@ -497,6 +497,10 @@ void CompositeViewer::realize() } } + // attach contexts to _incrementalCompileOperation if attached. + if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); + + bool grabFocus = true; if (grabFocus) { @@ -994,6 +998,12 @@ void CompositeViewer::updateTraversal() } + if (_incrementalCompileOperation.valid()) + { + // merge subgraphs that have been compiled by the incremental compiler operation. + _incrementalCompileOperation->mergeCompiledSubgraphs(); + } + if (_updateOperations.valid()) { _updateOperations->runOperations(this); diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index 0a9135863..86b1b6666 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -448,7 +448,10 @@ void Viewer::realize() gc->releaseContext(); } } - + + // attach contexts to _incrementalCompileOperation if attached. + if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); + bool grabFocus = true; if (grabFocus) { @@ -898,6 +901,13 @@ void Viewer::updateTraversal() { _updateOperations->runOperations(this); } + + if (_incrementalCompileOperation.valid()) + { + // merge subgraphs that have been compiled by the incremental compiler operation. + _incrementalCompileOperation->mergeCompiledSubgraphs(); + } + { // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph diff --git a/src/osgViewer/ViewerBase.cpp b/src/osgViewer/ViewerBase.cpp index 6faebb4b9..b0a3d0eea 100644 --- a/src/osgViewer/ViewerBase.cpp +++ b/src/osgViewer/ViewerBase.cpp @@ -375,7 +375,7 @@ void ViewerBase::startThreading() if (!gc->isRealized()) { - osg::notify(osg::INFO)<<"ViewerBase::startThreading() : Realizng window "<realize(); } @@ -551,6 +551,21 @@ void ViewerBase::removeUpdateOperation(osg::Operation* operation) } } +void ViewerBase::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico) +{ + if (_incrementalCompileOperation == ico) return; + + Contexts contexts; + getContexts(contexts, false); + + if (_incrementalCompileOperation.valid()) _incrementalCompileOperation->removeContexts(contexts); + + // assign new operation + _incrementalCompileOperation = ico; + + if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); +} + int ViewerBase::run() { if (!isRealized())