Preload instances in SceneManager

This commit is contained in:
scrawl 2016-02-09 18:33:02 +01:00
parent 2e62298bd3
commit e28dc3e72f
16 changed files with 207 additions and 27 deletions

View file

@ -0,0 +1,79 @@
#include "multiobjectcache.hpp"
#include <vector>
#include <osg/Object>
namespace Resource
{
MultiObjectCache::MultiObjectCache()
{
}
MultiObjectCache::~MultiObjectCache()
{
}
void MultiObjectCache::removeUnreferencedObjectsInCache()
{
std::vector<osg::ref_ptr<osg::Object> > objectsToRemove;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
// Remove unreferenced entries from object cache
ObjectCacheMap::iterator oitr = _objectCache.begin();
while(oitr != _objectCache.end())
{
if (oitr->second->referenceCount() <= 1)
{
objectsToRemove.push_back(oitr->second);
_objectCache.erase(oitr++);
}
else
{
++oitr;
}
}
}
// note, actual unref happens outside of the lock
objectsToRemove.clear();
}
void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
_objectCache.insert(std::make_pair(filename, object));
}
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(const std::string &fileName)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
ObjectCacheMap::iterator found = _objectCache.find(fileName);
if (found == _objectCache.end())
return osg::ref_ptr<osg::Object>();
else
{
osg::ref_ptr<osg::Object> object = found->second;
_objectCache.erase(found);
return object;
}
}
void MultiObjectCache::releaseGLObjects(osg::State *state)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
for(ObjectCacheMap::iterator itr = _objectCache.begin();
itr != _objectCache.end();
++itr)
{
osg::Object* object = itr->second.get();
object->releaseGLObjects(state);
}
}
}

View file

@ -0,0 +1,47 @@
#ifndef OPENMW_COMPONENTS_MULTIOBJECTCACHE_H
#define OPENMW_COMPONENTS_MULTIOBJECTCACHE_H
#include <map>
#include <string>
#include <osg/ref_ptr>
#include <osg/Referenced>
namespace osg
{
class Object;
class State;
}
namespace Resource
{
/// @brief Cache for "non reusable" objects.
class MultiObjectCache : public osg::Referenced
{
public:
MultiObjectCache();
~MultiObjectCache();
void removeUnreferencedObjectsInCache();
void addEntryToObjectCache(const std::string& filename, osg::Object* object);
/** Take an Object from cache. Return NULL if no object found. */
osg::ref_ptr<osg::Object> takeFromObjectCache(const std::string& fileName);
/** call releaseGLObjects on all objects attached to the object cache.*/
void releaseGLObjects(osg::State* state);
protected:
typedef std::multimap<std::string, osg::ref_ptr<osg::Object> > ObjectCacheMap;
ObjectCacheMap _objectCache;
OpenThreads::Mutex _objectCacheMutex;
};
}
#endif

View file

@ -28,6 +28,7 @@
#include "imagemanager.hpp"
#include "niffilemanager.hpp"
#include "objectcache.hpp"
#include "multiobjectcache.hpp"
namespace
{
@ -233,6 +234,7 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
: ResourceManager(vfs)
, mInstanceCache(new MultiObjectCache)
, mImageManager(imageManager)
, mNifFileManager(nifFileManager)
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
@ -246,7 +248,6 @@ namespace Resource
SceneManager::~SceneManager()
{
// this has to be defined in the .cpp file as we can't delete incomplete types
}
/// @brief Callback to read image files from the VFS.
@ -372,7 +373,17 @@ namespace Resource
}
}
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string &name)
osg::ref_ptr<osg::Node> SceneManager::cacheInstance(const std::string &name)
{
std::string normalized = name;
mVFS->normalizeFilename(normalized);
osg::ref_ptr<osg::Node> node = createInstance(normalized);
mInstanceCache->addEntryToObjectCache(normalized, node.get());
return node;
}
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string& name)
{
osg::ref_ptr<const osg::Node> scene = getTemplate(name);
osg::ref_ptr<osg::Node> cloned = osg::clone(scene.get(), SceneUtil::CopyOp());
@ -383,9 +394,22 @@ namespace Resource
return cloned;
}
osg::ref_ptr<osg::Node> SceneManager::createInstance(const std::string &name, osg::Group* parentNode)
osg::ref_ptr<osg::Node> SceneManager::getInstance(const std::string &name)
{
osg::ref_ptr<osg::Node> cloned = createInstance(name);
std::string normalized = name;
mVFS->normalizeFilename(normalized);
osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized);
if (obj.get())
return static_cast<osg::Node*>(obj.get());
return createInstance(normalized);
}
osg::ref_ptr<osg::Node> SceneManager::getInstance(const std::string &name, osg::Group* parentNode)
{
osg::ref_ptr<osg::Node> cloned = getInstance(name);
attachTo(cloned, parentNode);
return cloned;
}
@ -487,4 +511,11 @@ namespace Resource
mUnRefImageDataAfterApply = unref;
}
void SceneManager::updateCache(double referenceTime)
{
ResourceManager::updateCache(referenceTime);
mInstanceCache->removeUnreferencedObjectsInCache();
}
}

View file

@ -29,6 +29,8 @@ namespace osgViewer
namespace Resource
{
class MultiObjectCache;
/// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files
/// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details.
class SceneManager : public ResourceManager
@ -43,15 +45,21 @@ namespace Resource
/// @note Thread safe.
osg::ref_ptr<const osg::Node> getTemplate(const std::string& name);
/// Create an instance of the given scene template
/// Create an instance of the given scene template and cache it for later use, so that future calls to getInstance() can simply
/// return this cached object instead of creating a new one.
/// @note The returned ref_ptr may be kept around by the caller to ensure that the object stays in cache for as long as needed.
/// @note Thread safe.
osg::ref_ptr<osg::Node> cacheInstance(const std::string& name);
/// Get an instance of the given scene template
/// @see getTemplate
/// @note Thread safe.
osg::ref_ptr<osg::Node> createInstance(const std::string& name);
osg::ref_ptr<osg::Node> getInstance(const std::string& name);
/// Create an instance of the given scene template and immediately attach it to a parent node
/// Get an instance of the given scene template and immediately attach it to a parent node
/// @see getTemplate
/// @note Not thread safe, unless parentNode is not part of the main scene graph yet.
osg::ref_ptr<osg::Node> createInstance(const std::string& name, osg::Group* parentNode);
osg::ref_ptr<osg::Node> getInstance(const std::string& name, osg::Group* parentNode);
/// Attach the given scene instance to the given parent node
/// @note You should have the parentNode in its intended position before calling this method,
@ -88,7 +96,15 @@ namespace Resource
/// otherwise should be disabled to reduce memory usage.
void setUnRefImageDataAfterApply(bool unref);
/// @see ResourceManager::updateCache
virtual void updateCache(double referenceTime);
private:
osg::ref_ptr<osg::Node> createInstance(const std::string& name);
osg::ref_ptr<MultiObjectCache> mInstanceCache;
OpenThreads::Mutex mSharedStateMutex;
Resource::ImageManager* mImageManager;