Use a common base class for resource managers

Implement updateCache to delete unreferenced cached objects when they have not been referenced for a while.
pull/893/head
scrawl 9 years ago
parent ea1efaac0c
commit df57d4bfba

@ -640,12 +640,15 @@ namespace MWPhysics
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
: mShapeManager(new Resource::BulletShapeManager(resourceSystem->getVFS(), resourceSystem->getSceneManager(), resourceSystem->getNifFileManager()))
, mResourceSystem(resourceSystem)
, mDebugDrawEnabled(false)
, mTimeAccum(0.0f)
, mWaterHeight(0)
, mWaterEnabled(false)
, mParentNode(parentNode)
{
mResourceSystem->addResourceManager(mShapeManager.get());
mCollisionConfiguration = new btDefaultCollisionConfiguration();
mDispatcher = new btCollisionDispatcher(mCollisionConfiguration);
mBroadphase = new btDbvtBroadphase();
@ -659,6 +662,8 @@ namespace MWPhysics
PhysicsSystem::~PhysicsSystem()
{
mResourceSystem->removeResourceManager(mShapeManager.get());
if (mWaterCollisionObject.get())
mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get());

@ -169,6 +169,7 @@ namespace MWPhysics
btCollisionWorld* mCollisionWorld;
std::auto_ptr<Resource::BulletShapeManager> mShapeManager;
Resource::ResourceSystem* mResourceSystem;
typedef std::map<MWWorld::ConstPtr, Object*> ObjectMap;
ObjectMap mObjects;

@ -233,7 +233,7 @@ namespace MWRender
void RenderingManager::clearCache()
{
mResourceSystem->clearCache();
mResourceSystem->updateCache(mViewer->getFrameStamp()->getReferenceTime());
if (mTerrain.get())
mTerrain->clearCache();
}

@ -41,7 +41,7 @@ add_component_dir (vfs
)
add_component_dir (resource
scenemanager keyframemanager imagemanager resourcesystem bulletshapemanager bulletshape niffilemanager objectcache
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache resourcesystem resourcemanager
)
add_component_dir (sceneutil

@ -97,10 +97,9 @@ private:
};
BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager)
: mVFS(vfs)
: ResourceManager(vfs)
, mSceneManager(sceneMgr)
, mNifFileManager(nifFileManager)
, mCache(new osgDB::ObjectCache)
{
}

@ -7,16 +7,7 @@
#include <osg/ref_ptr>
#include "bulletshape.hpp"
namespace VFS
{
class Manager;
}
namespace osgDB
{
class ObjectCache;
}
#include "resourcemanager.hpp"
namespace Resource
{
@ -29,7 +20,7 @@ namespace Resource
/// Handles loading, caching and "instancing" of bullet shapes.
/// A shape 'instance' is a clone of another shape, with the goal of setting a different scale on this instance.
/// @note May be used from any thread.
class BulletShapeManager
class BulletShapeManager : public ResourceManager
{
public:
BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager);
@ -38,11 +29,8 @@ namespace Resource
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name);
private:
const VFS::Manager* mVFS;
SceneManager* mSceneManager;
NifFileManager* mNifFileManager;
osg::ref_ptr<osgDB::ObjectCache> mCache;
};
}

