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/visitor.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/sceneutil/unrefqueue.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -85,9 +86,10 @@ namespace
|
||||||
namespace MWRender
|
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)
|
: mRootNode(rootNode)
|
||||||
, mResourceSystem(resourceSystem)
|
, mResourceSystem(resourceSystem)
|
||||||
|
, mUnrefQueue(unrefQueue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +188,11 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr)
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
mObjects.erase(iter);
|
mObjects.erase(iter);
|
||||||
|
|
||||||
|
if (mUnrefQueue.get())
|
||||||
|
mUnrefQueue->push(ptr.getRefData().getBaseNode());
|
||||||
|
|
||||||
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
|
ptr.getRefData().getBaseNode()->getParent(0)->removeChild(ptr.getRefData().getBaseNode());
|
||||||
|
|
||||||
ptr.getRefData().setBaseNode(NULL);
|
ptr.getRefData().setBaseNode(NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +206,8 @@ void Objects::removeCell(const MWWorld::CellStore* store)
|
||||||
{
|
{
|
||||||
if(iter->first.getCell() == store)
|
if(iter->first.getCell() == store)
|
||||||
{
|
{
|
||||||
|
if (mUnrefQueue.get())
|
||||||
|
mUnrefQueue->push(iter->second->getObjectRoot());
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
mObjects.erase(iter++);
|
mObjects.erase(iter++);
|
||||||
}
|
}
|
||||||
|
@ -211,6 +219,8 @@ void Objects::removeCell(const MWWorld::CellStore* store)
|
||||||
if(cell != mCellSceneNodes.end())
|
if(cell != mCellSceneNodes.end())
|
||||||
{
|
{
|
||||||
cell->second->getParent(0)->removeChild(cell->second);
|
cell->second->getParent(0)->removeChild(cell->second);
|
||||||
|
if (mUnrefQueue.get())
|
||||||
|
mUnrefQueue->push(cell->second);
|
||||||
mCellSceneNodes.erase(cell);
|
mCellSceneNodes.erase(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ namespace MWWorld
|
||||||
class CellStore;
|
class CellStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace SceneUtil
|
||||||
|
{
|
||||||
|
class UnrefQueue;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender{
|
namespace MWRender{
|
||||||
|
|
||||||
class Animation;
|
class Animation;
|
||||||
|
@ -65,12 +70,14 @@ class Objects{
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> mRootNode;
|
osg::ref_ptr<osg::Group> mRootNode;
|
||||||
|
|
||||||
void insertBegin(const MWWorld::Ptr& ptr);
|
|
||||||
|
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
|
|
||||||
|
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||||
|
|
||||||
|
void insertBegin(const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
public:
|
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();
|
~Objects();
|
||||||
|
|
||||||
/// @param animated Attempt to load separate keyframes from a .kf file matching the model file?
|
/// @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/statesetupdater.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
#include <components/sceneutil/workqueue.hpp>
|
#include <components/sceneutil/workqueue.hpp>
|
||||||
|
#include <components/sceneutil/unrefqueue.hpp>
|
||||||
|
|
||||||
#include <components/terrain/terraingrid.hpp>
|
#include <components/terrain/terraingrid.hpp>
|
||||||
|
|
||||||
|
@ -156,6 +157,7 @@ namespace MWRender
|
||||||
, mRootNode(rootNode)
|
, mRootNode(rootNode)
|
||||||
, mResourceSystem(resourceSystem)
|
, mResourceSystem(resourceSystem)
|
||||||
, mWorkQueue(new SceneUtil::WorkQueue)
|
, mWorkQueue(new SceneUtil::WorkQueue)
|
||||||
|
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
||||||
, mFogDepth(0.f)
|
, mFogDepth(0.f)
|
||||||
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
|
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
|
||||||
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
|
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
|
||||||
|
@ -176,7 +178,7 @@ namespace MWRender
|
||||||
|
|
||||||
mPathgrid.reset(new Pathgrid(mRootNode));
|
mPathgrid.reset(new Pathgrid(mRootNode));
|
||||||
|
|
||||||
mObjects.reset(new Objects(mResourceSystem, lightRoot));
|
mObjects.reset(new Objects(mResourceSystem, lightRoot, mUnrefQueue.get()));
|
||||||
|
|
||||||
mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation);
|
mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation);
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ namespace MWRender
|
||||||
mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
|
mWater.reset(new Water(mRootNode, lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
|
||||||
|
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(lightRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(),
|
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()));
|
mCamera.reset(new Camera(mViewer->getCamera()));
|
||||||
|
|
||||||
|
@ -437,6 +439,8 @@ namespace MWRender
|
||||||
|
|
||||||
void RenderingManager::update(float dt, bool paused)
|
void RenderingManager::update(float dt, bool paused)
|
||||||
{
|
{
|
||||||
|
mUnrefQueue->flush(mWorkQueue.get());
|
||||||
|
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
mEffectManager->update(dt);
|
mEffectManager->update(dt);
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace Fallback
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
class WorkQueue;
|
class WorkQueue;
|
||||||
|
class UnrefQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -200,6 +201,7 @@ namespace MWRender
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
||||||
|
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Light> mSunLight;
|
osg::ref_ptr<osg::Light> mSunLight;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ add_component_dir (resource
|
||||||
|
|
||||||
add_component_dir (sceneutil
|
add_component_dir (sceneutil
|
||||||
clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller
|
clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller
|
||||||
lightmanager lightutil positionattitudetransform workqueue
|
lightmanager lightutil positionattitudetransform workqueue unrefqueue
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nif
|
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/lightmanager.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/sceneutil/unrefqueue.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadland.hpp>
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
|
@ -46,11 +47,10 @@ namespace
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
|
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue)
|
||||||
Storage* storage, int nodeMask)
|
|
||||||
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
|
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
|
||||||
, mNumSplits(4)
|
, mNumSplits(4)
|
||||||
, mKdTreeBuilder(new osg::KdTreeBuilder)
|
, mUnrefQueue(unrefQueue)
|
||||||
{
|
{
|
||||||
mCache = BufferCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1);
|
mCache = BufferCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1);
|
||||||
}
|
}
|
||||||
|
@ -212,13 +212,6 @@ void TerrainGrid::loadCell(int x, int y)
|
||||||
element->mNode = terrainNode;
|
element->mNode = terrainNode;
|
||||||
mTerrainRoot->addChild(element->mNode);
|
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();
|
mGrid[std::make_pair(x,y)] = element.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +223,10 @@ void TerrainGrid::unloadCell(int x, int y)
|
||||||
|
|
||||||
GridElement* element = it->second;
|
GridElement* element = it->second;
|
||||||
mTerrainRoot->removeChild(element->mNode);
|
mTerrainRoot->removeChild(element->mNode);
|
||||||
|
|
||||||
|
if (mUnrefQueue.get())
|
||||||
|
mUnrefQueue->push(element->mNode);
|
||||||
|
|
||||||
delete element;
|
delete element;
|
||||||
|
|
||||||
mGrid.erase(it);
|
mGrid.erase(it);
|
||||||
|
@ -240,7 +237,11 @@ void TerrainGrid::clearCache()
|
||||||
for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();)
|
for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();)
|
||||||
{
|
{
|
||||||
if (it->second->referenceCount() <= 1)
|
if (it->second->referenceCount() <= 1)
|
||||||
|
{
|
||||||
|
if (mUnrefQueue.get())
|
||||||
|
mUnrefQueue->push(it->second);
|
||||||
mTextureCache.erase(it++);
|
mTextureCache.erase(it++);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
#include "material.hpp"
|
#include "material.hpp"
|
||||||
|
|
||||||
namespace osg
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
class KdTreeBuilder;
|
class UnrefQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
|
@ -20,8 +20,7 @@ namespace Terrain
|
||||||
class TerrainGrid : public Terrain::World
|
class TerrainGrid : public Terrain::World
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
|
TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue = NULL);
|
||||||
Storage* storage, int nodeMask);
|
|
||||||
~TerrainGrid();
|
~TerrainGrid();
|
||||||
|
|
||||||
virtual void loadCell(int x, int y);
|
virtual void loadCell(int x, int y);
|
||||||
|
@ -42,7 +41,7 @@ namespace Terrain
|
||||||
typedef std::map<std::pair<int, int>, GridElement*> Grid;
|
typedef std::map<std::pair<int, int>, GridElement*> Grid;
|
||||||
Grid mGrid;
|
Grid mGrid;
|
||||||
|
|
||||||
osg::ref_ptr<osg::KdTreeBuilder> mKdTreeBuilder;
|
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue