Fix growing memory consumption issues
References in simgear's cache maps prevented effects, textures, clouds, trees and lights from being unloaded at run-time (ref-counter could never reach 0). Changed cache maps to use OSG 'observer' pointers instead, so reference counters aren't influenced, though cache maps still hold an (observing) pointer. Also take care when finding a cache entry with empty content (i.e. texture was unloaded).
This commit is contained in:
@@ -1392,10 +1392,11 @@ public:
|
|||||||
|
|
||||||
void valueChanged(SGPropertyNode* node)
|
void valueChanged(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
_tniq->refreshValidity();
|
if (_tniq.valid())
|
||||||
|
_tniq->refreshValidity();
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
osg::ref_ptr<Technique> _tniq;
|
osg::observer_ptr<Technique> _tniq;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
#include <osg/Object>
|
#include <osg/Object>
|
||||||
|
#include <osg/observer_ptr>
|
||||||
#include <osgDB/ReaderWriter>
|
#include <osgDB/ReaderWriter>
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
@@ -158,7 +159,7 @@ protected:
|
|||||||
bool operator()(const Key& lhs, const Key& rhs) const;
|
bool operator()(const Key& lhs, const Key& rhs) const;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
typedef std::tr1::unordered_map<Key, osg::ref_ptr<Effect>,
|
typedef std::tr1::unordered_map<Key, osg::observer_ptr<Effect>,
|
||||||
boost::hash<Key>, Key::EqualTo> Cache;
|
boost::hash<Key>, Key::EqualTo> Cache;
|
||||||
Cache* getCache()
|
Cache* getCache()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public:
|
|||||||
Texture* build(Effect* effect, Pass* pass, const SGPropertyNode*,
|
Texture* build(Effect* effect, Pass* pass, const SGPropertyNode*,
|
||||||
const SGReaderWriterOptions* options);
|
const SGReaderWriterOptions* options);
|
||||||
protected:
|
protected:
|
||||||
typedef map<TexTuple, ref_ptr<T> > TexMap;
|
typedef map<TexTuple, observer_ptr<T> > TexMap;
|
||||||
TexMap texMap;
|
TexMap texMap;
|
||||||
const string _type;
|
const string _type;
|
||||||
};
|
};
|
||||||
@@ -290,11 +290,20 @@ Texture* TexBuilder<T>::build(Effect* effect, Pass* pass, const SGPropertyNode*
|
|||||||
{
|
{
|
||||||
TexTuple attrs = makeTexTuple(effect, props, options, _type);
|
TexTuple attrs = makeTexTuple(effect, props, options, _type);
|
||||||
typename TexMap::iterator itr = texMap.find(attrs);
|
typename TexMap::iterator itr = texMap.find(attrs);
|
||||||
|
|
||||||
if (itr != texMap.end())
|
if (itr != texMap.end())
|
||||||
return itr->second.get();
|
{
|
||||||
|
T* tex = itr->second.get();
|
||||||
|
if (tex)
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
T* tex = new T;
|
T* tex = new T;
|
||||||
setAttrs(attrs, tex, options);
|
setAttrs(attrs, tex, options);
|
||||||
texMap.insert(make_pair(attrs, tex));
|
if (itr == texMap.end())
|
||||||
|
texMap.insert(make_pair(attrs, tex));
|
||||||
|
else
|
||||||
|
itr->second = tex; // update existing, but empty observer
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ using namespace osg;
|
|||||||
using namespace effect;
|
using namespace effect;
|
||||||
|
|
||||||
typedef vector<const SGPropertyNode*> RawPropVector;
|
typedef vector<const SGPropertyNode*> RawPropVector;
|
||||||
typedef map<const string, ref_ptr<Effect> > EffectMap;
|
typedef map<const string, observer_ptr<Effect> > EffectMap;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -122,7 +122,8 @@ Effect* makeEffect(const string& name,
|
|||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
|
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
|
||||||
EffectMap::iterator itr = effectMap.find(name);
|
EffectMap::iterator itr = effectMap.find(name);
|
||||||
if (itr != effectMap.end())
|
if ((itr != effectMap.end())&&
|
||||||
|
itr->second.valid())
|
||||||
return itr->second.get();
|
return itr->second.get();
|
||||||
}
|
}
|
||||||
string effectFileName(name);
|
string effectFileName(name);
|
||||||
@@ -207,7 +208,8 @@ Effect* makeEffect(SGPropertyNode* prop,
|
|||||||
itr = cache->find(key);
|
itr = cache->find(key);
|
||||||
if (itr != cache->end()) {
|
if (itr != cache->end()) {
|
||||||
effect = itr->second.get();
|
effect = itr->second.get();
|
||||||
effect->generator = parent->generator; // Copy the generators
|
if (effect.valid())
|
||||||
|
effect->generator = parent->generator; // Copy the generators
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!effect.valid()) {
|
if (!effect.valid()) {
|
||||||
@@ -219,8 +221,13 @@ Effect* makeEffect(SGPropertyNode* prop,
|
|||||||
lock(effectMutex);
|
lock(effectMutex);
|
||||||
pair<Effect::Cache::iterator, bool> irslt
|
pair<Effect::Cache::iterator, bool> irslt
|
||||||
= cache->insert(make_pair(key, effect));
|
= cache->insert(make_pair(key, effect));
|
||||||
if (!irslt.second)
|
if (!irslt.second) {
|
||||||
effect = irslt.first->second;
|
ref_ptr<Effect> old = irslt.first->second.get();
|
||||||
|
if (old.valid())
|
||||||
|
effect = old; // Another thread beat us in creating it! Discard our own...
|
||||||
|
else
|
||||||
|
irslt.first->second = effect; // update existing, but empty observer
|
||||||
|
}
|
||||||
effect->generator = parent->generator; // Copy the generators
|
effect->generator = parent->generator; // Copy the generators
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ using namespace std;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap;
|
typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
|
||||||
EffectMap effectMap;
|
EffectMap effectMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,13 @@ SGNewCloud::SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def
|
|||||||
|
|
||||||
// Create a new Effect for the texture, if required.
|
// Create a new Effect for the texture, if required.
|
||||||
EffectMap::iterator iter = effectMap.find(texture);
|
EffectMap::iterator iter = effectMap.find(texture);
|
||||||
if (iter == effectMap.end()) {
|
|
||||||
|
if (iter != effectMap.end()) {
|
||||||
|
effect = iter->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!effect.valid())
|
||||||
|
{
|
||||||
SGPropertyNode_ptr pcloudEffect = new SGPropertyNode;
|
SGPropertyNode_ptr pcloudEffect = new SGPropertyNode;
|
||||||
makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud");
|
makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud");
|
||||||
setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"),
|
setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"),
|
||||||
@@ -111,10 +117,14 @@ SGNewCloud::SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def
|
|||||||
texture);
|
texture);
|
||||||
ref_ptr<SGReaderWriterOptions> options;
|
ref_ptr<SGReaderWriterOptions> options;
|
||||||
options = SGReaderWriterOptions::fromPath(texture_root.str());
|
options = SGReaderWriterOptions::fromPath(texture_root.str());
|
||||||
if ((effect = makeEffect(pcloudEffect, true, options.get())))
|
effect = makeEffect(pcloudEffect, true, options.get());
|
||||||
effectMap.insert(EffectMap::value_type(texture, effect));
|
if (effect.valid())
|
||||||
} else {
|
{
|
||||||
effect = iter->second.get();
|
if (iter == effectMap.end())
|
||||||
|
effectMap.insert(EffectMap::value_type(texture, effect));
|
||||||
|
else
|
||||||
|
iter->second = effect; // update existing, but empty observer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ private:
|
|||||||
|
|
||||||
// The density of the cloud is the shading applied
|
// The density of the cloud is the shading applied
|
||||||
// to cloud sprites on the opposite side of the cloud
|
// to cloud sprites on the opposite side of the cloud
|
||||||
// from the sun. For an invidual cloud instance a value
|
// from the sun. For an individual cloud instance a value
|
||||||
// between min_density and max_density is chosen.
|
// between min_density and max_density is chosen.
|
||||||
float min_density;
|
float min_density;
|
||||||
float max_density;
|
float max_density;
|
||||||
@@ -102,7 +102,6 @@ private:
|
|||||||
static float sprite_density;
|
static float sprite_density;
|
||||||
|
|
||||||
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
|
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ void addTreeToLeafGeode(Geode* geode, const SGVec3f& p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap;
|
typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
|
||||||
|
|
||||||
static EffectMap treeEffectMap;
|
static EffectMap treeEffectMap;
|
||||||
|
|
||||||
@@ -299,9 +299,14 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
|
|||||||
for (i = forestList.begin(); i != forestList.end(); ++i) {
|
for (i = forestList.begin(); i != forestList.end(); ++i) {
|
||||||
TreeBin* forest = *i;
|
TreeBin* forest = *i;
|
||||||
|
|
||||||
Effect* effect = 0;
|
ref_ptr<Effect> effect;
|
||||||
EffectMap::iterator iter = treeEffectMap.find(forest->texture);
|
EffectMap::iterator iter = treeEffectMap.find(forest->texture);
|
||||||
if (iter == treeEffectMap.end()) {
|
|
||||||
|
if (iter != treeEffectMap.end())
|
||||||
|
effect = iter->second.get();
|
||||||
|
|
||||||
|
if (!effect.valid())
|
||||||
|
{
|
||||||
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
||||||
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
|
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
|
||||||
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
||||||
@@ -309,11 +314,12 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
|
|||||||
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
||||||
->setStringValue(forest->texture);
|
->setStringValue(forest->texture);
|
||||||
effect = makeEffect(effectProp, true, options);
|
effect = makeEffect(effectProp, true, options);
|
||||||
treeEffectMap.insert(EffectMap::value_type(forest->texture, effect));
|
if (iter == treeEffectMap.end())
|
||||||
} else {
|
treeEffectMap.insert(EffectMap::value_type(forest->texture, effect));
|
||||||
effect = iter->second.get();
|
else
|
||||||
|
iter->second = effect; // update existing, but empty observer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, create a quadtree for the forest.
|
// Now, create a quadtree for the forest.
|
||||||
ShaderGeometryQuadtree
|
ShaderGeometryQuadtree
|
||||||
quadtree(GetTreeCoord(), AddTreesLeafObject(),
|
quadtree(GetTreeCoord(), AddTreesLeafObject(),
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ gen_standard_light_sprite(void)
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
typedef boost::tuple<float, osg::Vec3, float, float, bool> PointParams;
|
typedef boost::tuple<float, osg::Vec3, float, float, bool> PointParams;
|
||||||
typedef std::map<PointParams, ref_ptr<Effect> > EffectMap;
|
typedef std::map<PointParams, observer_ptr<Effect> > EffectMap;
|
||||||
|
|
||||||
EffectMap effectMap;
|
EffectMap effectMap;
|
||||||
|
|
||||||
@@ -174,7 +174,8 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
|
|||||||
PointParams pointParams(size, attenuation, minSize, maxSize, directional);
|
PointParams pointParams(size, attenuation, minSize, maxSize, directional);
|
||||||
ScopedLock<Mutex> lock(lightMutex);
|
ScopedLock<Mutex> lock(lightMutex);
|
||||||
EffectMap::iterator eitr = effectMap.find(pointParams);
|
EffectMap::iterator eitr = effectMap.find(pointParams);
|
||||||
if (eitr != effectMap.end())
|
if ((eitr != effectMap.end())&&
|
||||||
|
eitr->second.valid())
|
||||||
return eitr->second.get();
|
return eitr->second.get();
|
||||||
// Basic stuff; no sprite or attenuation support
|
// Basic stuff; no sprite or attenuation support
|
||||||
Pass *basicPass = new Pass;
|
Pass *basicPass = new Pass;
|
||||||
@@ -204,7 +205,7 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
|
|||||||
spritePass->setTextureAttribute(0, attrFact->getStandardTexEnv());
|
spritePass->setTextureAttribute(0, attrFact->getStandardTexEnv());
|
||||||
Pass *combinedPass = clone(spritePass, CopyOp::SHALLOW_COPY);
|
Pass *combinedPass = clone(spritePass, CopyOp::SHALLOW_COPY);
|
||||||
combinedPass->setAttributeAndModes(point);
|
combinedPass->setAttributeAndModes(point);
|
||||||
Effect* effect = new Effect;
|
ref_ptr<Effect> effect = new Effect;
|
||||||
std::vector<std::string> parameterExtensions;
|
std::vector<std::string> parameterExtensions;
|
||||||
|
|
||||||
if (SGSceneFeatures::instance()->getEnablePointSpriteLights())
|
if (SGSceneFeatures::instance()->getEnablePointSpriteLights())
|
||||||
@@ -232,8 +233,11 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
|
|||||||
Technique* basicTniq = new Technique(true);
|
Technique* basicTniq = new Technique(true);
|
||||||
basicTniq->passes.push_back(basicPass);
|
basicTniq->passes.push_back(basicPass);
|
||||||
effect->techniques.push_back(basicTniq);
|
effect->techniques.push_back(basicTniq);
|
||||||
effectMap.insert(std::make_pair(pointParams, effect));
|
if (eitr == effectMap.end())
|
||||||
return effect;
|
effectMap.insert(std::make_pair(pointParams, effect));
|
||||||
|
else
|
||||||
|
eitr->second = effect; // update existing, but empty observer
|
||||||
|
return effect.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user