Added automatically removal from the OjbectCache when a object or it's subgraph contain Texture that no longer have an osg::Image.

This commit is contained in:
Robert Osfield 2019-12-16 16:51:16 +00:00
parent 994b066329
commit 9ae47b921b

View File

@ -11,6 +11,7 @@
* OpenSceneGraph Public License for more details.
*/
#include <osg/Texture>
#include <osgDB/ObjectCache>
#include <osgDB/Options>
@ -188,15 +189,95 @@ void ObjectCache::clear()
_objectCache.clear();
}
namespace ObjectCacheUtils
{
struct ContainsUnreffedTextures : public osg::NodeVisitor
{
ContainsUnreffedTextures() :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
foundUnreffedTexture(false)
{}
bool foundUnreffedTexture;
bool check(const osg::Texture* texture)
{
if (!texture) return false;
unsigned int numImages = 0;
for(unsigned int i=0; i<texture->getNumImages(); ++i)
{
if (texture->getImage(i)) ++numImages;
}
return numImages==0;
}
bool check(const osg::StateSet* stateset)
{
for(unsigned int i=0; i<stateset->getNumTextureAttributeLists(); ++i)
{
const osg::StateAttribute* sa = stateset->getTextureAttribute(i, osg::StateAttribute::TEXTURE);
if (sa && check(sa->asTexture())) return true;
}
return false;
}
bool check(osg::Object* object)
{
if (object->asStateAttribute()) return check(dynamic_cast<const osg::Texture*>(object));
if (object->asStateSet()) return check(object->asStateSet());
if (!object->asNode()) return false;
foundUnreffedTexture = false;
object->asNode()->accept(*this);
return foundUnreffedTexture;
}
void apply(osg::Node& node)
{
if (node.getStateSet())
{
if (check(node.getStateSet()))
{
foundUnreffedTexture = true;
return;
}
}
traverse(node);
}
};
} // ObjectCacheUtils
void ObjectCache::releaseGLObjects(osg::State* state)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
ObjectCacheUtils::ContainsUnreffedTextures cut;
for(ObjectCacheMap::iterator itr = _objectCache.begin();
itr != _objectCache.end();
++itr)
)
{
ObjectCacheMap::iterator curr_itr = itr;
// get object and advance iterator to next item
osg::Object* object = itr->second.first.get();
bool needToRemoveEntry = cut.check(itr->second.first.get());
object->releaseGLObjects(state);
++itr;
if (needToRemoveEntry)
{
_objectCache.erase(curr_itr);
}
}
}