From Tim More, "This submission tries to optimize redundant compilation of StateSets and Drawables

in the DatabasePager. The practical effects of these are to greatly reduce startup time
and the time to load an individual scenery tile in FlightGear.

- From my log message:

   Minimize the number of StateSets and drawables that are compiled by checking
   if they have already been compiled or will be elminated by the
   SharedStateManager.

   Move the sorting of the dataToCompile queue out of compileGLObjects
   into the man pager run function.

   Change the SharedStateManager to use maps instead of vectors."
This commit is contained in:
Robert Osfield
2007-12-11 12:32:31 +00:00
parent 42723fec8f
commit 640999dea6
4 changed files with 377 additions and 137 deletions

View File

@@ -31,6 +31,8 @@
#include <map>
#include <list>
#include <algorithm>
#include <functional>
namespace osgDB {
@@ -275,7 +277,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
friend struct DatabaseRequest;
struct DatabaseRequest : public osg::Referenced
{
DatabaseRequest():
@@ -294,8 +296,13 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
osg::ref_ptr<osg::Node> _loadedModel;
DataToCompileMap _dataToCompileMap;
osg::ref_ptr<ReaderWriter::Options> _loadOptions;
bool isRequestCurrent (int frameNumber) const
{
return frameNumber - _frameNumberLastRequest <= 1;
}
};
typedef std::vector< osg::ref_ptr<DatabaseRequest> > DatabaseRequestList;
typedef std::vector< osg::ref_ptr<osg::Object> > ObjectList;
@@ -321,8 +328,86 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
_databasePagerThreadBlock->set(
(!_fileRequestList.empty() || !_childrenToDeleteList.empty()) && !_databasePagerThreadPaused);
}
// Helper functions for determining if objects need to be
// compiled.
inline static bool isCompiled(const osg::Texture* texture,
unsigned int contextID)
{
return texture->getTextureObject(contextID);
}
// Is texture compiled for all active contexts?
inline bool isCompiled(osg::Texture* texture) const
{
using namespace std;
return (count_if(_activeGraphicsContexts.begin(),
_activeGraphicsContexts.end(),
bind1st(mem_fun(&osg::Texture::getTextureObject),
texture))
== _activeGraphicsContexts.size());
}
inline static bool isCompiled(const osg::StateSet* stateSet,
unsigned int contextID)
{
for (unsigned i = 0;
i < stateSet->getTextureAttributeList().size();
++i)
{
const osg::Texture* texture
= dynamic_cast<const osg::Texture*>(stateSet->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
if (texture && !isCompiled(texture, contextID))
return false;
}
return true;
}
inline bool isCompiled(osg::StateSet* stateSet)
{
using namespace std;
for (unsigned i = 0;
i < stateSet->getTextureAttributeList().size();
++i)
{
osg::Texture* texture
= dynamic_cast<osg::Texture*>(stateSet->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
if (texture
&& (count_if(_activeGraphicsContexts.begin(),
_activeGraphicsContexts.end(),
bind1st(mem_fun(&osg::Texture::getTextureObject),
texture))
!= _activeGraphicsContexts.size()))
return false;
}
return true;
}
inline static bool isCompiled(const osg::Drawable* drawable,
unsigned int contextID)
{
// Worry about vbos later
if (drawable->getUseDisplayList())
{
return drawable->getDisplayList(contextID) != 0;
}
return true;
}
inline bool isCompiled(const osg::Drawable* drawable) const
{
using namespace std;
if (drawable->getUseDisplayList())
{
return (count_if(_activeGraphicsContexts.begin(),
_activeGraphicsContexts.end(),
bind1st(mem_fun(&osg::Drawable::getDisplayList),
drawable))
== _activeGraphicsContexts.size());
}
return true;
}
/** 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. */

View File

@@ -42,8 +42,8 @@ namespace osgDB {
SharedStateManager();
void setShareMode(unsigned int mode) { shareMode = mode; }
unsigned int getShareMode() { return shareMode; }
void setShareMode(unsigned int mode) { _shareMode = mode; }
unsigned int getShareMode() { return _shareMode; }
// Call right after each unload and before Registry cache prune.
void prune();
@@ -53,7 +53,10 @@ 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);
protected:
void process(osg::StateSet* ss, osg::Object* parent);
@@ -62,24 +65,46 @@ namespace osgDB {
void setStateSet(osg::StateSet* ss, osg::Object* object);
void shareTextures(osg::StateSet* ss);
struct CompareStateAttributes
{
bool operator()(const osg::ref_ptr<osg::StateAttribute>& lhs,
const osg::ref_ptr<osg::StateAttribute>& rhs)
{
return *lhs < *rhs;
}
};
struct CompareStateSets
{
bool operator()(const osg::ref_ptr<osg::StateSet>& lhs,
const osg::ref_ptr<osg::StateSet>& rhs)
{
return lhs->compare(*rhs, true) < 0;
}
};
// Lists of shared objects
typedef std::set< osg::ref_ptr<osg::StateAttribute> > TextureSet;
typedef std::set< osg::ref_ptr<osg::StateAttribute>, CompareStateAttributes > TextureSet;
TextureSet _sharedTextureList;
typedef std::set< osg::ref_ptr<osg::StateSet> > StateSetSet;
typedef std::set< osg::ref_ptr<osg::StateSet>, CompareStateSets > StateSetSet;
StateSetSet _sharedStateSetList;
// Temporary lists just to avoid unnecessary find calls
typedef std::pair<osg::StateAttribute*, bool> TextureSharePair;
typedef std::map<osg::StateAttribute*, TextureSharePair> TextureTextureSharePairMap;
TextureTextureSharePairMap tmpSharedTextureList;
typedef std::pair<osg::StateSet*, bool> StateSetSharePair;
typedef std::map<osg::StateSet*, StateSetSharePair> StateSetStateSetSharePairMap;
StateSetStateSetSharePairMap tmpSharedStateSetList;
// Share connection mutex
unsigned int shareMode;
unsigned int _shareMode;
OpenThreads::Mutex *mutex;
OpenThreads::Mutex *_mutex;
// Mutex for doing isShared queries from other threads
mutable OpenThreads::Mutex _listMutex;
};
}

View File

@@ -10,6 +10,8 @@
#include <OpenThreads/ScopedLock>
#include <algorithm>
#include <functional>
#include <set>
#ifdef WIN32
#include <windows.h>
@@ -28,6 +30,57 @@ static osg::ApplicationUsageProxy DatabasePager_e4(osg::ApplicationUsage::ENVIRO
static osg::ApplicationUsageProxy DatabasePager_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_CHILDREN_TO_REMOVE_PER_FRAME <int>", "Set the maximum number of PagedLOD child to remove per frame.");
static osg::ApplicationUsageProxy DatabasePager_e6(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DATABASE_PAGER_MINIMUM_INACTIVE_PAGEDLOD <int>", "Set the minimum number of inactive PagedLOD child to keep.");
// Convert function objects that take pointer args into functions that a
// reference to an osg::ref_ptr. This is quite useful for doing STL
// operations on lists of ref_ptr. This code assumes that a function
// with an argument const Foo* should be composed into a function of
// argument type ref_ptr<Foo>&, not ref_ptr<const Foo>&. Some support
// for that should be added to make this more general.
namespace
{
template <typename U>
struct PointerTraits
{
typedef class NullType {} PointeeType;
};
template <typename U>
struct PointerTraits<U*>
{
typedef U PointeeType;
};
template <typename U>
struct PointerTraits<const U*>
{
typedef U PointeeType;
};
template <typename FuncObj>
class RefPtrAdapter
: public std::unary_function<const osg::ref_ptr<typename PointerTraits<typename FuncObj::argument_type>::PointeeType>,
typename FuncObj::result_type>
{
public:
typedef typename PointerTraits<typename FuncObj::argument_type>::PointeeType PointeeType;
typedef osg::ref_ptr<PointeeType> RefPtrType;
explicit RefPtrAdapter(const FuncObj& funcObj) : _func(funcObj) {}
typename FuncObj::result_type operator()(const RefPtrType& refPtr) const
{
return _func(refPtr.get());
}
protected:
FuncObj _func;
};
template <typename FuncObj>
RefPtrAdapter<FuncObj> refPtrAdapt(const FuncObj& func)
{
return RefPtrAdapter<FuncObj>(func);
}
}
DatabasePager::DatabasePager()
{
//osg::notify(osg::INFO)<<"Constructing DatabasePager()"<<std::endl;
@@ -416,12 +469,13 @@ public:
FindCompileableGLObjectsVisitor(DatabasePager::DataToCompile& dataToCompile,
bool changeAutoUnRef, bool valueAutoUnRef,
bool changeAnisotropy, float valueAnisotropy,
DatabasePager::DrawablePolicy drawablePolicy):
DatabasePager::DrawablePolicy drawablePolicy,
const DatabasePager* pager):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_dataToCompile(dataToCompile),
_changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
_changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy),
_drawablePolicy(drawablePolicy)
_drawablePolicy(drawablePolicy), _pager(pager)
{
}
@@ -448,30 +502,55 @@ public:
{
if (stateset)
{
// search for the existence of any texture object attributes
bool foundTextureState = false;
// search for the existance of any texture object
// attributes
// 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;i<stateset->getTextureAttributeList().size();++i)
{
osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
if (texture)
// Has this texture already been encountered?
if (texture && !_textureSet.count(texture))
{
_textureSet.insert(texture);
if (_changeAutoUnRef) texture->setUnRefImageDataAfterApply(_valueAutoUnRef);
if (_changeAnisotropy) texture->setMaxAnisotropy(_valueAnisotropy);
foundTextureState = true;
if ((_changeAnisotropy
&& texture->getMaxAnisotropy() != _valueAnisotropy))
{
if (_changeAnisotropy)
texture->setMaxAnisotropy(_valueAnisotropy);
}
if (!_pager->isCompiled(texture))
{
compileStateSet = true;
if (osg::getNotifyLevel() >= osg::DEBUG_INFO)
{
osg::notify(osg::DEBUG_INFO)
<<"Found compilable texture " << texture << " ";
osg::Image* image = texture->getImage(0);
if (image) osg::notify(osg::DEBUG_INFO) << image->getFileName();
osg::notify(osg::DEBUG_INFO) << std:: endl;
}
break;
}
}
}
// if texture object attributes exist add the state to the list for later compilation.
if (foundTextureState)
if (compileStateSet)
{
//osg::notify(osg::DEBUG_INFO)<<"Found compilable texture state"<<std::endl;
_dataToCompile.first.insert(stateset);
}
}
}
inline void apply(osg::Drawable* drawable)
{
if (_drawableSet.count(drawable))
return;
apply(drawable->getStateSet());
switch(_drawablePolicy)
@@ -495,8 +574,12 @@ public:
// osg::notify(osg::NOTICE)<<"USE_VERTEX_ARRAYS"<<std::endl;
break;
}
if (drawable->getUseDisplayList() || drawable->getUseVertexBufferObjects())
// Don't compile if already compiled. This can happen if the
// subgraph is shared with already-loaded nodes.
//
// XXX This "compiles" VBOs too, but compilation doesn't do
// anything for VBOs, does it?
if (drawable->getUseDisplayList() && _pager->isCompiled(drawable))
{
// osg::notify(osg::NOTICE)<<" Found compilable drawable"<<std::endl;
_dataToCompile.second.push_back(drawable);
@@ -509,6 +592,9 @@ public:
bool _changeAnisotropy;
float _valueAnisotropy;
DatabasePager::DrawablePolicy _drawablePolicy;
const DatabasePager* _pager;
std::set<osg::ref_ptr<osg::Texture> > _textureSet;
std::set<osg::ref_ptr<osg::Drawable> > _drawableSet;
};
@@ -631,7 +717,7 @@ void DatabasePager::run()
FindCompileableGLObjectsVisitor frov(dtc,
_changeAutoUnRef, _valueAutoUnRef,
_changeAnisotropy, _valueAnisotropy,
_drawablePolicy);
_drawablePolicy, this);
databaseRequest->_loadedModel->accept(frov);
@@ -676,33 +762,51 @@ void DatabasePager::run()
updateDatabasePagerThreadBlock();
}
// Prepare and prune the to-be-compiled list here in
// the pager thread rather than in the draw or
// graphics context thread(s).
if (loadedObjectsNeedToBeCompiled)
{
for(ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin();
itr != _activeGraphicsContexts.end();
++itr)
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
sort(_dataToCompileList.begin(),
_dataToCompileList.end(), SortFileRequestFunctor());
// Prune all the old entries.
DatabaseRequestList::iterator tooOld
= find_if(_dataToCompileList.begin(),
_dataToCompileList.end(),
refPtrAdapt(std::not1(std::bind2nd(std::mem_fun(&DatabaseRequest
::isRequestCurrent),
_frameNumber))));
// This is the database thread, so just delete
_dataToCompileList.erase(tooOld, _dataToCompileList.end());
if (!_dataToCompileList.empty())
{
osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr);
if (gc)
{
osg::GraphicsThread* gt = gc->getGraphicsThread();
if (gt)
{
gt->add(new DatabasePager::CompileOperation(this));
}
else
{
gc->makeCurrent();
for(ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin();
itr != _activeGraphicsContexts.end();
++itr)
{
osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr);
if (gc)
{
osg::GraphicsThread* gt = gc->getGraphicsThread();
if (gt)
{
gt->add(new DatabasePager::CompileOperation(this));
}
else
{
gc->makeCurrent();
compileAllGLObjects(*(gc->getState()));
compileAllGLObjects(*(gc->getState()));
gc->releaseContext();
gc->releaseContext();
}
}
}
}
// osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<<std::endl;
// osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<<std::endl;
}
}
}
@@ -1028,6 +1132,8 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
bool compileAll = (availableTime==DBL_MAX);
SharedStateManager *sharedManager
= Registry::instance()->getSharedStateManager();
osg::RenderInfo renderInfo;
renderInfo.setState(&state);
@@ -1045,40 +1151,9 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
// get the first compilable entry.
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
if (!_dataToCompileList.empty())
{
std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor());
// prune all the old entries.
DatabaseRequestList::iterator litr;
int i=0;
for(litr = _dataToCompileList.begin();
(litr != _dataToCompileList.end()) && (_frameNumber-(*litr)->_frameNumberLastRequest)<=1;
++litr,i++)
{
//osg::notify(osg::NOTICE)<<"Compile "<<_frameNumber-(*litr)->_frameNumberLastRequest<<std::endl;
}
if (litr != _dataToCompileList.end())
{
if (_deleteRemovedSubgraphsInDatabaseThread)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex);
for(DatabaseRequestList::iterator ditr=litr;
ditr!=_dataToCompileList.end();
++ditr)
{
_childrenToDeleteList.push_back((*ditr)->_loadedModel.get());
}
}
//osg::notify(osg::NOTICE)<<"Pruning "<<_dataToCompileList.size()-i<<std::endl;
_dataToCompileList.erase(litr,_dataToCompileList.end());
}
// advance to the next entry to compile if one is available.
databaseRequest = _dataToCompileList.empty() ? 0 : _dataToCompileList.front();
}
// advance to the next entry to compile if one is available.
databaseRequest = _dataToCompileList.empty() ? 0 : _dataToCompileList.front();
};
unsigned int numObjectsCompiled = 0;
@@ -1098,12 +1173,18 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
StateSetList& sslist = dtc.first;
//osg::notify(osg::INFO)<<"Compiling statesets"<<std::endl;
StateSetList::iterator itr=sslist.begin();
unsigned int objTemp = numObjectsCompiled;
for(;
itr!=sslist.end() && (elapsedTime+estimatedTextureDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame;
++itr)
{
//osg::notify(osg::INFO)<<" Compiling stateset "<<(*itr).get()<<std::endl;
if (isCompiled(itr->get(), state.getContextID())
|| (sharedManager && sharedManager->isShared(itr->get())))
{
elapsedTime = timer.delta_s(start_tick,timer.tick());
continue;
}
double startCompileTime = timer.delta_s(start_tick,timer.tick());
(*itr)->compileGLObjects(state);
@@ -1119,7 +1200,12 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
++numObjectsCompiled;
}
// remove the compiled stateset from the list.
if (osg::getNotifyLevel() >= osg::DEBUG_INFO
&& numObjectsCompiled > objTemp)
osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
<< numObjectsCompiled - objTemp
<< " StateSets" << std::endl;
// remove the compiled statesets from the list.
sslist.erase(sslist.begin(),itr);
}
@@ -1129,11 +1215,17 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
//osg::notify(osg::INFO)<<"Compiling drawables"<<std::endl;
DrawableList& dwlist = dtc.second;
DrawableList::iterator itr=dwlist.begin();
unsigned int objTemp = numObjectsCompiled;
for(;
itr!=dwlist.end() && (compileAll || ((elapsedTime+estimatedDrawableDuration)<availableTime && numObjectsCompiled<_maximumNumOfObjectsToCompilePerFrame));
++itr)
{
//osg::notify(osg::INFO)<<" Compiling drawable "<<(*itr).get()<<std::endl;
if (isCompiled(itr->get(), state.getContextID()))
{
elapsedTime = timer.delta_s(start_tick,timer.tick());
continue;
}
double startCompileTime = timer.delta_s(start_tick,timer.tick());
(*itr)->compileGLObjects(renderInfo);
elapsedTime = timer.delta_s(start_tick,timer.tick());
@@ -1144,6 +1236,11 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
++numObjectsCompiled;
}
if (osg::getNotifyLevel() >= osg::DEBUG_INFO
&& numObjectsCompiled > objTemp)
osg::notify(osg::DEBUG_INFO)<< _frameNumber << " compiled "
<< numObjectsCompiled - objTemp
<< " Drawables" << std::endl;
// remove the compiled drawables from the list.
dwlist.erase(dwlist.begin(),itr);
}
@@ -1151,7 +1248,9 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
//osg::notify(osg::INFO)<<"Checking if compiled"<<std::endl;
// now check the to compile entries for all active graphics contexts
// to make sure that all have been compiled.
// to make sure that all have been compiled. They won't be
// if we ran out of time or if another thread is still
// compiling for its graphics context.
bool allCompiled = true;
for(DataToCompileMap::iterator itr=dcm.begin();
itr!=dcm.end() && allCompiled;
@@ -1161,27 +1260,39 @@ void DatabasePager::compileGLObjects(osg::State& state, double& availableTime)
if (!(itr->second.second.empty())) allCompiled=false;
}
//if (numObjectsCompiled > 0)
//osg::notify(osg::NOTICE)<< _frameNumber << "compiled " << numObjectsCompiled << " objects" << std::endl;
if (allCompiled)
{
// we've compile all of the current databaseRequest so we can now pop it off the
// we've compiled all of the current databaseRequest so we can now pop it off the
// to compile list and place it on the merge list.
// osg::notify(osg::NOTICE)<<"All compiled"<<std::endl;
// to compile list and place it on the merge list.
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex);
// The request might have been removed from the
// _dataToCompile list by another graphics thread, in
// which case it's already on the merge list, or by
// the pager, which means that the request has
// expired. Also, the compile list might have been
// shuffled by the pager, so the current request is
// not guaranteed to still be at the beginning of the
// list.
DatabaseRequestList::iterator requestIter
= find(_dataToCompileList.begin(), _dataToCompileList.end(),
databaseRequest);
if (requestIter != _dataToCompileList.end())
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
_dataToMergeList.push_back(databaseRequest);
}
if (!_dataToCompileList.empty()) _dataToCompileList.erase(_dataToCompileList.begin());
if (!_dataToCompileList.empty())
{
std::sort(_dataToCompileList.begin(),_dataToCompileList.end(),SortFileRequestFunctor());
databaseRequest = _dataToCompileList.front();
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex);
_dataToMergeList.push_back(databaseRequest);
}
_dataToCompileList.erase(requestIter);
}
if (!_dataToCompileList.empty()) databaseRequest = _dataToCompileList.front();
else databaseRequest = 0;
}

