From 6d9641a78b4bb20fa4c648581f95b1e566eb24c1 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 2 Feb 2007 12:41:13 +0000 Subject: [PATCH] Added a concrete osg::DeleteHandler implementation which provides support for retain objects for several frames before deleting them. Also added RenderStageCache into CullVistor.cpp that is used for handling RTT osg::Camera's that are being used in double buffered SceneView usage. --- VisualStudio/osg/osg.dsp | 8 +++ include/osg/DeleteHandler | 83 ++++++++++++++++++++++++ include/osg/Referenced | 33 ++-------- include/osgUtil/RenderLeaf | 11 ++++ src/osg/DeleteHandler.cpp | 126 ++++++++++++++++++++++++++++++++++++ src/osg/GNUmakefile | 1 + src/osg/Referenced.cpp | 43 ++---------- src/osgProducer/Viewer.cpp | 7 ++ src/osgUtil/CullVisitor.cpp | 44 ++++++++++++- src/osgUtil/RenderBin.cpp | 4 +- src/osgViewer/Viewer.cpp | 16 +++++ 11 files changed, 309 insertions(+), 67 deletions(-) create mode 100644 include/osg/DeleteHandler create mode 100644 src/osg/DeleteHandler.cpp diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index e28e650a2..ca8e60822 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -280,6 +280,10 @@ SOURCE=..\..\src\osg\CullStack.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\DeleteHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Depth.cpp # End Source File # Begin Source File @@ -748,6 +752,10 @@ SOURCE=..\..\Include\Osg\CullStack # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\DeleteHandler +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Depth # End Source File # Begin Source File diff --git a/include/osg/DeleteHandler b/include/osg/DeleteHandler new file mode 100644 index 000000000..f7c161ac9 --- /dev/null +++ b/include/osg/DeleteHandler @@ -0,0 +1,83 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSG_DELETEHANDLER +#define OSG_DELETEHANDLER 1 + +#include + +#include + +namespace osg { + + +/** Class for override the default delete behavior so that users can implement their own object + * deletion schemes. This might be done to help implement protection of multiple threads from deleting + * objects unintentionally. + * Note, the DeleteHandler cannot itself be reference counted, otherwise it + * would be responsible for deleting itself! + * An static auto_ptr<> is used internally in Referenced.cpp to manage the + * DeleteHandler's memory.*/ +class DeleteHandler +{ + public: + + typedef std::pair FrameNumberObjectPair; + typedef std::list ObjectsToDeleteList; + + DeleteHandler(int numberOfFramesToRetainObjects=0); + + virtual ~DeleteHandler() { flushAll(); } + + /** Set the number of frames to retain objects that are have been requested for deletion. + * When set to zero objects are deleted immediately, by set to 1 there are kept around for an extra frame etc. + * The ability to retain obejcts for several frames is useful to prevent premature deletion when objects + * are stil be used the graphics threads that are using double buffering of rendering data structures with + * non ref_ptr<> pointers to scene graph elements.*/ + void setNumFramesToRetainObjects(int numberOfFramesToRetainObjects) { _numFramesToRetainObjects = numberOfFramesToRetainObjects; } + + int getNumFramesToRetainObjects() const { return _numFramesToRetainObjects; } + + /** Set the current frame numberso that subsequent deletes get tagged as associated with this frame.*/ + void setFrameNumber(int frameNumber) { _currentFrameNumber = frameNumber; } + + /** Get the current frame number.*/ + int getFrameNumber() const { return _currentFrameNumber; } + + inline void doDelete(const Referenced* object) { delete object; } + + /** Flush objects that ready to be fully deleted.*/ + virtual void flush(); + + /** Flush all objects that the DeleteHandler holds. + * Note, this should only be called if there are no threads running with non ref_ptr<> pointers, such as graphics threads.*/ + virtual void flushAll(); + + /** Request the deletion of an object. + * Depending on users implementation of DeleteHandler, the delete of the object may occur + * straight away or be delayed until doDelete is called. + * The default implementation does a delete straight away.*/ + virtual void requestDelete(const osg::Referenced* object); + + protected: + + int _numFramesToRetainObjects; + int _currentFrameNumber; + OpenThreads::Mutex _mutex; + ObjectsToDeleteList _objectsToDelete; + +}; + +} + +#endif diff --git a/include/osg/Referenced b/include/osg/Referenced index b08b6765a..2d72707cd 100644 --- a/include/osg/Referenced +++ b/include/osg/Referenced @@ -30,6 +30,7 @@ #include #endif + namespace osg { #ifndef OSG_JAVA_BUILD @@ -104,8 +105,11 @@ class OSG_EXPORT Referenced protected: + virtual ~Referenced(); + void deletUsingDeleteHandler() const; + mutable OpenThreads::Mutex* _refMutex; mutable int _refCount; @@ -114,32 +118,6 @@ class OSG_EXPORT Referenced }; - -/** Class for override the default delete behavior so that users can implment their own object - * deletion schemes. This might be done to help implement protection of multiple threads from deleting - * objects unintentionally. - * Note, the DeleteHandler cannot itself be reference counted, otherwise it - * would be responsible for deleting itself! - * An static auto_ptr<> is used internally in Referenced.cpp to manage the - * DeleteHandler's memory.*/ -class DeleteHandler -{ - public: - - virtual ~DeleteHandler() {} - - /** flush any cache of objects that need to be deleted by doing an actual delete.*/ - virtual void flush() {} - - inline void doDelete(const Referenced* object) { delete object; } - - /** Request the deletion of an object. - * Depending on users implementation of DeleteHandler, the delete of the object may occur - * straight away or be delayed until doDelete is called. - * The default implementation does a delete straight away.*/ - virtual void requestDelete(const Referenced* object) { doDelete(object); } -}; - inline void Referenced::ref() const { if (_refMutex) @@ -170,13 +148,14 @@ inline void Referenced::unref() const if (needDelete) { - if (getDeleteHandler()) getDeleteHandler()->requestDelete(this); + if (getDeleteHandler()) deletUsingDeleteHandler(); else delete this; } } #else + /** Java wrappers use the CBridgable base-class for referencing * and garbage collection. */ diff --git a/include/osgUtil/RenderLeaf b/include/osgUtil/RenderLeaf index 2c5ad0dc1..6fd2dc55e 100644 --- a/include/osgUtil/RenderLeaf +++ b/include/osgUtil/RenderLeaf @@ -72,8 +72,19 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced public: + + StateGraph* _parent; + +#if 1 osg::Drawable* _drawable; + osg::Drawable* getDrawable() { return _drawable; } + osg::Drawable* getDrawable() const { return _drawable; } +#else + osg::ref_ptr _drawable; + osg::Drawable* getDrawable() { return _drawable.get(); } + osg::Drawable* getDrawable() const { return _drawable.get(); } +#endif osg::ref_ptr _projection; osg::ref_ptr _modelview; float _depth; diff --git a/src/osg/DeleteHandler.cpp b/src/osg/DeleteHandler.cpp new file mode 100644 index 000000000..677b252e6 --- /dev/null +++ b/src/osg/DeleteHandler.cpp @@ -0,0 +1,126 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ +#include +#include + +namespace osg +{ + +// specialzed smart pointer, used to get round auto_ptr<>'s lack of the destructor reseting itself to 0. +struct DeleteHandlerPointer +{ + DeleteHandlerPointer(): + _ptr(0) {} + + DeleteHandlerPointer(DeleteHandler* ptr): + _ptr(ptr) {} + + ~DeleteHandlerPointer() + { + delete _ptr; + _ptr = 0; + } + + inline DeleteHandlerPointer& operator = (DeleteHandler* ptr) + { + if (_ptr==ptr) return *this; + delete _ptr; + _ptr = ptr; + return *this; + } + + void reset(DeleteHandler* ptr) + { + if (_ptr==ptr) return; + delete _ptr; + _ptr = ptr; + } + + inline DeleteHandler& operator*() { return *_ptr; } + + inline const DeleteHandler& operator*() const { return *_ptr; } + + inline DeleteHandler* operator->() { return _ptr; } + + inline const DeleteHandler* operator->() const { return _ptr; } + + DeleteHandler* get() { return _ptr; } + + const DeleteHandler* get() const { return _ptr; } + + DeleteHandler* _ptr; +}; + + +DeleteHandler::DeleteHandler(int numberOfFramesToRetainObjects): + _numFramesToRetainObjects(numberOfFramesToRetainObjects) +{ +} + +void DeleteHandler::flush() +{ + typedef std::list DeletionList; + DeletionList deletionList; + + { + // gather all the objects to delete whilst holding the mutex to the _objectsToDelete + // list, but delete the objects outside this scoped lock so that if any objects deleted + // unref their children then no deadlock happens. + OpenThreads::ScopedLock lock(_mutex); + int frameNumberToClearTo = _currentFrameNumber - _numFramesToRetainObjects; + + ObjectsToDeleteList::iterator itr; + for(itr = _objectsToDelete.begin(); + itr != _objectsToDelete.end(); + ++itr) + { + if (itr->first > frameNumberToClearTo) break; + + deletionList.push_back(itr->second); + + itr->second = 0; + } + + _objectsToDelete.erase( _objectsToDelete.begin(), itr); + } + + for(DeletionList::iterator ditr = deletionList.begin(); + ditr != deletionList.end(); + ++ditr) + { + doDelete(*ditr); + } + +} + +void DeleteHandler::flushAll() +{ + int temp = _numFramesToRetainObjects; + _numFramesToRetainObjects = 0; + + flush(); + + _numFramesToRetainObjects = temp; +} + +void DeleteHandler::requestDelete(const osg::Referenced* object) +{ + if (_numFramesToRetainObjects==0) doDelete(object); + else + { + OpenThreads::ScopedLock lock(_mutex); + _objectsToDelete.push_back(FrameNumberObjectPair(_currentFrameNumber,object)); + } +} + +}; // end of namespace osg diff --git a/src/osg/GNUmakefile b/src/osg/GNUmakefile index 8dbf16dfa..e90882133 100644 --- a/src/osg/GNUmakefile +++ b/src/osg/GNUmakefile @@ -33,6 +33,7 @@ CXXFILES =\ CullingSet.cpp\ CullSettings.cpp\ CullStack.cpp\ + DeleteHandler.cpp\ Depth.cpp\ DisplaySettings.cpp\ Drawable.cpp\ diff --git a/src/osg/Referenced.cpp b/src/osg/Referenced.cpp index 7d8161044..ae7a9a3ec 100644 --- a/src/osg/Referenced.cpp +++ b/src/osg/Referenced.cpp @@ -22,6 +22,8 @@ #include #include +#include + #ifndef OSG_JAVA_BUILD namespace osg @@ -177,43 +179,7 @@ void Referenced::setThreadSafeRefUnref(bool threadSafe) } } -/* -void Referenced::ref() const -{ - if (_refMutex) - { - OpenThreads::ScopedLock lock(*_refMutex); - ++_refCount; - } - else - { - ++_refCount; - } -} - -void Referenced::unref() const -{ - bool needDelete = false; - if (_refMutex) - { - OpenThreads::ScopedLock lock(*_refMutex); - --_refCount; - needDelete = _refCount<=0; - } - else - { - --_refCount; - needDelete = _refCount<=0; - } - - if (needDelete) - { - if (getDeleteHandler()) getDeleteHandler()->requestDelete(this); - else delete this; - } -} -*/ void Referenced::unref_nodelete() const { if (_refMutex) @@ -257,6 +223,11 @@ void Referenced::removeObserver(Observer* observer) } } +void Referenced::deletUsingDeleteHandler() const +{ + getDeleteHandler()->requestDelete(this); +} + }; // end of namespace osg #endif //OSG_JAVA_BUILD diff --git a/src/osgProducer/Viewer.cpp b/src/osgProducer/Viewer.cpp index ba70e2986..4bc4da549 100644 --- a/src/osgProducer/Viewer.cpp +++ b/src/osgProducer/Viewer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -260,6 +261,12 @@ Viewer::Viewer(osg::ArgumentParser& arguments): Viewer::~Viewer() { + setSceneData(0); + + if (osg::Referenced::getDeleteHandler()) + { + osg::Referenced::getDeleteHandler()->flushAll(); + } } osg::NodePath Viewer::getCoordinateSystemNodePath() const diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 831c97369..f02a51a3c 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -1068,6 +1068,38 @@ void CullVisitor::apply(osg::ClearNode& node) } +namespace osgUtil +{ + +class RenderStageCache : public osg::Object +{ + public: + + RenderStageCache() {} + RenderStageCache(const RenderStageCache&, const osg::CopyOp&) {} + + META_Object(osgUtil, RenderStageCache); + + void setRenderStage(CullVisitor* cv, RenderStage* rs) + { + OpenThreads::ScopedLock lock(_mutex); + _renderStageMap[cv] = rs; + } + + RenderStage* getRenderStage(osgUtil::CullVisitor* cv) + { + OpenThreads::ScopedLock lock(_mutex); + return _renderStageMap[cv].get(); + } + + typedef std::map > RenderStageMap; + + OpenThreads::Mutex _mutex; + RenderStageMap _renderStageMap; +}; + +} + void CullVisitor::apply(osg::Camera& camera) { // push the node's state. @@ -1136,12 +1168,21 @@ void CullVisitor::apply(osg::Camera& camera) // use render to texture stage. // create the render to texture stage. - osg::ref_ptr rtts = dynamic_cast(camera.getRenderingCache(contextID)); + osg::ref_ptr rsCache = dynamic_cast(camera.getRenderingCache(contextID)); + if (!rsCache) + { + rsCache = new osgUtil::RenderStageCache; + camera.setRenderingCache(contextID, rsCache.get()); + } + + osg::ref_ptr rtts = rsCache->getRenderStage(this); if (!rtts) { OpenThreads::ScopedLock lock(*(camera.getDataChangeMutex())); rtts = new osgUtil::RenderStage; + rsCache->setRenderStage(this,rtts.get()); + rtts->setCamera(&camera); if (camera.getDrawBuffer() != GL_NONE) @@ -1164,7 +1205,6 @@ void CullVisitor::apply(osg::Camera& camera) rtts->setReadBuffer(previous_stage->getReadBuffer()); } - camera.setRenderingCache(contextID, rtts.get()); } else { diff --git a/src/osgUtil/RenderBin.cpp b/src/osgUtil/RenderBin.cpp index 74a2f222a..c862d0e25 100644 --- a/src/osgUtil/RenderBin.cpp +++ b/src/osgUtil/RenderBin.cpp @@ -481,7 +481,7 @@ bool RenderBin::getStats(Statistics& stats) const ++dw_itr) { const RenderLeaf* rl = *dw_itr; - const Drawable* dw= rl->_drawable; + const Drawable* dw= rl->getDrawable(); stats.addDrawable(); // number of geosets if (rl->_modelview.get()) { @@ -506,7 +506,7 @@ bool RenderBin::getStats(Statistics& stats) const ++dw_itr) { const RenderLeaf* rl = dw_itr->get(); - const Drawable* dw= rl->_drawable; + const Drawable* dw= rl->getDrawable(); stats.addDrawable(); // number of geosets if (rl->_modelview.get()) stats.addMatrix(); // number of matrices if (dw) diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index b6181b158..8222bd898 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -20,6 +21,7 @@ using namespace osgViewer; + class ViewerQuerySupport { public: @@ -544,6 +546,8 @@ Viewer::Viewer(): _eventVisitor->setActionAdapter(this); setStats(new osg::Stats("Viewer")); + + osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2)); } Viewer::~Viewer() @@ -569,6 +573,11 @@ Viewer::~Viewer() (*citr)->close(); } + if (osg::Referenced::getDeleteHandler()) + { + osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); + osg::Referenced::getDeleteHandler()->flushAll(); + } //osg::notify(osg::NOTICE)<<"finish Viewer::~Viewer()"<setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime()); } + + if (osg::Referenced::getDeleteHandler()) + { + osg::Referenced::getDeleteHandler()->flush(); + osg::Referenced::getDeleteHandler()->setFrameNumber(_frameStamp->getFrameNumber()); + } + } void Viewer::eventTraversal()