@ -42,8 +42,7 @@ namespace Resource
{
ImageManager::ImageManager(const VFS::Manager *vfs)
: mVFS(vfs)
, mCache(new osgDB::ObjectCache)
: ResourceManager(vfs)
, mWarningImage(createWarningImage())
, mOptions(new osgDB::Options("dds_flip dds_dxt1_detect_rgba"))
{

@ -8,20 +8,16 @@
#include <osg/Image>
#include <osg/Texture2D>
#include "resourcemanager.hpp"
namespace osgViewer
{
class Viewer;
}
namespace VFS
{
class Manager;
}
namespace osgDB
{
class Options;
class ObjectCache;
}
namespace Resource
@ -29,7 +25,7 @@ namespace Resource
/// @brief Handles loading/caching of Images.
/// @note May be used from any thread.
class ImageManager
class ImageManager : public ResourceManager
{
public:
ImageManager(const VFS::Manager* vfs);
@ -39,15 +35,9 @@ namespace Resource
/// Returns the dummy image if the given image is not found.
osg::ref_ptr<osg::Image> getImage(const std::string& filename);
const VFS::Manager* getVFS() { return mVFS; }
osg::Image* getWarningImage();
private:
const VFS::Manager* mVFS;
osg::ref_ptr<osgDB::ObjectCache> mCache;
osg::ref_ptr<osg::Image> mWarningImage;
osg::ref_ptr<osgDB::Options> mOptions;

@ -9,8 +9,7 @@ namespace Resource
{
KeyframeManager::KeyframeManager(const VFS::Manager* vfs)
: mCache(new osgDB::ObjectCache)
, mVFS(vfs)
: ResourceManager(vfs)
{
}

@ -4,15 +4,7 @@
#include <osg/ref_ptr>
#include <string>
namespace VFS
{
class Manager;
}
namespace osgDB
{
class ObjectCache;
}
#include "resourcemanager.hpp"
namespace NifOsg
{
@ -24,22 +16,15 @@ namespace Resource
/// @brief Managing of keyframe resources
/// @note May be used from any thread.
class KeyframeManager
class KeyframeManager : public ResourceManager
{
public:
KeyframeManager(const VFS::Manager* vfs);
~KeyframeManager();
void clearCache();
/// Retrieve a read-only keyframe resource by name (case-insensitive).
/// @note Throws an exception if the resource is not found.
osg::ref_ptr<const NifOsg::KeyframeHolder> get(const std::string& name);
private:
osg::ref_ptr<osgDB::ObjectCache> mCache;
const VFS::Manager* mVFS;
};
}

@ -29,9 +29,9 @@ namespace Resource
};
NifFileManager::NifFileManager(const VFS::Manager *vfs)
: mVFS(vfs)
: ResourceManager(vfs, 0.0) // NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager,
// so we'll use expiryDelay of 0 to instantly delete NIF files after use.
{
mCache = new osgDB::ObjectCache;
}
NifFileManager::~NifFileManager()
@ -39,12 +39,6 @@ namespace Resource
}
void NifFileManager::clearCache()
{
// NIF files aren't needed any more when the converted objects are cached in SceneManager / BulletShapeManager,
// so we'll simply drop all nif files here, unlikely to need them again
mCache->clear();
}
Nif::NIFFilePtr NifFileManager::get(const std::string &name)
{

@ -5,39 +5,23 @@
#include <components/nif/niffile.hpp>
namespace VFS
{
class Manager;
}
namespace osgDB
{
class ObjectCache;
}
#include "resourcemanager.hpp"
namespace Resource
{
/// @brief Handles caching of NIFFiles.
/// @note May be used from any thread.
class NifFileManager
class NifFileManager : public ResourceManager
{
public:
NifFileManager(const VFS::Manager* vfs);
~NifFileManager();
void clearCache();
/// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet.
/// @note For performance reasons the NifFileManager does not handle case folding, needs
/// to be done in advance by other managers accessing the NifFileManager.
Nif::NIFFilePtr get(const std::string& name);
private:
// Use the osgDB::ObjectCache so objects are retrieved in thread safe way
osg::ref_ptr<osgDB::ObjectCache> mCache;
const VFS::Manager* mVFS;
};
}

@ -0,0 +1,34 @@
#include "resourcemanager.hpp"
#include "objectcache.hpp"
namespace Resource
{
ResourceManager::ResourceManager(const VFS::Manager *vfs, const double expiryDelay)
: mVFS(vfs)
, mCache(new osgDB::ObjectCache)
, mExpiryDelay(expiryDelay)
{
}
void ResourceManager::updateCache(double referenceTime)
{
// NOTE: we could clear the cache from the background thread if the deletion proves too much of an overhead
// idea: customize objectCache to not hold a lock while doing the actual deletion
mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime);
mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay);
}
void ResourceManager::clearCache()
{
mCache->clear();
}
const VFS::Manager* ResourceManager::getVFS() const
{
return mVFS;
}
}

@ -0,0 +1,43 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_MANAGER_H
#define OPENMW_COMPONENTS_RESOURCE_MANAGER_H
#include <osg/ref_ptr>
namespace VFS
{
class Manager;
}
namespace osgDB
{
class ObjectCache;
}
namespace Resource
{
/// @brief Base class for managers that require a virtual file system and object cache.
/// @par This base class implements clearing of the cache, but populating it and what it's used for is up to the individual sub classes.
class ResourceManager
{
public:
/// @param expiryDelay how long to keep objects in cache after no longer being referenced.
ResourceManager(const VFS::Manager* vfs, const double expiryDelay = 300.0);
/// Clear cache entries that have not been referenced for longer than expiryDelay.
virtual void updateCache(double referenceTime);
/// Clear all cache entries regardless of having external references.
virtual void clearCache();
const VFS::Manager* getVFS() const;
protected:
const VFS::Manager* mVFS;
osg::ref_ptr<osgDB::ObjectCache> mCache;
double mExpiryDelay;
};
}
#endif

@ -15,11 +15,21 @@ namespace Resource
mKeyframeManager.reset(new KeyframeManager(vfs));
mImageManager.reset(new ImageManager(vfs));
mSceneManager.reset(new SceneManager(vfs, mImageManager.get(), mNifFileManager.get()));
addResourceManager(mNifFileManager.get());
addResourceManager(mKeyframeManager.get());
// note, scene references images so add images afterwards for correct implementation of updateCache()
addResourceManager(mSceneManager.get());
addResourceManager(mImageManager.get());
}
ResourceSystem::~ResourceSystem()
{
// this has to be defined in the .cpp file as we can't delete incomplete types
mResourceManagers.clear();
// no delete, all handled by auto_ptr
}
SceneManager* ResourceSystem::getSceneManager()
@ -42,9 +52,24 @@ namespace Resource
return mKeyframeManager.get();
}
void ResourceSystem::clearCache()
void ResourceSystem::updateCache(double referenceTime)
{
osg::Timer timer;
for (std::vector<ResourceManager*>::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it)
(*it)->updateCache(referenceTime);
std::cout << "updateCache took " << timer.time_m() << " ms" << std::endl;
}
void ResourceSystem::addResourceManager(ResourceManager *resourceMgr)
{
mResourceManagers.push_back(resourceMgr);
}
void ResourceSystem::removeResourceManager(ResourceManager *resourceMgr)
{
mNifFileManager->clearCache();
std::vector<ResourceManager*>::iterator found = std::find(mResourceManagers.begin(), mResourceManagers.end(), resourceMgr);
if (found != mResourceManagers.end())
mResourceManagers.erase(found);
}
const VFS::Manager* ResourceSystem::getVFS() const

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_RESOURCE_RESOURCESYSTEM_H
#include <memory>
#include <vector>
namespace VFS
{
@ -15,6 +16,7 @@ namespace Resource
class ImageManager;
class NifFileManager;
class KeyframeManager;
class ResourceManager;
/// @brief Wrapper class that constructs and provides access to the most commonly used resource subsystems.
/// @par Resource subsystems can be used with multiple OpenGL contexts, just like the OSG equivalents, but
@ -31,8 +33,17 @@ namespace Resource
KeyframeManager* getKeyframeManager();
/// Indicates to each resource manager to clear the cache, i.e. to drop cached objects that are no longer referenced.
void clearCache();
/// @note May be called from any thread if you do not add or remove resource managers at that point.
void updateCache(double referenceTime);
/// Add this ResourceManager to be handled by the ResourceSystem.
/// @note Does not transfer ownership.
void addResourceManager(ResourceManager* resourceMgr);
/// @note Do nothing if resourceMgr does not exist.
/// @note Does not delete resourceMgr.
void removeResourceManager(ResourceManager* resourceMgr);
/// @note May be called from any thread.
const VFS::Manager* getVFS() const;
private:
@ -41,6 +52,10 @@ namespace Resource
std::auto_ptr<NifFileManager> mNifFileManager;
std::auto_ptr<KeyframeManager> mKeyframeManager;
// Store the base classes separately to get convenient access to the common interface
// Here users can register their own resourcemanager as well
std::vector<ResourceManager*> mResourceManagers;
const VFS::Manager* mVFS;
ResourceSystem(const ResourceSystem&);

@ -230,7 +230,7 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
: mVFS(vfs)
: ResourceManager(vfs)
, mImageManager(imageManager)
, mNifFileManager(nifFileManager)
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
@ -238,7 +238,6 @@ namespace Resource
, mMaxAnisotropy(1)
, mUnRefImageDataAfterApply(false)
, mParticleSystemMask(~0u)
, mCache(new osgDB::ObjectCache)
{
}
@ -403,11 +402,6 @@ namespace Resource
node->accept(visitor);
}
const VFS::Manager* SceneManager::getVFS() const
{
return mVFS;
}
Resource::ImageManager* SceneManager::getImageManager()
{
return mImageManager;
@ -483,5 +477,4 @@ namespace Resource
mUnRefImageDataAfterApply = unref;
}
}

