From 4d7572965015a93c7ed56c2b164f8491e679e695 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 25 Sep 2009 18:05:54 +0000 Subject: [PATCH] Added stats collection to new Texture Pool code, and improved TexturePool implementation. The Texture Pool can be enabled by setting the env var OSG_TEXTURE_POOL_SIZE=size_in_bytes. Note, setting a size of 1 will result in the TexturePool allocating the minimum number of textures it can without having to reuse TextureObjects from within the same frame. --- include/osg/Texture | 46 +++++++ include/osg/Timer | 53 ++++++++ src/osg/Texture.cpp | 251 ++++++++++++++++++++++++++++++-------- src/osg/Texture2D.cpp | 4 + src/osgUtil/SceneView.cpp | 7 ++ 5 files changed, 307 insertions(+), 54 deletions(-) diff --git a/include/osg/Texture b/include/osg/Texture index a8af1a276..82ee5fb09 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -998,6 +998,7 @@ class OSG_EXPORT Texture : public osg::StateAttribute TextureObject* _next; Texture* _texture; bool _allocated; + unsigned int _frameLastUsed; double _timeStamp; }; @@ -1013,6 +1014,7 @@ class OSG_EXPORT Texture : public osg::StateAttribute void discardAllDeletedTextureObjects(); void flushDeletedTextureObjects(double currentTime, double& availableTime); + TextureObject* takeFromOrphans(Texture* texture); TextureObject* takeOrGenerate(Texture* texture); void moveToBack(TextureObject* to); void addToBack(TextureObject* to); @@ -1048,7 +1050,18 @@ class OSG_EXPORT Texture : public osg::StateAttribute unsigned int getContextID() const { return _contextID; } + + + void setNumberActiveTextureObjects(unsigned int size) { _numActiveTextureObjects = size; } + unsigned int& getNumberActiveTextureObjects() { return _numActiveTextureObjects; } + unsigned int getNumberActiveTextureObjects() const { return _numActiveTextureObjects; } + + void setNumberOrphanedTextureObjects(unsigned int size) { _numOrphanedTextureObjects = size; } + unsigned int& getNumberOrphanedTextureObjects() { return _numOrphanedTextureObjects; } + unsigned int getNumberOrphanedTextureObjects() const { return _numOrphanedTextureObjects; } + void setCurrTexturePoolSize(unsigned int size) { _currTexturePoolSize = size; } + unsigned int& getCurrTexturePoolSize() { return _currTexturePoolSize; } unsigned int getCurrTexturePoolSize() const { return _currTexturePoolSize; } void setMaxTexturePoolSize(unsigned int size); @@ -1072,13 +1085,46 @@ class OSG_EXPORT Texture : public osg::StateAttribute void flushDeletedTextureObjects(double currentTime, double& availableTime); void releaseTextureObject(TextureObject* to); + + void newFrame(osg::FrameStamp* fs); + void resetStats(); + void reportStats(); + + unsigned int& getFrameNumber() { return _frameNumber; } + unsigned int& getNumberFrames() { return _numFrames; } + + unsigned int& getNumberDeleted() { return _numDeleted; } + double& getDeleteTime() { return _deleteTime; } + + unsigned int& getNumberGenerated() { return _numGenerated; } + double& getGenerateTime() { return _generateTime; } + + unsigned int& getNumberApplied() { return _numApplied; } + double& getApplyTime() { return _applyTime; } + + protected: typedef std::map< TextureProfile, osg::ref_ptr > TextureSetMap; unsigned int _contextID; + unsigned int _numActiveTextureObjects; + unsigned int _numOrphanedTextureObjects; unsigned int _currTexturePoolSize; unsigned int _maxTexturePoolSize; TextureSetMap _textureSetMap; + + unsigned int _frameNumber; + + unsigned int _numFrames; + unsigned int _numDeleted; + double _deleteTime; + + unsigned int _numGenerated; + double _generateTime; + + unsigned int _numApplied; + double _applyTime; + }; static osg::ref_ptr& getTextureObjectManager(unsigned int contextID); diff --git a/include/osg/Timer b/include/osg/Timer index d5381dcae..1261cce92 100644 --- a/include/osg/Timer +++ b/include/osg/Timer @@ -74,6 +74,59 @@ class OSG_EXPORT Timer { Timer_t _startTick; double _secsPerTick; +}; + +/** Helper class for timing sections of code. */ +class ElapsedTime +{ + public: + inline ElapsedTime(double* elapsedTime, osg::Timer* timer = 0): + _time(elapsedTime) + { + init(timer); + } + + inline ElapsedTime(osg::Timer* timer = 0): + _time(0) + { + init(timer); + } + + inline ~ElapsedTime() + { + finish(); + } + + inline void reset() + { + _startTick = _timer->tick(); + } + + inline double elapsedTime() const + { + return _timer->delta_s(_startTick, _timer->tick()); + } + + inline void finish() + { + Timer_t endTick = _timer->tick(); + if (_time) *_time += _timer->delta_s(_startTick, endTick); + _startTick = endTick; + } + + protected: + + inline void init(osg::Timer* timer) + { + if (timer) _timer = timer; + else _timer = osg::Timer::instance(); + + _startTick = _timer->tick(); + } + + double* _time; + Timer* _timer; + Timer_t _startTick; }; diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index 6c746e19e..b517c0f1c 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -1,4 +1,4 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield +/* -*-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 @@ -108,7 +108,7 @@ Texture::TextureObjectSet::~TextureObjectSet() bool Texture::TextureObjectSet::checkConsistency() const { - // return true; + return true; // osg::notify(osg::NOTICE)<<"TextureObjectSet::checkConsistency()"<getNumberOrphanedTextureObjects() += numOrphaned; + _parent->getNumberActiveTextureObjects() -= numOrphaned; + _pendingOrphanedTextureObjects.clear(); checkConsistency(); @@ -213,24 +220,36 @@ void Texture::TextureObjectSet::flushAllDeletedTextureObjects() GLuint id = (*itr)->id(); - osg::notify(osg::NOTICE)<<"Deleting textureobject id="<getNumberOrphanedTextureObjects()<=s_minimumNumberOfTextureObjectsToRetainInCache) return; + + unsigned int numDeleted = 0; + unsigned int maxNumObjectsToDelete = _parent->getNumberOrphanedTextureObjects()-s_minimumNumberOfTextureObjectsToRetainInCache; + if (maxNumObjectsToDelete>4) maxNumObjectsToDelete = 4; + + ElapsedTime timer; + + TextureObjectList::iterator itr = _orphanedTextureObjects.begin(); + for(; + itr != _orphanedTextureObjects.end() && timer.elapsedTime()id(); + + // osg::notify(osg::NOTICE)<<"Deleting textureobject id="<setTexture(texture); return to.release(); - } - // // no TextureObjects available to recyle so have to create one from scratch // @@ -327,11 +403,12 @@ Texture::TextureObject* Texture::TextureObjectSet::takeOrGenerate(Texture* textu ++_numOfTextureObjects; // update the current texture pool size - _parent->setCurrTexturePoolSize( _parent->getCurrTexturePoolSize() + _profile._size ); + _parent->getCurrTexturePoolSize() += _profile._size; + _parent->getNumberActiveTextureObjects() += 1; addToBack(to); - osg::notify(osg::NOTICE)<<"Created new TextureObject, _numOfTextureObjects "<<_numOfTextureObjects<_next = "<_next<_frameLastUsed = _parent->getFrameNumber(); + // nothing to do if we are already tail if (to==_tail) return; @@ -412,6 +491,8 @@ void Texture::TextureObjectSet::addToBack(Texture::TextureObject* to) } else { + to->_frameLastUsed = _parent->getFrameNumber(); + if (_tail) _tail->_next = to; to->_previous = _tail; @@ -451,8 +532,18 @@ void Texture::TextureObjectSet::orphan(Texture::TextureObject* to) Texture::TextureObjectManager::TextureObjectManager(unsigned int contextID): _contextID(contextID), + _numActiveTextureObjects(0), + _numOrphanedTextureObjects(0), _currTexturePoolSize(0), - _maxTexturePoolSize(0) + _maxTexturePoolSize(0), + _frameNumber(0), + _numFrames(0), + _numDeleted(0), + _deleteTime(0.0), + _numGenerated(0), + _generateTime(0.0), + _numApplied(0), + _applyTime(0.0) { } @@ -495,6 +586,9 @@ Texture::TextureObject* Texture::TextureObjectManager::generateTextureObject(con GLsizei depth, GLint border) { + ElapsedTime elapsedTime(&(getGenerateTime())); + ++getNumberGenerated(); + Texture::TextureProfile profile(target,numMipmapLevels,internalFormat,width,height,depth,border); osg::ref_ptr& tos = _textureSetMap[profile]; if (!tos) tos = new Texture::TextureObjectSet(this, profile); @@ -513,7 +607,7 @@ void Texture::TextureObjectManager::handlePendingOrphandedTextureObjects() void Texture::TextureObjectManager::flushAllDeletedTextureObjects() { - return; + ElapsedTime elapsedTime(&(getDeleteTime())); for(TextureSetMap::iterator itr = _textureSetMap.begin(); itr != _textureSetMap.end(); @@ -535,6 +629,8 @@ void Texture::TextureObjectManager::discardAllDeletedTextureObjects() void Texture::TextureObjectManager::flushDeletedTextureObjects(double currentTime, double& availableTime) { + ElapsedTime elapsedTime(&(getDeleteTime())); + for(TextureSetMap::iterator itr = _textureSetMap.begin(); (itr != _textureSetMap.end()) && (availableTime > 0.0); ++itr) @@ -550,6 +646,39 @@ void Texture::TextureObjectManager::releaseTextureObject(Texture::TextureObject* } +void Texture::TextureObjectManager::newFrame(osg::FrameStamp* fs) +{ + if (fs) _frameNumber = fs->getFrameNumber(); + else ++_frameNumber; + + ++_numFrames; +} + +void Texture::TextureObjectManager::reportStats() +{ + double numFrames(_numFrames==0 ? 1.0 : _numFrames); + osg::notify(osg::NOTICE)<<"TextureObjectMananger::reportStats()"<& Texture::getTextureObjectManager(unsigned int contextID) { typedef osg::buffered_object< ref_ptr > TextureObjectManagerBuffer; @@ -681,8 +810,12 @@ unsigned int Texture::s_numberDeletedTextureInLastFrame = 0; static ref_ptr s_textureObjectManager = new OriginalTextureObjectManager; -Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int /*contextID*/,GLenum target) +Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID,GLenum target) { + Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID); + ElapsedTime elapsedTime(&(tom->getGenerateTime())); + tom->getNumberGenerated()++; + GLuint id; glGenTextures( 1L, &id ); @@ -691,7 +824,7 @@ Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Text static int s_number = 0; -Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int /*contextID*/, +Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID, GLenum target, GLint numMipmapLevels, GLenum internalFormat, @@ -700,6 +833,10 @@ Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Text GLsizei depth, GLint border) { + Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID); + ElapsedTime elapsedTime(&(tom->getGenerateTime())); + tom->getNumberGenerated()++; + ++s_number; ++Texture::s_numberNewTextureInLastFrame; // notify(NOTICE)<<"creating new texture object "<getGenerateTime())); + tom->getNumberGenerated()++; + OpenThreads::ScopedLock lock(_mutex); Texture::TextureObjectList& tol = _textureObjectListMap[contextID]; @@ -748,6 +889,9 @@ Texture::TextureObject* OriginalTextureObjectManager::reuseTextureObject(Texture void OriginalTextureObjectManager::flushAllTextureObjects(unsigned int contextID) { + Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID); + ElapsedTime elapsedTime(&(tom->getDeleteTime())); + OpenThreads::ScopedLock lock(_mutex); Texture::TextureObjectList& tol = _textureObjectListMap[contextID]; @@ -761,6 +905,8 @@ void OriginalTextureObjectManager::flushAllTextureObjects(unsigned int contextID // osg::notify(osg::NOTICE)<<" deleting texture object "<<(*itr)->_id<id(); glDeleteTextures( 1L, &id); + + tom->getNumberDeleted()++; } tol.clear(); } @@ -775,18 +921,17 @@ void OriginalTextureObjectManager::discardAllTextureObjects(unsigned int context void OriginalTextureObjectManager::flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime) { + // if no time available don't try to flush objects. if (availableTime<=0.0) return; + Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID); + ElapsedTime timer(&(tom->getDeleteTime())); + unsigned int numObjectsDeleted = 0; unsigned int maxNumObjectsToDelete = 4; - const osg::Timer& timer = *osg::Timer::instance(); - osg::Timer_t start_tick = timer.tick(); - double elapsedTime = 0.0; - - unsigned int numTexturesDeleted = 0; - { + { OpenThreads::ScopedLock lock(_mutex); Texture::TextureObjectList& tol = _textureObjectListMap[contextID]; @@ -803,7 +948,7 @@ void OriginalTextureObjectManager::flushTextureObjects(unsigned int contextID,do double expiryTime = currentTime-_expiryDelay; for(itr=tol.begin(); - itr!=tol.end() && elapsedTimes_minimumNumberOfTextureObjectsToRetainInCache && numObjectsDeleteds_minimumNumberOfTextureObjectsToRetainInCache && numObjectsDeletedgetTimeStamp()<=expiryTime) @@ -814,20 +959,18 @@ void OriginalTextureObjectManager::flushTextureObjects(unsigned int contextID,do GLuint id = (*itr)->id(); glDeleteTextures( 1L, &id); itr = tol.erase(itr); - ++numTexturesDeleted; ++numObjectsDeleted; } else { ++itr; } - elapsedTime = timer.delta_s(start_tick,timer.tick()); } } - elapsedTime = timer.delta_s(start_tick,timer.tick()); - // if (numTexturesDeleted) notify(osg::NOTICE)<<"Number of Texture's deleted = "<getNumberDeleted()+=numObjectsDeleted; - availableTime -= elapsedTime; + availableTime -= timer.elapsedTime(); } diff --git a/src/osg/Texture2D.cpp b/src/osg/Texture2D.cpp index cbd9ea4f4..04ed018b2 100644 --- a/src/osg/Texture2D.cpp +++ b/src/osg/Texture2D.cpp @@ -137,6 +137,10 @@ void Texture2D::apply(State& state) const // current OpenGL context. const unsigned int contextID = state.getContextID(); + Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID); + ElapsedTime elapsedTime(&(tom->getApplyTime())); + tom->getNumberApplied()++; + // get the texture object for the current contextID. TextureObject* textureObject = getTextureObject(contextID); diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index 04790a3d9..c8f5f3d23 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -1022,6 +1022,9 @@ void SceneView::draw() osg::State* state = _renderInfo.getState(); state->initializeExtensionProcs(); + osg::Texture::TextureObjectManager* tom = osg::Texture::getTextureObjectManager(state->getContextID()); + tom->newFrame(state->getFrameStamp()); + if (!_initCalled) init(); // note, to support multi-pipe systems the deletion of OpenGL display list @@ -1560,6 +1563,10 @@ void SceneView::draw() } } +#ifdef REPORT_TEXTURE_MANAGER_STATS + tom->reportStats(); +#endif + // osg::notify(osg::NOTICE)<<"SceneView draw() DynamicObjectCount"<getDynamicObjectCount()<