Preload terrain

coverity_scan
scrawl 9 years ago
parent 98848c752a
commit 0865cea211

@ -258,16 +258,21 @@ namespace MWRender
return mResourceSystem;
}
SceneUtil::WorkQueue *RenderingManager::getWorkQueue()
SceneUtil::WorkQueue* RenderingManager::getWorkQueue()
{
return mWorkQueue.get();
}
SceneUtil::UnrefQueue *RenderingManager::getUnrefQueue()
SceneUtil::UnrefQueue* RenderingManager::getUnrefQueue()
{
return mUnrefQueue.get();
}
Terrain::World* RenderingManager::getTerrain()
{
return mTerrain.get();
}
void RenderingManager::preloadCommonAssets()
{
osg::ref_ptr<PreloadCommonAssetsWorkItem> workItem (new PreloadCommonAssetsWorkItem(mResourceSystem));
@ -279,12 +284,6 @@ namespace MWRender
mWorkQueue->addWorkItem(workItem);
}
void RenderingManager::clearCache()
{
if (mTerrain.get())
mTerrain->clearCache();
}
double RenderingManager::getReferenceTime() const
{
return mViewer->getFrameStamp()->getReferenceTime();
@ -838,7 +837,7 @@ namespace MWRender
void RenderingManager::updateTextureFiltering()
{
if (mTerrain.get())
mTerrain->clearCache();
mTerrain->updateCache();
mResourceSystem->getSceneManager()->setFilterSettings(
Settings::Manager::getString("texture mag filter", "General"),

@ -73,11 +73,10 @@ namespace MWRender
SceneUtil::WorkQueue* getWorkQueue();
SceneUtil::UnrefQueue* getUnrefQueue();
Terrain::World* getTerrain();
void preloadCommonAssets();
void clearCache();
double getReferenceTime() const;
osg::Group* getLightRoot();

@ -8,6 +8,7 @@
#include <components/resource/keyframemanager.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/nifosg/nifloader.hpp>
#include <components/terrain/world.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -44,10 +45,14 @@ namespace MWWorld
{
public:
/// Constructor to be called from the main thread.
PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager)
: mSceneManager(sceneManager)
PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager, Terrain::World* terrain)
: mIsExterior(cell->getCell()->isExterior())
, mX(cell->getCell()->getGridX())
, mY(cell->getCell()->getGridY())
, mSceneManager(sceneManager)
, mBulletShapeManager(bulletShapeManager)
, mKeyframeManager(keyframeManager)
, mTerrain(terrain)
{
osg::Timer timer;
ListModelsVisitor visitor (mMeshes);
@ -86,8 +91,8 @@ namespace MWWorld
//std::cout << "preloading " << mesh << std::endl;
mPreloadedNodes.push_back(mSceneManager->cacheInstance(mesh));
mPreloadedShapes.push_back(mBulletShapeManager->cacheInstance(mesh));
mPreloadedObjects.push_back(mSceneManager->cacheInstance(mesh));
mPreloadedObjects.push_back(mBulletShapeManager->cacheInstance(mesh));
size_t slashpos = mesh.find_last_of("/\\");
if (slashpos != std::string::npos && slashpos != mesh.size()-1)
@ -99,7 +104,7 @@ namespace MWWorld
if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0)
{
kfname.replace(kfname.size()-4, 4, ".kf");
mPreloadedKeyframes.push_back(mKeyframeManager->get(kfname));
mPreloadedObjects.push_back(mKeyframeManager->get(kfname));
}
}
@ -111,29 +116,44 @@ namespace MWWorld
// error will be shown when visiting the cell
}
}
std::cout << "preloaded " << mPreloadedNodes.size() << " nodes in " << preloadTimer.time_m() << std::endl;
if (mIsExterior)
{
try
{
mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY));
}
catch(std::exception& e)
{
}
}
std::cout << "preloaded " << mPreloadedObjects.size() << " objects in " << preloadTimer.time_m() << std::endl;
}
private:
typedef std::vector<std::string> MeshList;
bool mIsExterior;
int mX;
int mY;
MeshList mMeshes;
Resource::SceneManager* mSceneManager;
Resource::BulletShapeManager* mBulletShapeManager;
Resource::KeyframeManager* mKeyframeManager;
Terrain::World* mTerrain;
// keep a ref to the loaded object to make sure it stays loaded as long as this cell is in the preloaded state
std::vector<osg::ref_ptr<const osg::Node> > mPreloadedNodes;
std::vector<osg::ref_ptr<const Resource::BulletShapeInstance> > mPreloadedShapes;
std::vector<osg::ref_ptr<const NifOsg::KeyframeHolder> > mPreloadedKeyframes;
// keep a ref to the loaded objects to make sure it stays loaded as long as this cell is in the preloaded state
std::vector<osg::ref_ptr<const osg::Object> > mPreloadedObjects;
};
/// Worker thread item: update the resource system's cache, effectively deleting unused entries.
class UpdateCacheItem : public SceneUtil::WorkItem
{
public:
UpdateCacheItem(Resource::ResourceSystem* resourceSystem, double referenceTime)
UpdateCacheItem(Resource::ResourceSystem* resourceSystem, Terrain::World* terrain, double referenceTime)
: mReferenceTime(referenceTime)
, mResourceSystem(resourceSystem)
, mTerrain(terrain)
{
}
@ -141,17 +161,21 @@ namespace MWWorld
{
osg::Timer timer;
mResourceSystem->updateCache(mReferenceTime);
mTerrain->updateCache();
std::cout << "cleared cache in " << timer.time_m() << std::endl;
}
private:
double mReferenceTime;
Resource::ResourceSystem* mResourceSystem;
Terrain::World* mTerrain;
};
CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager)
CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain)
: mResourceSystem(resourceSystem)
, mBulletShapeManager(bulletShapeManager)
, mTerrain(terrain)
, mExpiryDelay(0.0)
{
}
@ -177,7 +201,7 @@ namespace MWWorld
return;
}
osg::ref_ptr<PreloadItem> item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager()));
osg::ref_ptr<PreloadItem> item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager(), mTerrain));
mWorkQueue->addWorkItem(item);
mPreloadCells[cell] = PreloadEntry(timestamp, item);
@ -201,7 +225,7 @@ namespace MWWorld
}
// the resource cache is cleared from the worker thread so that we're not holding up the main thread with delete operations
mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, timestamp));
mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, mTerrain, timestamp));
}
void CellPreloader::setExpiryDelay(double expiryDelay)

@ -11,6 +11,11 @@ namespace Resource
class BulletShapeManager;
}
namespace Terrain
{
class World;
}
namespace MWWorld
{
class CellStore;
@ -18,7 +23,7 @@ namespace MWWorld
class CellPreloader
{
public:
CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager);
CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain);
/// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell.
/// @note The cell itself must be in State_Loaded or State_Preloaded.
@ -37,6 +42,7 @@ namespace MWWorld
private:
Resource::ResourceSystem* mResourceSystem;
Resource::BulletShapeManager* mBulletShapeManager;
Terrain::World* mTerrain;
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
double mExpiryDelay;

@ -416,7 +416,6 @@ namespace MWWorld
mCellChanged = true;
mPreloader->updateCache(mRendering.getReferenceTime());
mRendering.clearCache();
std::cout << "changeCellGrid took " << timer.time_m() << std::endl;
}
@ -463,7 +462,7 @@ namespace MWWorld
, mPreloadDoors(Settings::Manager::getBool("preload doors", "Cells"))
, mPreloadFastTravel(Settings::Manager::getBool("preload fast travel", "Cells"))
{
mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager()));
mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager(), rendering.getTerrain()));
mPreloader->setWorkQueue(mRendering.getWorkQueue());
mPhysics->setUnrefQueue(rendering.getUnrefQueue());
@ -549,7 +548,6 @@ namespace MWWorld
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
mPreloader->updateCache(mRendering.getReferenceTime());
mRendering.clearCache();
std::cout << "change to interior took " << timer.time_m() << std::endl;
}

@ -19,11 +19,6 @@ namespace Resource
mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay);
}
void ResourceManager::clearCache()
{
mCache->clear();
}
void ResourceManager::setExpiryDelay(double expiryDelay)
{
mExpiryDelay = expiryDelay;

@ -22,9 +22,6 @@ namespace Resource
/// Clear cache entries that have not been referenced for longer than expiryDelay.
virtual void updateCache(double referenceTime);
/// Clear all cache entries regardless of having external references.
virtual void clearCache();
/// How long to keep objects in cache after no longer being referenced.
void setExpiryDelay (double expiryDelay);

@ -2,6 +2,8 @@
#include <cassert>
#include <OpenThreads/ScopedLock>
#include <osg/PrimitiveSet>
#include "defs.hpp"
@ -178,6 +180,7 @@ namespace Terrain
osg::ref_ptr<osg::Vec2Array> BufferCache::getUVBuffer()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex);
if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end())
{
return mUvBufferMap[mNumVerts];
@ -206,6 +209,7 @@ namespace Terrain
osg::ref_ptr<osg::DrawElements> BufferCache::getIndexBuffer(unsigned int flags)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex);
unsigned int verts = mNumVerts;
if (mIndexBufferMap.find(flags) != mIndexBufferMap.end())

@ -17,8 +17,10 @@ namespace Terrain
/// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each)
/// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices)
/// @note Thread safe.
osg::ref_ptr<osg::DrawElements> getIndexBuffer (unsigned int flags);
/// @note Thread safe.
osg::ref_ptr<osg::Vec2Array> getUVBuffer();
// TODO: add releaseGLObjects() for our vertex/element buffer objects
@ -27,8 +29,10 @@ namespace Terrain
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
// combination of LOD deltas and index buffer LOD we may need.
std::map<int, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
OpenThreads::Mutex mIndexBufferMutex;
std::map<int, osg::ref_ptr<osg::Vec2Array> > mUvBufferMap;
OpenThreads::Mutex mUvBufferMutex;
unsigned int mNumVerts;
};

@ -2,6 +2,8 @@
#include <memory>
#include <OpenThreads/ScopedLock>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
@ -50,9 +52,9 @@ namespace Terrain
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)
, mCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1)
, mUnrefQueue(unrefQueue)
{
mCache = BufferCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1);
}
TerrainGrid::~TerrainGrid()
@ -63,6 +65,21 @@ TerrainGrid::~TerrainGrid()
}
}
osg::ref_ptr<osg::Node> TerrainGrid::cacheCell(int x, int y)
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mGridCacheMutex);
Grid::iterator found = mGridCache.find(std::make_pair(x,y));
if (found != mGridCache.end())
return found->second;
}
osg::ref_ptr<osg::Node> node = buildTerrain(NULL, 1.f, osg::Vec2f(x+0.5, y+0.5));
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mGridCacheMutex);
mGridCache.insert(std::make_pair(std::make_pair(x,y), node));
return node;
}
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
{
if (chunkSize * mNumSplits > 1.f)
@ -131,19 +148,22 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
unsigned int dummyTextureCounter = 0;
std::vector<osg::ref_ptr<osg::Texture2D> > layerTextures;
for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
{
osg::ref_ptr<osg::Texture2D> texture = mTextureCache[it->mDiffuseMap];
if (!texture)
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mTextureCacheMutex);
for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
{
texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap));
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
mResourceSystem->getSceneManager()->applyFilterSettings(texture);
mTextureCache[it->mDiffuseMap] = texture;
osg::ref_ptr<osg::Texture2D> texture = mTextureCache[it->mDiffuseMap];
if (!texture)
{
texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap));
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
mResourceSystem->getSceneManager()->applyFilterSettings(texture);
mTextureCache[it->mDiffuseMap] = texture;
}
layerTextures.push_back(texture);
textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back());
}
layerTextures.push_back(texture);
textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, layerTextures.back());
}
std::vector<osg::ref_ptr<osg::Texture2D> > blendmapTextures;
@ -196,11 +216,27 @@ void TerrainGrid::loadCell(int x, int y)
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
return; // already loaded
osg::Vec2f center(x+0.5f, y+0.5f);
// try to get it from the cache
osg::ref_ptr<osg::Node> terrainNode;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mGridCacheMutex);
Grid::const_iterator found = mGridCache.find(std::make_pair(x,y));
if (found != mGridCache.end())
{
terrainNode = found->second;
if (!terrainNode)
return; // no terrain defined
}
}
osg::ref_ptr<osg::Node> terrainNode = buildTerrain(NULL, 1.f, center);
// didn't find in cache, build it
if (!terrainNode)
return; // no terrain defined
{
osg::Vec2f center(x+0.5f, y+0.5f);
terrainNode = buildTerrain(NULL, 1.f, center);
if (!terrainNode)
return; // no terrain defined
}
mTerrainRoot->addChild(terrainNode);
@ -213,7 +249,7 @@ void TerrainGrid::unloadCell(int x, int y)
if (it == mGrid.end())
return;
osg::Node* terrainNode = it->second;
osg::ref_ptr<osg::Node> terrainNode = it->second;
mTerrainRoot->removeChild(terrainNode);
if (mUnrefQueue.get())
@ -222,18 +258,28 @@ void TerrainGrid::unloadCell(int x, int y)
mGrid.erase(it);
}
void TerrainGrid::clearCache()
void TerrainGrid::updateCache()
{
for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();)
{
if (it->second->referenceCount() <= 1)
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mTextureCacheMutex);
for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();)
{
if (it->second->referenceCount() <= 1)
mTextureCache.erase(it++);
else
++it;
}
}
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mGridCacheMutex);
for (Grid::iterator it = mGridCache.begin(); it != mGridCache.end();)
{
if (mUnrefQueue.get())
mUnrefQueue->push(it->second);
mTextureCache.erase(it++);
if (it->second->referenceCount() <= 1)
mGridCache.erase(it++);
else
++it;
}
else
++it;
}
}

