mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-30 22:07:58 +03:00
Preload instances in SceneManager
This commit is contained in:
parent
2e62298bd3
commit
e28dc3e72f
16 changed files with 207 additions and 27 deletions
79
components/resource/multiobjectcache.cpp
Normal file
79
components/resource/multiobjectcache.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
components/resource/multiobjectcache.hpp
Normal file
47
components/resource/multiobjectcache.hpp
Normal 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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue