Preload instances in SceneManager

coverity_scan
scrawl 9 years ago
parent 2e62298bd3
commit e28dc3e72f

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

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

@ -105,7 +105,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
else else
bonename = "Shield Bone"; 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); osg::ref_ptr<osg::Node> attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename);
mResourceSystem->getSceneManager()->notifyAttached(attached); 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) 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); 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) 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); osg::ref_ptr<osg::Node> attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename);
mResourceSystem->getSceneManager()->notifyAttached(attached); mResourceSystem->getSceneManager()->notifyAttached(attached);
if (enchantedGlow) if (enchantedGlow)

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

@ -84,7 +84,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
return; return;
std::string model = ammo->getClass().getModel(*ammo); 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)); mAmmunition = PartHolderPtr(new PartHolder(arrow));
} }

@ -86,7 +86,7 @@ namespace MWWorld
//std::cout << "preloading " << mesh << std::endl; //std::cout << "preloading " << mesh << std::endl;
mPreloadedNodes.push_back(mSceneManager->getTemplate(mesh)); mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh));
mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh)); mPreloadedShapes.push_back(mBulletShapeManager->getShape(mesh));
size_t slashpos = mesh.find_last_of("/\\"); 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) catch (std::exception& e)
{ {
@ -185,6 +183,11 @@ namespace MWWorld
mPreloadCells[cell] = PreloadEntry(timestamp, item); mPreloadCells[cell] = PreloadEntry(timestamp, item);
} }
void CellPreloader::notifyLoaded(CellStore *cell)
{
mPreloadCells.erase(cell);
}
void CellPreloader::updateCache(double timestamp) void CellPreloader::updateCache(double timestamp)
{ {
// TODO: add settings for a minimum/maximum size of the cache // 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. /// @note The cell itself must be in State_Loaded or State_Preloaded.
void preload(MWWorld::CellStore* cell, double timestamp); 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. /// Removes preloaded cells that have not had a preload request for a while.
void updateCache(double timestamp); void updateCache(double timestamp);

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

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

@ -41,7 +41,7 @@ add_component_dir (vfs
) )
add_component_dir (resource 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 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 "imagemanager.hpp"
#include "niffilemanager.hpp" #include "niffilemanager.hpp"
#include "objectcache.hpp" #include "objectcache.hpp"
#include "multiobjectcache.hpp"
namespace namespace
{ {
@ -233,6 +234,7 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
: ResourceManager(vfs) : ResourceManager(vfs)
, mInstanceCache(new MultiObjectCache)
, mImageManager(imageManager) , mImageManager(imageManager)
, mNifFileManager(nifFileManager) , mNifFileManager(nifFileManager)
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR) , mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
@ -246,7 +248,6 @@ namespace Resource
SceneManager::~SceneManager() SceneManager::~SceneManager()
{ {
// this has to be defined in the .cpp file as we can't delete incomplete types // 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. /// @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<const osg::Node> scene = getTemplate(name);
osg::ref_ptr<osg::Node> cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); osg::ref_ptr<osg::Node> cloned = osg::clone(scene.get(), SceneUtil::CopyOp());
@ -383,9 +394,22 @@ namespace Resource
return cloned; 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); attachTo(cloned, parentNode);
return cloned; return cloned;
} }
@ -487,4 +511,11 @@ namespace Resource
mUnRefImageDataAfterApply = unref; mUnRefImageDataAfterApply = unref;
} }
void SceneManager::updateCache(double referenceTime)
{
ResourceManager::updateCache(referenceTime);
mInstanceCache->removeUnreferencedObjectsInCache();
}
} }

@ -29,6 +29,8 @@ namespace osgViewer
namespace Resource namespace Resource
{ {
class MultiObjectCache;
/// @brief Handles loading and caching of scenes, e.g. .nif files or .osg files /// @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. /// @note Some methods of the scene manager can be used from any thread, see the methods documentation for more details.
class SceneManager : public ResourceManager class SceneManager : public ResourceManager
@ -43,15 +45,21 @@ namespace Resource
/// @note Thread safe. /// @note Thread safe.
osg::ref_ptr<const osg::Node> getTemplate(const std::string& name); 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 /// @see getTemplate
/// @note Thread safe. /// @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 /// @see getTemplate
/// @note Not thread safe, unless parentNode is not part of the main scene graph yet. /// @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 /// Attach the given scene instance to the given parent node
/// @note You should have the parentNode in its intended position before calling this method, /// @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. /// otherwise should be disabled to reduce memory usage.
void setUnRefImageDataAfterApply(bool unref); void setUnRefImageDataAfterApply(bool unref);
/// @see ResourceManager::updateCache
virtual void updateCache(double referenceTime);
private: private:
osg::ref_ptr<osg::Node> createInstance(const std::string& name);
osg::ref_ptr<MultiObjectCache> mInstanceCache;
OpenThreads::Mutex mSharedStateMutex; OpenThreads::Mutex mSharedStateMutex;
Resource::ImageManager* mImageManager; Resource::ImageManager* mImageManager;

Loading…
Cancel
Save