@ -8,27 +8,19 @@
#include <osg/Node>
#include <osg/Texture>
#include "resourcemanager.hpp"
namespace Resource
{
class ImageManager;
class NifFileManager;
}
namespace VFS
{
class Manager;
}
namespace osgUtil
{
class IncrementalCompileOperation;
}
namespace osgDB
{
class ObjectCache;
}
namespace osgViewer
{
class Viewer;
@ -39,7 +31,7 @@ namespace Resource
/// @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
class SceneManager : public ResourceManager
{
public:
SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager);
@ -78,8 +70,6 @@ namespace Resource
/// @note SceneManager::attachTo calls this method automatically, only needs to be called by users if manually attaching
void notifyAttached(osg::Node* node) const;
const VFS::Manager* getVFS() const;
Resource::ImageManager* getImageManager();
/// @param mask The node mask to apply to loaded particle system nodes.
@ -99,7 +89,6 @@ namespace Resource
void setUnRefImageDataAfterApply(bool unref);
private:
const VFS::Manager* mVFS;
Resource::ImageManager* mImageManager;
Resource::NifFileManager* mNifFileManager;
@ -112,8 +101,6 @@ namespace Resource
unsigned int mParticleSystemMask;
osg::ref_ptr<osgDB::ObjectCache> mCache;
SceneManager(const SceneManager&);
void operator = (const SceneManager&);
};

@ -16,6 +16,7 @@ namespace VFS
/// @par Various archive types (e.g. directories on the filesystem, or compressed archives)
/// can be registered, and will be merged into a single file tree. If the same filename is
/// contained in multiple archives, the last added archive will have priority.
/// @par Most of the methods in this class are considered thread-safe, see each method documentation for details.
class Manager
{
public:
@ -33,20 +34,25 @@ namespace VFS
void buildIndex();
/// Does a file with this name exist?
/// @note May be called from any thread once the index has been built.
bool exists(const std::string& name) const;
/// Get a complete list of files from all archives
/// @note May be called from any thread once the index has been built.
const std::map<std::string, File*>& getIndex() const;
/// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false.
/// @note May be called from any thread once the index has been built.
void normalizeFilename(std::string& name) const;
/// Retrieve a file by name.
/// @note Throws an exception if the file can not be found.
/// @note May be called from any thread once the index has been built.
Files::IStreamPtr get(const std::string& name) const;
/// Retrieve a file by name (name is already normalized).
/// @note Throws an exception if the file can not be found.
/// @note May be called from any thread once the index has been built.
Files::IStreamPtr getNormalized(const std::string& normalizedName) const;
private:

Loading…
Cancel
Save