Introduce UnrefQueue to handle the deleting of no longer needed objects in the background thread

coverity_scan
scrawl 9 years ago
parent f6f9eff9a6
commit d11c2864df

@ -14,6 +14,7 @@
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
@ -85,9 +86,10 @@ namespace
namespace MWRender
{
Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode)
Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode, SceneUtil::UnrefQueue* unrefQueue)
: mRootNode(rootNode)
, mResourceSystem(resourceSystem)
, mUnrefQueue(unrefQueue)
{
}
@ -186,7 +188,11 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr)
delete iter->second;
mObjects.erase(iter);
if (mUnrefQueue.get())
mUnrefQueue->push(ptr.getRefData().getBaseNode());
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
ptr.getRefData().setBaseNode(NULL);
return true;
}
@ -200,6 +206,8 @@ void Objects::removeCell(const MWWorld::CellStore* store)
{
if(iter->first.getCell() == store)
{
if (mUnrefQueue.get())
mUnrefQueue->push(iter->second->getObjectRoot());
delete iter->second;
mObjects.erase(iter++);
}
@ -211,6 +219,8 @@ void Objects::removeCell(const MWWorld::CellStore* store)
if(cell != mCellSceneNodes.end())
{
cell->second->getParent(0)->removeChild(cell->second);
if (mUnrefQueue.get())
mUnrefQueue->push(cell->second);
mCellSceneNodes.erase(cell);
}
}

@ -30,6 +30,11 @@ namespace MWWorld
class CellStore;
}
namespace SceneUtil
{
class UnrefQueue;
}
namespace MWRender{
class Animation;
@ -65,12 +70,14 @@ class Objects{
osg::ref_ptr<osg::Group> mRootNode;
void insertBegin(const MWWorld::Ptr& ptr);
Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
void insertBegin(const MWWorld::Ptr& ptr);
public:
Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode);
Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode, SceneUtil::UnrefQueue* unrefQueue);
~Objects();
/// @param animated Attempt to load separate keyframes from a .kf file matching the model file?