@ -21,11 +21,20 @@ namespace Terrain
TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask, SceneUtil::UnrefQueue* unrefQueue = NULL);
~TerrainGrid();
/// Load a terrain cell and store it in cache for later use.
/// @note The returned ref_ptr should be kept by the caller to ensure that the terrain stays in cache for as long as needed.
/// @note Thread safe.
virtual osg::ref_ptr<osg::Node> cacheCell(int x, int y);
/// @note Not thread safe.
virtual void loadCell(int x, int y);
/// @note Not thread safe.
virtual void unloadCell(int x, int y);
/// Clear cached textures that are no longer referenced
void clearCache();
/// Clear cached objects that are no longer referenced
/// @note Thread safe.
void updateCache();
private:
osg::ref_ptr<osg::Node> buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter);
@ -35,10 +44,16 @@ namespace Terrain
typedef std::map<std::string, osg::ref_ptr<osg::Texture2D> > TextureCache;
TextureCache mTextureCache;
OpenThreads::Mutex mTextureCacheMutex;
typedef std::map<std::pair<int, int>, osg::ref_ptr<osg::Node> > Grid;
Grid mGrid;
Grid mGridCache;
OpenThreads::Mutex mGridCacheMutex;
BufferCache mCache;
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
};

@ -11,7 +11,6 @@ namespace Terrain
World::World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
Storage* storage, int nodeMask)
: mStorage(storage)
, mCache(storage->getCellVertices())
, mParent(parent)
, mResourceSystem(resourceSystem)
, mIncrementalCompileOperation(ico)

@ -39,10 +39,12 @@ namespace Terrain
Storage* storage, int nodeMask);
virtual ~World();
virtual void clearCache() {}
virtual void updateCache() {}
float getHeightAt (const osg::Vec3f& worldPos);
virtual osg::ref_ptr<osg::Node> cacheCell(int x, int y) {return NULL;}
// This is only a hint and may be ignored by the implementation.
virtual void loadCell(int x, int y) {}
virtual void unloadCell(int x, int y) {}
@ -52,8 +54,6 @@ namespace Terrain
protected:
Storage* mStorage;
BufferCache mCache;
osg::ref_ptr<osg::Group> mParent;
osg::ref_ptr<osg::Group> mTerrainRoot;

Loading…
Cancel
Save