View File

@@ -19,9 +19,9 @@ using namespace osgDB;
SharedStateManager::SharedStateManager():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
shareMode = SHARE_TEXTURES;
//shareMode = SHARE_STATESETS;
mutex=0;
_shareMode = SHARE_TEXTURES;
//_shareMode = SHARE_STATESETS;
_mutex=0;
}
//----------------------------------------------------------------
@@ -29,18 +29,23 @@ SharedStateManager::SharedStateManager():
//----------------------------------------------------------------
void SharedStateManager::prune()
{
StateSetSet::iterator sitr, sitr1;
for(sitr=_sharedStateSetList.begin(); sitr!=_sharedStateSetList.end(); sitr=sitr1)
StateSetSet::iterator sitr;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_listMutex);
for(sitr=_sharedStateSetList.begin(); sitr!=_sharedStateSetList.end();)
{
sitr1=sitr; ++sitr1;
if((*sitr)->referenceCount()<=1) _sharedStateSetList.erase(sitr);
if ((*sitr)->referenceCount()<=1)
_sharedStateSetList.erase(sitr++);
else
++sitr;
}
TextureSet::iterator titr, titr1;
for(titr=_sharedTextureList.begin(); titr!=_sharedTextureList.end(); titr=titr1)
TextureSet::iterator titr;
for(titr=_sharedTextureList.begin(); titr!=_sharedTextureList.end();)
{
titr1=titr; ++titr1;
if((*titr)->referenceCount()<=1) _sharedTextureList.erase(titr);
if ((*titr)->referenceCount()<=1)
_sharedTextureList.erase(titr++);
else
++titr;
}
}
@@ -54,11 +59,11 @@ void SharedStateManager::share(osg::Node *node, OpenThreads::Mutex *mt)
// const osg::Timer& timer = *osg::Timer::instance();
// osg::Timer_t start_tick = timer.tick();
mutex = mt;
_mutex = mt;
apply(*node);
tmpSharedTextureList.clear();
tmpSharedStateSetList.clear();
mutex = 0;
_mutex = 0;
// osg::Timer_t end_tick = timer.tick();
// std::cout << "SHARING TIME = "<<timer.delta_m(start_tick,end_tick)<<"ms"<<std::endl;
@@ -91,31 +96,40 @@ void SharedStateManager::apply(osg::Geode& geode)
}
}
bool SharedStateManager::isShared(osg::StateSet *ss)
{
if ((_shareMode & SHARE_STATESETS) != 0)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_listMutex);
return find(ss) != 0;
}
else
return false;
}
//----------------------------------------------------------------
// SharedStateManager::find
//----------------------------------------------------------------
//
// The find methods don't need to lock _listMutex because the thread
// from which they are called is doing the writing to the lists.
osg::StateSet *SharedStateManager::find(osg::StateSet *ss)
{
for(StateSetSet::iterator itr=_sharedStateSetList.begin();
itr!=_sharedStateSetList.end();
++itr)
{
if(ss->compare(*(itr->get()),true)==0)
return (osg::StateSet *)itr->get();
}
return NULL;
StateSetSet::iterator result
= _sharedStateSetList.find(osg::ref_ptr<osg::StateSet>(ss));
if (result == _sharedStateSetList.end())
return NULL;
else
return result->get();
}
osg::StateAttribute *SharedStateManager::find(osg::StateAttribute *sa)
{
for(TextureSet::iterator itr=_sharedTextureList.begin();
itr!=_sharedTextureList.end();
++itr)
{
if(sa->compare(*(itr->get()))==0)
return (osg::StateAttribute *)itr->get();
}
return NULL;
TextureSet::iterator result
= _sharedTextureList.find(osg::ref_ptr<osg::StateAttribute>(sa));
if (result == _sharedTextureList.end())
return NULL;
else
return result->get();
}
@@ -163,15 +177,17 @@ void SharedStateManager::shareTextures(osg::StateSet* ss)
{
// Texture is in sharedAttributeList:
// Share now. Required to be shared all next times
if(mutex) mutex->lock();
if(_mutex) _mutex->lock();
ss->setTextureAttributeAndModes(unit, textureFromSharedList, osg::StateAttribute::ON);
if(mutex) mutex->unlock();
if(_mutex) _mutex->unlock();
tmpSharedTextureList[texture] = TextureSharePair(textureFromSharedList, true);
}
else
{
// Texture is not in _sharedAttributeList:
// Add to _sharedAttributeList. Not needed to be shared all next times.
// Add to _sharedAttributeList. Not needed to be
// shared all next times.
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_listMutex);
_sharedTextureList.insert(texture);
tmpSharedTextureList[texture] = TextureSharePair(texture, false);
}
@@ -180,9 +196,9 @@ void SharedStateManager::shareTextures(osg::StateSet* ss)
{
// Texture is in tmpSharedAttributeList and share flag is on:
// It should be shared
if(mutex) mutex->lock();
if(_mutex) _mutex->lock();
ss->setTextureAttributeAndModes(unit, titr->second.first, osg::StateAttribute::ON);
if(mutex) mutex->unlock();
if(_mutex) _mutex->unlock();
}
}
}
@@ -194,7 +210,7 @@ void SharedStateManager::shareTextures(osg::StateSet* ss)
//----------------------------------------------------------------
void SharedStateManager::process(osg::StateSet* ss, osg::Object* parent)
{
if(shareMode & SHARE_STATESETS)
if(_shareMode & SHARE_STATESETS)
{
// Valid StateSet to be shared
if(ss->getDataVariance()==osg::Object::STATIC)
@@ -209,20 +225,23 @@ void SharedStateManager::process(osg::StateSet* ss, osg::Object* parent)
{
// StateSet is in sharedStateSetList:
// Share now. Required to be shared all next times
if(mutex) mutex->lock();
if(_mutex) _mutex->lock();
setStateSet(ssFromSharedList, parent);
if(mutex) mutex->unlock();
if(_mutex) _mutex->unlock();
tmpSharedStateSetList[ss] = StateSetSharePair(ssFromSharedList, true);
}
else
{
// StateSet is not in sharedStateSetList:
// Add to sharedStateSetList. Not needed to be shared all next times.
_sharedStateSetList.insert(ss);
tmpSharedStateSetList[ss] = StateSetSharePair(ss, false);
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_listMutex);
_sharedStateSetList.insert(ss);
tmpSharedStateSetList[ss]
= StateSetSharePair(ss, false);
}
// Only in this case sharing textures is also required
if(shareMode & SHARE_TEXTURES)
if(_shareMode & SHARE_TEXTURES)
{
shareTextures(ss);
}
@@ -232,14 +251,14 @@ void SharedStateManager::process(osg::StateSet* ss, osg::Object* parent)
{
// StateSet is in tmpSharedStateSetList and share flag is on:
// It should be shared
if(mutex) mutex->lock();
if(_mutex) _mutex->lock();
setStateSet(sitr->second.first, parent);
if(mutex) mutex->unlock();
if(_mutex) _mutex->unlock();
}
}
}
else if(shareMode & SHARE_TEXTURES)
else if(_shareMode & SHARE_TEXTURES)
{
shareTextures(ss);
}