forked from mirror/openmw-tes3mp
Introduce UnrefQueue to handle the deleting of no longer needed objects in the background thread
This commit is contained in:
parent
f6f9eff9a6
commit
d11c2864df
9 changed files with 128 additions and 22 deletions
|
@ -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
|
||||
|
|
46
components/sceneutil/unrefqueue.cpp
Normal file
46
components/sceneutil/unrefqueue.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
37
components/sceneutil/unrefqueue.hpp
Normal file
37
components/sceneutil/unrefqueue.hpp
Normal file
|
@ -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…
Reference in a new issue