@ -27,6 +27,7 @@
#include <components/sceneutil/statesetupdater.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include <components/terrain/terraingrid.hpp>
@ -156,6 +157,7 @@ namespace MWRender
, mRootNode(rootNode)
, mResourceSystem(resourceSystem)
, mWorkQueue(new SceneUtil::WorkQueue)
, mUnrefQueue(new SceneUtil::UnrefQueue)
, mFogDepth(0.f)
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
@ -176,7 +178,7 @@ namespace MWRender
mPathgrid.reset(new Pathgrid(mRootNode));
mObjects.reset(new Objects(mResourceSystem, lightRoot));
mObjects.reset(new Objects(mResourceSystem, lightRoot, mUnrefQueue.get()));
mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation);
@ -187,7 +189,7 @@ namespace MWRender
mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(),
new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain));
new TerrainStorage(mResourceSystem->getVFS(), false), Mask_Terrain, mUnrefQueue.get()));
mCamera.reset(new Camera(mViewer->getCamera()));
@ -437,6 +439,8 @@ namespace MWRender
void RenderingManager::update(float dt, bool paused)
{
mUnrefQueue->flush(mWorkQueue.get());
if (!paused)
{
mEffectManager->update(dt);

@ -45,6 +45,7 @@ namespace Fallback
namespace SceneUtil
{
class WorkQueue;
class UnrefQueue;
}
namespace MWRender
@ -200,6 +201,7 @@ namespace MWRender
Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
osg::ref_ptr<osg::Light> mSunLight;

@ -46,7 +46,7 @@ add_component_dir (resource
add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue
lightmanager lightutil positionattitudetransform workqueue unrefqueue
)
add_component_dir (nif

@ -0,0 +1,46 @@
#include "unrefqueue.hpp"
#include <osg/Object>
//#include <osg/Timer>
//#include <iostream>
#include <components/sceneutil/workqueue.hpp>
namespace SceneUtil
{
class UnrefWorkItem : public SceneUtil::WorkItem
{
public:
std::vector<osg::ref_ptr<osg::Object> > mObjects;
virtual void doWork()
{
//osg::Timer timer;
//size_t objcount = mObjects.size();
mObjects.clear();
//std::cout << "cleared " << objcount << " objects in " << timer.time_m() << std::endl;
}
};
UnrefQueue::UnrefQueue()
{
mWorkItem = new UnrefWorkItem;
}
void UnrefQueue::push(osg::Object *obj)
{
mWorkItem->mObjects.push_back(obj);
}
void UnrefQueue::flush(SceneUtil::WorkQueue *workQueue)
{
if (mWorkItem->mObjects.empty())
return;
workQueue->addWorkItem(mWorkItem);
mWorkItem = new UnrefWorkItem;
}
}

@ -0,0 +1,37 @@
#ifndef OPENMW_COMPONENTS_UNREFQUEUE_H
#define OPENMW_COMPONENTS_UNREFQUEUE_H
#include <osg/ref_ptr>
#include <osg/Referenced>
namespace osg
{
class Object;
}
namespace SceneUtil
{
class WorkQueue;
class UnrefWorkItem;
/// @brief Handles unreferencing of objects through the WorkQueue. Typical use scenario
/// would be the main thread pushing objects that are no longer needed, and the background thread deleting them.
class UnrefQueue : public osg::Referenced
{
public:
UnrefQueue();
/// Adds an object to the list of objects to be unreferenced. Call from the main thread.
void push(osg::Object* obj);
/// Adds a WorkItem to the given WorkQueue that will clear the list of objects in a worker thread, thus unreferencing them.
/// Call from the main thread.
void flush(SceneUtil::WorkQueue* workQueue);
private:
osg::ref_ptr<UnrefWorkItem> mWorkItem;
};
}
#endif

@ -8,6 +8,7 @@
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include <components/esm/loadland.hpp>
@ -46,11 +47,10 @@ namespace
namespace Terrain
{
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
Storage* storage, int nodeMask)
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue)
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
, mNumSplits(4)
, mKdTreeBuilder(new osg::KdTreeBuilder)
, mUnrefQueue(unrefQueue)
{
mCache = BufferCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1);
}
@ -212,13 +212,6 @@ void TerrainGrid::loadCell(int x, int y)
element->mNode = terrainNode;
mTerrainRoot->addChild(element->mNode);
// kdtree probably not needed with mNumSplits=4
/*
// build a kdtree to speed up intersection tests with the terrain
// Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree
geode->accept(*mKdTreeBuilder);
*/
mGrid[std::make_pair(x,y)] = element.release();
}
@ -230,6 +223,10 @@ void TerrainGrid::unloadCell(int x, int y)
GridElement* element = it->second;
mTerrainRoot->removeChild(element->mNode);
if (mUnrefQueue.get())
mUnrefQueue->push(element->mNode);
delete element;
mGrid.erase(it);
@ -240,7 +237,11 @@ void TerrainGrid::clearCache()
for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();)
{
if (it->second->referenceCount() <= 1)
{
if (mUnrefQueue.get())
mUnrefQueue->push(it->second);
mTextureCache.erase(it++);
}
else
++it;
}

@ -6,9 +6,9 @@
#include "world.hpp"
#include "material.hpp"
namespace osg
namespace SceneUtil
{
class KdTreeBuilder;
class UnrefQueue;
}
namespace Terrain
@ -20,8 +20,7 @@ namespace Terrain
class TerrainGrid : public Terrain::World
{
public:
TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
Storage* storage, int nodeMask);
TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue = NULL);
~TerrainGrid();
virtual void loadCell(int x, int y);
@ -42,7 +41,7 @@ namespace Terrain
typedef std::map<std::pair<int, int>, GridElement*> Grid;
Grid mGrid;
osg::ref_ptr<osg::KdTreeBuilder> mKdTreeBuilder;
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
};
}

Loading…
Cancel
Save