diff --git a/applications/osgviewer/osgviewer.cpp b/applications/osgviewer/osgviewer.cpp index 6b3cfc4a4..7ca07ca86 100644 --- a/applications/osgviewer/osgviewer.cpp +++ b/applications/osgviewer/osgviewer.cpp @@ -117,6 +117,12 @@ int main( int argc, char **argv ) // wait for all cull and draw threads to complete before exit. viewer.sync(); + // run a clean up frame to delete all OpenGL objects. + viewer.cleanup_frame(); + + // wait for all the clean up frame to complete. + viewer.sync(); + return 0; } diff --git a/examples/osghangglide/osghangglide.cpp b/examples/osghangglide/osghangglide.cpp index 5b74f6a5a..616ecba43 100644 --- a/examples/osghangglide/osghangglide.cpp +++ b/examples/osghangglide/osghangglide.cpp @@ -166,6 +166,12 @@ int main( int argc, char **argv ) // wait for all cull and draw threads to complete before exit. viewer.sync(); + // run a clean up frame to delete all OpenGL objects. + viewer.cleanup_frame(); + + // wait for all the clean up frame to complete. + viewer.sync(); + return 0; } diff --git a/examples/osgwindows/osgwindows.cpp b/examples/osgwindows/osgwindows.cpp index fd9241d11..e3c418dd3 100644 --- a/examples/osgwindows/osgwindows.cpp +++ b/examples/osgwindows/osgwindows.cpp @@ -159,6 +159,12 @@ int main( int argc, char **argv ) // wait for all cull and draw threads to complete before exit. viewer.sync(); + // run a clean up frame to delete all OpenGL objects. + viewer.cleanup_frame(); + + // wait for all the clean up frame to complete. + viewer.sync(); + return 0; } diff --git a/include/osg/Drawable b/include/osg/Drawable index c64e73ef6..dcad58516 100644 --- a/include/osg/Drawable +++ b/include/osg/Drawable @@ -238,10 +238,9 @@ class OSG_EXPORT Drawable : public Object */ virtual void compileGLObjects(State& state) const; - /** - if osg::State object is supplied: release any OpenGL display lists associated with graphics context specified - or - if state pointer is NULL: release all display lists for all graphics contexts */ + /** If State is non-zero, this function releases OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ virtual void releaseGLObjects(State* state=0) const; struct UpdateCallback : public virtual osg::Object diff --git a/include/osg/Geode b/include/osg/Geode index 4c36a0faf..2eb66f067 100644 --- a/include/osg/Geode +++ b/include/osg/Geode @@ -132,6 +132,11 @@ class OSG_EXPORT Geode : public Node return _bbox; } + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + protected: virtual ~Geode(); diff --git a/include/osg/Group b/include/osg/Group index 3c322423f..285191b1e 100644 --- a/include/osg/Group +++ b/include/osg/Group @@ -120,6 +120,12 @@ class OSG_EXPORT Group : public Node return _children.size(); // node not found. } + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: virtual ~Group(); diff --git a/include/osg/Node b/include/osg/Node index 4583fb4b2..c7df1892d 100644 --- a/include/osg/Node +++ b/include/osg/Node @@ -248,6 +248,12 @@ class OSG_EXPORT Node : public Object void dirtyBound(); + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: /** Node destructor. Note, is protected so that Nodes cannot diff --git a/include/osg/Object b/include/osg/Object index 57ff1d1ff..e1ff2e079 100644 --- a/include/osg/Object +++ b/include/osg/Object @@ -20,6 +20,9 @@ namespace osg { +// forward declare +class State; + /** META_Object macro define the standard clone, isSameKindAs and className methods. * Use when subclassing from Object to make it more convenient to define * the standard pure virtual clone, isSameKindAs and className methods @@ -102,6 +105,11 @@ class OSG_EXPORT Object : public Referenced inline const Referenced* getUserData() const { return _userData.get(); } + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const {} + protected: /** Object destructor. Note, is protected so that Objects cannot diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 0abbd06f2..a2cf416ec 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -349,7 +349,11 @@ class OSGDB_EXPORT Registry : public osg::Referenced /** Remove all archives from the archive cache.*/ void clearArchiveCache(); - + + /** If State is non-zero, this function releases OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + void releaseGLObjects(osg::State* state=0); /** get the attached library with specified name.*/ DynamicLibrary* getLibrary(const std::string& fileName); diff --git a/include/osgProducer/OsgCameraGroup b/include/osgProducer/OsgCameraGroup index 7275daeb2..0372577b9 100644 --- a/include/osgProducer/OsgCameraGroup +++ b/include/osgProducer/OsgCameraGroup @@ -188,9 +188,16 @@ class OSGPRODUCER_EXPORT OsgCameraGroup : public Producer::CameraGroup /** Dispatch the cull and draw for each of the Camera's for this frame.*/ virtual void frame(); + + + /** Dispatch a clean up frame that should be called before closing a OsgCameraGroup, i.e. on exit from an app. + * The clean up frame first release all GL objects associated with all the graphics context associated with + * the camera group, then runs a special frame that does the actual OpenGL deletion of GL objects for each + * graphics context. */ + virtual void cleanup_frame(); - protected : + protected : virtual void setUpSceneViewsWithData(); diff --git a/include/osgProducer/OsgSceneHandler b/include/osgProducer/OsgSceneHandler index 677dbf70e..ec80128ab 100644 --- a/include/osgProducer/OsgSceneHandler +++ b/include/osgProducer/OsgSceneHandler @@ -79,8 +79,15 @@ class OSGPRODUCER_EXPORT OsgSceneHandler : public Producer::Camera::SceneHandler virtual void draw(Producer::Camera& camera) { + if (_flushOfAllDeletedGLObjectsOnNextFrame && _sceneView.valid()) + { + _sceneView->flushAllDeletedGLObjects(); + } + if (_drawCallback.valid()) (*_drawCallback)(*this,camera); else drawImplementation(camera); + + _flushOfAllDeletedGLObjectsOnNextFrame = false; } virtual void drawImplementation(Producer::Camera& camera); @@ -89,10 +96,12 @@ class OSGPRODUCER_EXPORT OsgSceneHandler : public Producer::Camera::SceneHandler Callback* getDrawCallback() { return _drawCallback.get(); } const Callback* getDrawCallback() const { return _drawCallback.get(); } - - void setContextID( int id ); + void setFlushOfAllDeletedGLObjectsOnNextFrame(bool flag) { _flushOfAllDeletedGLObjectsOnNextFrame = flag; } + + bool getFlushOfAllDeletedGLObjectsOnNextFrame() const { return _flushOfAllDeletedGLObjectsOnNextFrame; } + protected: virtual ~OsgSceneHandler() {} @@ -106,6 +115,8 @@ class OSGPRODUCER_EXPORT OsgSceneHandler : public Producer::Camera::SceneHandler osg::Timer_t _frameStartTick; osg::Timer_t _previousFrameStartTick; + + bool _flushOfAllDeletedGLObjectsOnNextFrame; }; } diff --git a/include/osgText/Font b/include/osgText/Font index 6d369a52b..67048e18f 100644 --- a/include/osgText/Font +++ b/include/osgText/Font @@ -120,7 +120,7 @@ public: /** If State is non-zero, this function releases OpenGL objects for * the specified graphics context. Otherwise, releases OpenGL objexts * for all graphics contexts. */ - virtual void releaseGLObjects(osg::State* state=0) const; + virtual void releaseGLObjects(osg::State* state=0) const; protected: diff --git a/include/osgText/Text b/include/osgText/Text index 695dc5cff..d7a8f4a15 100644 --- a/include/osgText/Text +++ b/include/osgText/Text @@ -235,6 +235,10 @@ public: /** accept a PrimtiveFunctor and call its methods to tell it about the interal primtives that this Drawable has.*/ virtual void accept(osg::PrimitiveFunctor& pf) const; + /** If State is non-zero, this function releases OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* state=0) const; // make Font a friend to allow it set the _font to 0 if the font is // forcefully unloaded. diff --git a/runexamples.bat b/runexamples.bat index e37084497..867079deb 100644 --- a/runexamples.bat +++ b/runexamples.bat @@ -30,14 +30,14 @@ osgclip cow.osg echo osgcubemap osgcubemap cessna.osg -# echo osgdepthshadow -# osgdepthshadow +echo osgdepthshadow +osgdepthshadow echo osgdistortion osgdistortion cow.osg -#echo osgforest -#osgforest +echo osgforest +osgforest echo osgfxbrowser osgfxbrowser dumptruck.osg @@ -64,7 +64,7 @@ echo osglight osglight glider.osg echo osglightpoint -#osglightpoint +osglightpoint echo osglogo osglogo @@ -96,8 +96,8 @@ osgplanets echo osgprerender osgprerender dumptruck.osg -#echo osgprerendercubemap -#osgprerendercubemap +echo osgprerendercubemap +osgprerendercubemap echo osgreflect osgreflect cessna.osg diff --git a/src/osg/Drawable.cpp b/src/osg/Drawable.cpp index 9aa0e274d..9deb7eaf7 100644 --- a/src/osg/Drawable.cpp +++ b/src/osg/Drawable.cpp @@ -490,6 +490,8 @@ void Drawable::compileGLObjects(State& state) const void Drawable::releaseGLObjects(State* state) const { + if (_stateset.valid()) _stateset->releaseGLObjects(state); + if (!_useDisplayList) return; if (state) diff --git a/src/osg/Geode.cpp b/src/osg/Geode.cpp index 5524be59a..75f866549 100644 --- a/src/osg/Geode.cpp +++ b/src/osg/Geode.cpp @@ -214,3 +214,15 @@ void Geode::compileDrawables(State& state) (*itr)->compileGLObjects(state); } } + +void Geode::releaseGLObjects(osg::State* state) const +{ + Node::releaseGLObjects(state); + + for(DrawableList::const_iterator itr=_drawables.begin(); + itr!=_drawables.end(); + ++itr) + { + (*itr)->releaseGLObjects(state); + } +} diff --git a/src/osg/Group.cpp b/src/osg/Group.cpp index 3dfb695b6..c605fdddc 100644 --- a/src/osg/Group.cpp +++ b/src/osg/Group.cpp @@ -388,3 +388,15 @@ bool Group::computeBound() const _bsphere_computed = true; return true; } + +void Group::releaseGLObjects(osg::State* state) const +{ + Node::releaseGLObjects(state); + + for(NodeList::const_iterator itr=_children.begin(); + itr!=_children.end(); + ++itr) + { + (*itr)->releaseGLObjects(state); + } +} diff --git a/src/osg/Node.cpp b/src/osg/Node.cpp index 28eb855bb..a31ce83a9 100644 --- a/src/osg/Node.cpp +++ b/src/osg/Node.cpp @@ -427,3 +427,11 @@ void Node::dirtyBound() } } + +void Node::releaseGLObjects(osg::State* state) const +{ + if (_stateset.valid()) _stateset->releaseGLObjects(state); +} + + + diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 96fd58a44..3cdede0c1 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -1787,6 +1787,19 @@ void Registry::clearArchiveCache() _archiveCache.clear(); } +void Registry::releaseGLObjects(osg::State* state) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + for(ObjectCache::iterator itr = _objectCache.begin(); + itr != _objectCache.end(); + ++itr) + { + osg::Object* object = itr->second.first.get(); + object->releaseGLObjects(state); + } +} + DatabasePager* Registry::getOrCreateDatabasePager() { if (!_databasePager) _databasePager = new DatabasePager; diff --git a/src/osgProducer/OsgCameraGroup.cpp b/src/osgProducer/OsgCameraGroup.cpp index 94f4c1681..af439658c 100644 --- a/src/osgProducer/OsgCameraGroup.cpp +++ b/src/osgProducer/OsgCameraGroup.cpp @@ -644,3 +644,23 @@ void OsgCameraGroup::frame() CameraGroup::frame(); } +void OsgCameraGroup::cleanup_frame() +{ + // first relase all GL objects and switch on the flush of deleted objects + // in the next frame. + for(SceneHandlerList::iterator itr = _shvec.begin(); + itr != _shvec.end(); + ++itr) + { + (*itr)->getSceneView()->releaseAllGLObjects(); + (*itr)->setFlushOfAllDeletedGLObjectsOnNextFrame(true); + } + + // make sure that the registry all flushes all its texture objects. + osgDB::Registry::instance()->releaseGLObjects(); + + // then run the frame to do the actuall OpenGL clean up. + frame(); +} + + diff --git a/src/osgProducer/OsgSceneHandler.cpp b/src/osgProducer/OsgSceneHandler.cpp index 95378251e..f8522fce8 100644 --- a/src/osgProducer/OsgSceneHandler.cpp +++ b/src/osgProducer/OsgSceneHandler.cpp @@ -25,6 +25,7 @@ OsgSceneHandler::OsgSceneHandler( osg::DisplaySettings *ds) : { _frameStartTick = 0; _previousFrameStartTick = 0; + _flushOfAllDeletedGLObjectsOnNextFrame = false; } void OsgSceneHandler::init() diff --git a/src/osgText/Text.cpp b/src/osgText/Text.cpp index 60b920a95..39e32de4b 100644 --- a/src/osgText/Text.cpp +++ b/src/osgText/Text.cpp @@ -1008,3 +1008,12 @@ void Text::accept(osg::PrimitiveFunctor& pf) const } } + +/** If State is non-zero, this function releases OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objexts + * for all graphics contexts. */ +void Text::releaseGLObjects(osg::State* state) const +{ + Drawable::releaseGLObjects(state); + if (_font.valid()) _font->releaseGLObjects(state); +} diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index 339a60923..1f7e6ff76 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -641,15 +641,14 @@ void SceneView::releaseAllGLObjects() { if (!_sceneData) return; - GLObjectsVisitor globjv(GLObjectsVisitor::RELEASE_DISPLAY_LISTS|GLObjectsVisitor::RELEASE_STATE_ATTRIBUTES); - globjv.setNodeMaskOverride(0xffffffff); - globjv.setState(_state.get()); - _sceneData->accept(globjv); + _sceneData->releaseGLObjects(_state.get()); } void SceneView::flushAllDeletedGLObjects() { + osg::notify(osg::NOTICE)<<"SceneView::flushAllDeletedGLObjects()"<getContextID(),currentTime,availableTime); osg::VertexProgram::flushDeletedVertexProgramObjects(_state->getContextID(),currentTime,availableTime); osg::FragmentProgram::flushDeletedFragmentProgramObjects(_state->getContextID(),currentTime,availableTime); -} + osg::Program::flushDeletedGlPrograms(_state->getContextID(),currentTime,availableTime); + } void SceneView::flushDeletedGLObjects(double& availableTime) { @@ -672,6 +672,7 @@ void SceneView::flushDeletedGLObjects(double& availableTime) osg::Drawable::flushDeletedVertexBufferObjects(_state->getContextID(),currentTime,availableTime); osg::VertexProgram::flushDeletedVertexProgramObjects(_state->getContextID(),currentTime,availableTime); osg::FragmentProgram::flushDeletedFragmentProgramObjects(_state->getContextID(),currentTime,availableTime); + osg::Program::flushDeletedGlPrograms(_state->getContextID(),currentTime,availableTime); } void SceneView::draw()