Preload instances in SceneManager

pull/893/head
scrawl 9 years ago
parent 2e62298bd3
commit e28dc3e72f

@ -100,7 +100,7 @@ void CSVRender::Object::update()
{
std::string path = "meshes\\" + model;
mResourceSystem->getSceneManager()->createInstance(path, mBaseNode);
mResourceSystem->getSceneManager()->getInstance(path, mBaseNode);
}
catch (std::exception& e)
{

@ -997,7 +997,7 @@ namespace MWRender
if (!forceskeleton)
{
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->createInstance(model, mInsert);
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->getInstance(model, mInsert);
mObjectRoot = created->asGroup();
if (!mObjectRoot)
{
@ -1009,7 +1009,7 @@ namespace MWRender
}
else
{
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->createInstance(model);
osg::ref_ptr<osg::Node> created = mResourceSystem->getSceneManager()->getInstance(model);
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
if (!skel)
{
@ -1136,7 +1136,7 @@ namespace MWRender
parentNode = found->second;
}
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(model, parentNode);
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model, parentNode);
node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

@ -105,7 +105,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
else
bonename = "Shield Bone";
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(item.getClass().getModel(item));
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item));
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename);
mResourceSystem->getSceneManager()->notifyAttached(attached);

@ -27,7 +27,7 @@ EffectManager::~EffectManager()
void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale)
{
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->createInstance(model);
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model);
node->setNodeMask(Mask_Effect);

@ -647,7 +647,7 @@ void NpcAnimation::updateParts()
PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor)
{
osg::ref_ptr<osg::Node> instance = mResourceSystem->getSceneManager()->createInstance(model);
osg::ref_ptr<osg::Node> instance = mResourceSystem->getSceneManager()->getInstance(model);
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename);
mResourceSystem->getSceneManager()->notifyAttached(attached);
if (enchantedGlow)

@ -1146,7 +1146,7 @@ void SkyManager::create()
{
assert(!mCreated);
mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot);
mAtmosphereDay = mSceneManager->getInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot);
ModVertexAlphaVisitor modAtmosphere(0);
mAtmosphereDay->accept(modAtmosphere);
@ -1159,9 +1159,9 @@ void SkyManager::create()
osg::ref_ptr<osg::Node> atmosphereNight;
if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif"))
atmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mAtmosphereNightNode);
atmosphereNight = mSceneManager->getInstance("meshes/sky_night_02.nif", mAtmosphereNightNode);
else
atmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mAtmosphereNightNode);
atmosphereNight = mSceneManager->getInstance("meshes/sky_night_01.nif", mAtmosphereNightNode);
atmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
ModVertexAlphaVisitor modStars(2);
atmosphereNight->accept(modStars);
@ -1176,14 +1176,14 @@ void SkyManager::create()
mCloudNode = new osg::PositionAttitudeTransform;
mEarlyRenderBinRoot->addChild(mCloudNode);
mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode);
mCloudMesh = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode);
ModVertexAlphaVisitor modClouds(1);
mCloudMesh->accept(modClouds);
mCloudUpdater = new CloudUpdater;
mCloudUpdater->setOpacity(1.f);
mCloudMesh->addUpdateCallback(mCloudUpdater);
mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode);
mCloudMesh2 = mSceneManager->getInstance("meshes/sky_clouds_01.nif", mCloudNode);
mCloudMesh2->accept(modClouds);
mCloudUpdater2 = new CloudUpdater;
mCloudUpdater2->setOpacity(0.f);
@ -1537,7 +1537,7 @@ void SkyManager::setWeather(const WeatherResult& weather)
mParticleNode->setNodeMask(Mask_WeatherParticles);
mRootNode->addChild(mParticleNode);
}
mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode);
mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode);
SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
mParticleEffect->accept(assignVisitor);

@ -84,7 +84,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
return;
std::string model = ammo->getClass().getModel(*ammo);
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->createInstance(model, parent);
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent);
mAmmunition = PartHolderPtr(new PartHolder(arrow));
}

@ -86,7 +86,7 @@ namespace MWWorld
//std::cout << "preloading " << mesh << std::endl;
mPreloadedNodes.push_back(mSceneManager->getTemplate(mesh));
mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh));
mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh));
size_t slashpos = mesh.find_last_of("/\\");
@ -104,8 +104,6 @@ namespace MWWorld
}
}
// TODO: do a createInstance() and hold on to it since we can make use of it when the cell goes active
}
catch (std::exception& e)
{
@ -185,6 +183,11 @@ namespace MWWorld
mPreloadCells[cell] = PreloadEntry(timestamp, item);
}
void CellPreloader::notifyLoaded(CellStore *cell)
{
mPreloadCells.erase(cell);
}
void CellPreloader::updateCache(double timestamp)
{
// TODO: add settings for a minimum/maximum size of the cache

@ -24,6 +24,8 @@ namespace MWWorld
/// @note The cell itself must be in State_Loaded or State_Preloaded.
void preload(MWWorld::CellStore* cell, double timestamp);
void notifyLoaded(MWWorld::CellStore* cell);
/// Removes preloaded cells that have not had a preload request for a while.
void updateCache(double timestamp);

@ -92,7 +92,7 @@ namespace MWWorld
attachTo = rotateNode;
}
mResourceSystem->getSceneManager()->createInstance(model, attachTo);
mResourceSystem->getSceneManager()->getInstance(model, attachTo);
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
state.mNode->accept(disableFreezeOnCullVisitor);

@ -296,6 +296,8 @@ namespace MWWorld
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
mRendering.configureAmbient(cell->getCell());
}
mPreloader->notifyLoaded(cell);
}
void Scene::changeToVoid()

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

@ -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);
}
}
}

@ -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…
Cancel
Save